1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00
This commit is contained in:
John Moule 2025-06-02 17:27:04 +01:00 committed by GitHub
commit 5ae490a1ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 198 additions and 2 deletions

View file

@ -0,0 +1,116 @@
/*******************************************************************************
* Copyright (c) 2025 Renesas Electronics Europe.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.cdt.build.gcc.core.tests;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import java.util.Arrays;
import org.eclipse.cdt.build.gcc.core.ClangToolChain;
import org.eclipse.cdt.core.build.IToolChain;
import org.eclipse.cdt.core.envvar.EnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.core.runtime.Platform;
import org.junit.Test;
/**
* Tests for org.eclipse.cdt.build.gcc.core.ClangToolChain
* Tests that the environment variables CC and CXX are set to clang values.
*/
public class TestClangToolChain {
/**
* Tests ClangToolChain.ClangToolChain(IToolChainProvider provider, Path pathToToolChain, String arch,
IEnvironmentVariable[] envVars).
* Where envVars is null.
* Expected:
* envVars contains "CC=clang", "CXX=clang++"
*/
@Test
public void clangContainsEnvVarsNull() throws Exception {
IToolChain tc = new ClangToolChain(null, null, null, null);
IEnvironmentVariable[] variables = tc.getVariables();
assertThat(Arrays.asList(variables), contains(//
new EnvironmentVariable("CC", "clang"), //
new EnvironmentVariable("CXX", "clang++")));
}
/**
* Tests ClangToolChain.ClangToolChain(IToolChainProvider provider, Path pathToToolChain, String arch,
IEnvironmentVariable[] envVars).
* Where envVars is empty.
* Expected:
* envVars contains "CC=clang", "CXX=clang++"
*/
@Test
public void clangContainsEnvVarsEmpty() throws Exception {
IEnvironmentVariable[] envVars = {};
IToolChain tc = new ClangToolChain(null, null, null, envVars);
IEnvironmentVariable[] variables = tc.getVariables();
assertThat(Arrays.asList(variables), contains(//
new EnvironmentVariable("CC", "clang"), //
new EnvironmentVariable("CXX", "clang++")));
}
/**
* Tests ClangToolChain.ClangToolChain(IToolChainProvider provider, Path pathToToolChain, String arch,
IEnvironmentVariable[] envVars).
* Where envVars contains "cc=testvalue"
* Expected:
* (Windows): envVars contains "CC=testvalue", "CXX=clang++"
* (non-Windows): envVars contains "cc=testvalue", "CC=clang", "CXX=clang++"
*/
@Test
public void clangContainscc() throws Exception {
IEnvironmentVariable[] envVars = { new EnvironmentVariable("cc", "testvalue") };
IToolChain tc = new ClangToolChain(null, null, null, envVars);
IEnvironmentVariable[] variables = tc.getVariables();
if (Platform.OS_WIN32.equals(Platform.getOS())) {
/*
* Windows: case-insensitive environment; cc is replaced with uppercase CC. value remains unchanged.
*/
assertThat(Arrays.asList(variables), not(hasItem(new EnvironmentVariable("cc", "testvalue"))));
assertThat(Arrays.asList(variables),
contains(new EnvironmentVariable("CC", "testvalue"), new EnvironmentVariable("CXX", "clang++")));
// the clang override value not applied because the envVar already existed.
assertThat(Arrays.asList(variables), not(hasItem(new EnvironmentVariable("CC", "clang"))));
} else {
/*
* Non-Windows: case-sensitive environment; cc is not replaced with uppercase CC. CC is added in addition to any cc.
*/
assertThat(Arrays.asList(variables), contains(//
new EnvironmentVariable("cc", "testvalue"), //
new EnvironmentVariable("CC", "clang"), //
new EnvironmentVariable("CXX", "clang++")));
}
}
/**
* Tests ClangToolChain.ClangToolChain(IToolChainProvider provider, Path pathToToolChain, String arch,
IEnvironmentVariable[] envVars).
* Where envVars contains "CC=testvalue"
* Expected:
* envVars contains "CC=testvalue", "CXX=clang++"
*/
@Test
public void clangContainsCC() throws Exception {
IEnvironmentVariable[] envVars = { new EnvironmentVariable("CC", "testvalue") };
IToolChain tc = new ClangToolChain(null, null, null, envVars);
IEnvironmentVariable[] variables = tc.getVariables();
assertThat(Arrays.asList(variables), contains(//
new EnvironmentVariable("CC", "testvalue"), //
new EnvironmentVariable("CXX", "clang++")));
}
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2017 QNX Software Systems and others.
* Copyright (c) 2017, 2025 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@ -11,9 +11,15 @@
package org.eclipse.cdt.build.gcc.core;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.cdt.core.build.IToolChainProvider;
import org.eclipse.cdt.core.envvar.EnvironmentVariable;
import org.eclipse.cdt.core.envvar.IEnvironmentVariable;
import org.eclipse.core.runtime.Platform;
/**
* The Clang toolchain. There's little different from the GCC toolchain other
@ -28,7 +34,81 @@ public class ClangToolChain extends GCCToolChain {
public ClangToolChain(IToolChainProvider provider, Path pathToToolChain, String arch,
IEnvironmentVariable[] envVars) {
super(provider, pathToToolChain, arch, envVars);
super(provider, pathToToolChain, arch, addClangEnvVars(envVars));
}
/**
* Add the environment variables CC and CXX, set to clang and clang++, to override the C/C++ compiler executable
* that CMake uses.
*
* Other methods of setting the compiler in CMake (eg; CMAKE_<LANG>_COMPILER in CMakeLists.txt,
* -DCMAKE_TOOLCHAIN_FILE=file) take precedence over these environment variables, so the user is not
* inhibited by this approach.
*
* @param envVars Environment variables originate from the core build toolchain (either "Discovered toolchain" or
* "User defined toolchain"); these are not the OS system envVars. When the tc is a user defined, it is possible to
* specify arbitrary environment variables, meaning the user may have already defined CC/CXX.
* If CC/CXX is already defined then nothing is added.
*
* @return the existing array of envVars, plus if they didn't already exist the envVars CC and CXX set for clang.
*/
private static IEnvironmentVariable[] addClangEnvVars(IEnvironmentVariable[] envVars) {
List<IEnvironmentVariable> envVarsNew = new ArrayList<>();
// envVars can be null if the user defined tc did not specify any env variables.
if (envVars != null) {
envVarsNew.addAll(Arrays.asList(envVars));
}
addIfAbsent("CC", "clang", envVarsNew); //$NON-NLS-1$ //$NON-NLS-2$
addIfAbsent("CXX", "clang++", envVarsNew); //$NON-NLS-1$ //$NON-NLS-2$
return envVarsNew.toArray(new EnvironmentVariable[0]);
}
/**
* @param name The name of the environment variable.
* On case insensitive platforms (windows) the case is ignored. If an envVar with the name "cc" already exists,
* a new envVar will NOT be added.<br>
*
* However, on Windows, existing cc/cxx envVars with lower-case names will have their names changed to upper case;
* the value remains unchanged.<br>
*
* On case sensitive platforms (Non-windows) the case is respected. If an envVar with the name "cc" already exists,
* a new envVar with name "CC" will be added using the value in {@code value}.
* @param value The value of the environment variable.
* @param envVars List of environment variables to check and potentially add to.
*/
private static void addIfAbsent(String name, String value, List<IEnvironmentVariable> envVars) {
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));
}
}
}
@Override