Repository: conan-io/conan

Issue:
[bug] Intel compilers: CMake does not find compiler after conan install
### Describe the bug

Dear Conan support, I am encountering the following issue:

### Environment
- ubuntu22.04 running on WSL2 (Windows 11).
- Conan  version: 2.19.1
- intel oneapi 2024.0 (base kit which includes compilers)

### Problem description
When I call 
```bash
conan install . -pr=<my-profile-using-intel-oneapi>
```
I'm getting the following error output:
```
[proc] Executing command: /usr/bin/cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake -S /build/src/test -B /build/src/test/build/RelWithDebInfo -G "Unix Makefiles"
[cmake] -- Using Conan toolchain: /build/src/test/build/RelWithDebInfo/generators/conan_toolchain.cmake
[cmake] -- Conan toolchain: Defining architecture flag: -m64
[cmake] -- Conan toolchain: Defining libcxx as C++ flags: -stdlib=libstdc++
[cmake] -- Conan toolchain: C++ Standard 20 with extensions ON
[cmake] CMake Error at /usr/share/cmake-3.28/Modules/CMakeDetermineCCompiler.cmake:49 (message):
[cmake]   Could not find compiler set in environment variable CC:
[cmake] 
[cmake]   icx.
[cmake] Call Stack (most recent call first):
[cmake]   CMakeLists.txt:3 (project)
[cmake] 
[cmake] 
[cmake] CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
[cmake] CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
```

When instead I run
```bash
conan build . -pr=<my-profile-using-intel-oneapi>
```
Then I'm able to subsequently use CMake directly with the conan-generated presets.

I guess the variables provided by `setvars.sh` script by Intel (especially the `PATH`) are not made persistent by Conan in the presets, hence the failure of CMake to actually find the compiler.

Thanks for your help!
- Milan

### How to reproduce it

Try to build a project using intel oneapi, by:
- using `conan install` to get the dependencies and CMake presets up
- then invoking cmake with the Conan-generated preset


Discussion:
Hi @mpll-d thanks a lot for taking the time to report this.

While there could be a few different things that might be happening here, for which we would need to see the profile and how you're setting the icx information, the first thing that comes to mind is that you might be missing sourcing the `conanbuild.sh` before running cmake, as shown in [this tutorial section](https://docs.conan.io/2/tutorial/consuming_packages/use_tools_as_conan_packages.html)

Note that some of the information is passed to the preset files so that it's not always necessary to run it,. but as a first check it's worth trying :)
Hi @AbrilRBS , this indeed looks like what you mention. I'm actually using CMake through the VS Code extension, and thought the conan-generated cmake preset would be the one responsible for setting up the environment to build the Conan package.

That brings 2 questions 😉 
- that's one step more to do as compared to when building with gcc. All else being equal, it feels a bit unexpected that this additional step is necessary when working with intel compilers. So shouldn't Conan set the proper environment info into the preset?
- do you, by any chance, know what the workflow/setup should be, for me to be able to use `conan install` and then be able to use the CMake VS Code extension? It would be a pity that we have to change our workflow due to using a different compiler

Many thanks for the swift and very accurate reply
Hi @mpll-d 

To add some further details.

The VS code IDE per se doesn't have any mechanism to locate and "activate" some specific compiler, that means that in most cases, those compilers have to be already defined and "activated" in order to find them.

For GNU-like compilers like gcc, the normal approach is to have them just in the system PATH so cmake will easily find and use them. The scenario with other compilers such as MSVC compiler is more complicated, it requires the activation of the compiler via the ``vcvars.bat`` scripts distributed as part of the installation of the compiler.

What the ``CMake tools`` VS code extension is capable of doing in some cases, is to automatically find and activate that ``vcvars.bat`` script, if it finds the ``cl.exe`` compiler defined as ``CMAKE_C/CXX_COMPILER`` cmake variable in the CMake presets file. Conan generated presets file include this definition for the Ninja generator.

But I'd say that the ``CMake tools`` don't have the same functionality for the intel compiler (it also has its own ``setvars`` script).

Conan already generates the necessary environment scripts, call it from ``conanbuild.bat`` in order to activate the Intel environment.
But that is the best that Conan can do, I am afraid that there is nothing else that can be done from the Conan side, as the rest depend on the VS Code ``CMake tools`` integration.

I think the issue is not specific to Conan. If not using Conan at all, I think it is not possible to have a CMake preset file and use the intel-cc compiler transparently without activating first manually the Intel ``setvars`` script.

As an extra detail, take into account that it is not possible to change the environment, or (mostly the same) to "activate" permanently a compiler environment via ``vcvars.bat`` or ``setvars.bat`` because while running a subprocess (such when Conan command is executing), a child process cannot change the environment of the caller process. So by OS limitations, it is no possible to call ``conan <anything>`` and then have the environment modified with an "activated" compiler. This is why the flow is more ``conan install`` + ``activation of the environment`` + ``build``. The ``activation of the environment`` is something that another tool such as the IDE or the cmake tools in VSCode can do before doing the ``build``, so the build happens in that environment.

