-
Notifications
You must be signed in to change notification settings - Fork 214
Set CC and CXX environment variables for clang toolchain #1169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Thanks to @Kummallinen for the suggestion to set cc environment variables. I'll update this soon with details of how to test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using environment variables to select the compiler type will not be portable to other IDEs or to a CI build. So a core build project that builds with clang
in CDT would build with gcc
elsewhere unless equivalent environment variables are present. Is there an alternative that would preserve portability?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. One of the strongest arguments against Eclipse CDT is that "we can't build your project without using your IDE.".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I see a portability problem here. If the users CMake file needs a particular compiler to build they can set that in the CMake file and this won't interfere with it. The environment variables are to select the compiler for a CMake project which is compiler agnostic (fairly common case) without needing to create a toolchain file when one isn't needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additional point, in CI you'd likely just set the same environment variables in the docker container or CI pipeline used for build to nudge CMake into selecting Clang not GCC. This is generic CMake usage, nothing novel for Core Build
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference, setting these variables is the 1st way the CMake Wiki suggests to do this: https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#method-1-use-environment-variables.
Setting these does not stop the user doing it another way if they are using a different generator value for example & won't override anything the user sets in their toolchain, cmake files or customised command line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The environment variables are to select the compiler for a CMake project which is compiler agnostic (fairly common case) without needing to create a toolchain file when one isn't needed.
I don't think the end user will necessarily appreciate a distinction like this. All they observe is a toolchain selection UI which gives the impression that they can select the toolchain (both path and compiler name) that applies to the project.
If it is common practice for developers using CMake to rely on environment to select toolchain technology (gcc
or clang
) in the absence of a toolchain file, then perhaps we just need to clarify within the UI that the selection applies within the Eclipse IDE only and may be overriden by directives in CMakeLists.txt
, by CMake command line arguments or by toolchain file association.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it is common practice for developers using CMake to rely on environment to select toolchain technology (
gcc
orclang
) in the absence of a toolchain file, then perhaps we just need to clarify within the UI that the selection applies within the Eclipse IDE only and may be overriden by directives inCMakeLists.txt
, by CMake command line arguments or by toolchain file association.
This is very common and is intended by the CMake developers. From what I've seen toolchain files are typically used when cross-compiling as the system name & architecture also need to be set along with other settings such as a sysroot. Though those can also come from environment variables.
A warning in the UI that the toolchain may be overridden by any custom arguments the user sets or within the CMake file itself would make sense. It also applies to the current state without this change as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we set CC for clang, should we also set it for gcc in GCCToolChain
? Otherwise we introduce the opposite problem. This is less common, but the same issue happens in reverse if cc
is actually clang
, like this:
$ readlink -f `which cc`
/usr/lib/llvm-20/bin/clang
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I agree.
I have tested this and can reproduce the problem:
In a windows cmd shell,
set CC=clang
set CXX=clang++
Then launch eclipse CDT from this shell.
In a CMake project, in Build Settings, set Toolchain to:
C:\msys64\ucrt64\bin\gcc.exe
Build project.
Expected: Builds using gcc.
Actual: Builds using clang, eg:
"-- The C compiler identification is Clang 19.1.7
-- The CXX compiler identification is Clang 19.1.7
"
* set(CMAKE_C_COMPILER clang) | ||
* set(CMAKE_CXX_COMPILER clang++) | ||
*/ | ||
addIfAbsent("cc", "clang", envVarsNew); //$NON-NLS-1$ //$NON-NLS-2$ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc and cxx should be upper case!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does envVarsNew already include the system environment, or is it just the environment set by other parts of Core Build? If it includes the system environment then we cant use addIfAbsent as they will likely already be set if you're on Linux or macOS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does envVarsNew already include the system environment,
No; its the env from the core build and/or any env vars set by the user for a "User Defined Toolchain".
private static IEnvironmentVariable[] addClangEnvVars(IEnvironmentVariable[] envVars) { | ||
List<IEnvironmentVariable> envVarsNew = new ArrayList<>(Arrays.asList(envVars)); | ||
/* | ||
* Set CC and CXX environment variables for clang and clang++. This is equivalent to setting these in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also need to set the ASM environment variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we also need to set the ASM environment variable?
Good question. I do not think so. CMake appears to set ASM automatically to clang when CC is set to clang.
I tested this using the attached project.
cmakeASM.zip
In the screendshot below, it can be seen that the ASM is set to clang.exe.
Sets the C and C++ compiler environment variables so CMake uses Clang instead of the system default compiler. Fixes eclipse-cdt#1140
Tests Test cases Prerequisites To test The following shows an example of Console build output:
Test case B) Toolchain set to gcc, uses the default gcc compiler automatically. The following shows an example of Console build output:
[1]: Before you begin |
* However, on Windows, existing cc/cxx envVars with lower-case names will have their names changed to upper case; | ||
* the value remains unchanged.<br> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do this - can you simply use same logic as on Linux? See code comment for why I am asking the question
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In our meeting on Th 5 Jun, we discussed this and agreed on windows any lower case cc/cxx env vars should be changed to upper case.
Do you no longer think that is a good idea?
Otherwise, yes, the same logic as used on Linux can be used for Windows.
iterator.remove(); | ||
envVars.add(new EnvironmentVariable(name, evOldValue)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Goes with comment on line 73 and I have a suggestion attached to line 81-111
When you do the remove + add you may be changing the type and logic of the variable. The removed one may not be an EnvironmentVariable
but one of the other implementations of of IEnvironmentVariable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I see that now. Renaming the variable name is tricky. Perhaps we should forget about it.
if (Platform.OS_WIN32.equals(Platform.getOS())) { | ||
// On Windows: case-insensitive check ignores case. | ||
Iterator<IEnvironmentVariable> iterator = envVars.iterator(); | ||
boolean found = false; | ||
|
||
while (iterator.hasNext()) { | ||
IEnvironmentVariable ev = iterator.next(); | ||
if (ev.getName().equalsIgnoreCase(name)) { | ||
found = true; | ||
// Replace if existing name is in lower-case and new name is in upper-case | ||
if (!ev.getName().equals(name) && name.equals(name.toUpperCase())) { | ||
// Original value is respected. | ||
String evOldValue = ev.getValue(); | ||
iterator.remove(); | ||
envVars.add(new EnvironmentVariable(name, evOldValue)); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
if (!found) { | ||
envVars.add(new EnvironmentVariable(name, value)); | ||
} | ||
|
||
} else { | ||
// On non-Windows: case-sensitive check respects case (exact match). | ||
boolean isAbsent = envVars.stream().noneMatch(ev -> ev.getName().equals(name)); | ||
if (isAbsent) { | ||
envVars.add(new EnvironmentVariable(name, value)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (Platform.OS_WIN32.equals(Platform.getOS())) { | |
// On Windows: case-insensitive check ignores case. | |
Iterator<IEnvironmentVariable> iterator = envVars.iterator(); | |
boolean found = false; | |
while (iterator.hasNext()) { | |
IEnvironmentVariable ev = iterator.next(); | |
if (ev.getName().equalsIgnoreCase(name)) { | |
found = true; | |
// Replace if existing name is in lower-case and new name is in upper-case | |
if (!ev.getName().equals(name) && name.equals(name.toUpperCase())) { | |
// Original value is respected. | |
String evOldValue = ev.getValue(); | |
iterator.remove(); | |
envVars.add(new EnvironmentVariable(name, evOldValue)); | |
} | |
break; | |
} | |
} | |
if (!found) { | |
envVars.add(new EnvironmentVariable(name, value)); | |
} | |
} else { | |
// On non-Windows: case-sensitive check respects case (exact match). | |
boolean isAbsent = envVars.stream().noneMatch(ev -> ev.getName().equals(name)); | |
if (isAbsent) { | |
envVars.add(new EnvironmentVariable(name, value)); | |
} | |
} | |
boolean isAbsent = envVars.stream().noneMatch(ev -> { | |
if (Platform.OS_WIN32.equals(Platform.getOS())) { | |
return ev.getName().equalsIgnoreCase(name); | |
} else { | |
return ev.getName().equals(name); | |
} | |
}); | |
if (isAbsent) { | |
envVars.add(new EnvironmentVariable(name, value)); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we set CC for clang, should we also set it for gcc in GCCToolChain
? Otherwise we introduce the opposite problem. This is less common, but the same issue happens in reverse if cc
is actually clang
, like this:
$ readlink -f `which cc`
/usr/lib/llvm-20/bin/clang
Sets the C and C++ compiler environment variables so CMake uses Clang instead of the system default compiler.
Fixes #1140