The alternatives could be:
- Check if ``CMake tools`` automatically find and loads the Intel environment via ``setvars`` if the ``CMAKE_C/CXX_COMPILER`` is set to ``IntelCC`` (i think this is not happening). If it is not happening, maybe do it as a feature request to ``CMake tools``
- Recall to call ``conanbuild.bat`` to activate the environment after ``conan install``

Please let me know if this clarifies the issue.
Hi @memsharded, 
Thanks for your detailed answer. I understand that MSVC / Intel oneAPI both rely on some `setvars` script, and that this needs to be called _at some point_.
As I was trying to answer you why the way it interacts with Conan was not satisfying to me, I think I solved my issue.

Here's the thing:
One usual way to work in VSCode, with Conan, is as follow:
- open a repo in VSCode (in my case in a linux dev container where oneAPI is installed)
- `conan install . -pr=<my-inteloneapi-profile>`
- then configure & build with the CMake extension to get the convenient integration (presets selection, test explorer & all)

Currently, this does not work for the reasons you described: I'm missing the sourcing of `setvars.sh`. My first thought is that I could add the line `source /opt/intel/oneapi/setvars.sh` to my `.bashrc` and work fine like that.
Unfortunately, next time I'm trying to run a `conan build` or `conan create` command, it will bail out because Conan will try to source `setvars.sh`, because the profile says I want to use intel oneapi.

Actually, I just noticed that it is possible to also use the environment variable `SETVARS_ARGS="--force"` in order for Conan's call to `setvars.sh` not to fail upon calling `conan build` or `conan create`.

So that fixes my issue, but this behaviour of Conan feels slightly rigid when using oneAPI... Would it be possible to rather provide a Conan option to skip Conan's call `source setvars.sh`? Or maybe provide something like a "lazy initialization": `conan build/create` only executes `setvars.sh` if the `oneapi` env vars are not already in the path.

Thanks and keep up the great work.
I think what you want might be easily achievable.

The current code is something like:
```python
        installation_path = self._conanfile.conf.get("tools.intel:installation_path")
        if not installation_path:
            raise ConanException("To use Intel oneAPI, specify a [conf] entry "
                                 "'tools.intel:installation_path' containing the path to the "
                                 "installation folder.")
```
Which means that code requires to define ``tools.intel:installation_path`` or it will fail.
We could use an empty string there to define "this is already activated, no need to do it" and the ``IntelCC`` generator adding the setvars script could be skipped. This is similar to what the ``VCVars`` generator is already doing, allowing to skip the generation of ``conanvcvars.bat``.
What do you think? This would be easy to implement, can be done for next release.
Trying it in a PR https://github.com/conan-io/conan/pull/18840
I agree with the approach, it does fix my issue. Thanks!
It's indeed preferable to not force-source setvars.sh over and over if we know it's already been done before.



Patch:
diff --git a/conan/tools/intel/intel_cc.py b/conan/tools/intel/intel_cc.py
index 2722b475788..a2ab6d08211 100644
--- a/conan/tools/intel/intel_cc.py
+++ b/conan/tools/intel/intel_cc.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
 """
     Intel generator module for oneAPI Toolkits.
 
@@ -75,6 +73,10 @@ def ms_toolset(self):
     def generate(self, scope="build"):
         """Generate the Conan Intel file to be loaded in build environment by default"""
         check_duplicated_generator(self, self._conanfile)
+        intel_cc_path = self._conanfile.conf.get("tools.intel:installation_path")
+        if intel_cc_path == "":
+            return
+
         if platform.system() == "Windows" and not self._conanfile.win_bash:
             content = textwrap.dedent("""\
                 @echo off


Test patch:
diff --git a/test/integration/toolchains/intel/test_intel_cc.py b/test/integration/toolchains/intel/test_intel_cc.py
index 795ee1c094a..5b155437d2e 100644
--- a/test/integration/toolchains/intel/test_intel_cc.py
+++ b/test/integration/toolchains/intel/test_intel_cc.py
@@ -1,3 +1,4 @@
+import os
 import platform
 import textwrap
 
@@ -55,3 +56,16 @@ def test_intel_cc_generator_linux():
     conanintelsetvars = get_intel_cc_generator_file(os_, installation_path, "conanintelsetvars.sh")
     expected = '. "/opt/intel/oneapi/setvars.sh" intel64'
     assert conanintelsetvars == expected
+
+
+def test_avoid_generation():
+    # The empty string for tools.intel:installation_path avoids the generation
+    profile = intelprofile % ("Linux", "")
+    client = TestClient()
+    client.save({
+        "conanfile.txt": conanfile,
+        "intelprofile": profile,
+    })
+    client.run("install . -pr intelprofile")
+    files = os.listdir(client.current_folder)
+    assert "conanintelsetvars" not in ",".join(files)