Skip to content

Commit e138646

Browse files
Ensure full ICBuildConfiguration environment is used during scanning (#1095)
Under certain conditions*, the compiler param in the command field of the compile_commands.json is a relative path rather than absolute. When this happens, the built-ins detection was not successful and the following exception was thrown: !ENTRY org.eclipse.cdt.core 4 0 2025-02-23 20:32:10.752 !MESSAGE Error: Cannot run program "gcc": Launching failed !STACK 0 java.io.IOException: Cannot run program "gcc": Launching failed at org.eclipse.cdt.utils.spawner.Spawner.exec(Spawner.java:450) at org.eclipse.cdt.utils.spawner.Spawner.<init>(Spawner.java:147) at org.eclipse.cdt.utils.spawner.Spawner.<init>(Spawner.java:134) at org.eclipse.cdt.utils.spawner.ProcessFactory$Builder.start(ProcessFactory.java:273) at org.eclipse.cdt.utils.spawner.ProcessFactory.exec(ProcessFactory.java:366) at org.eclipse.cdt.core.CommandLauncher.execute(CommandLauncher.java:189) at org.eclipse.cdt.jsoncdb.core.internal.builtins.CompilerBuiltinsDetector.detectBuiltins(CompilerBuiltinsDetector.java:111) at org.eclipse.cdt.jsoncdb.core.CompileCommandsJsonParser.detectBuiltins(CompileCommandsJsonParser.java:290) at org.eclipse.cdt.jsoncdb.core.CompileCommandsJsonParser.processJsonFile(CompileCommandsJsonParser.java:193) at org.eclipse.cdt.jsoncdb.core.CompileCommandsJsonParser.parse(CompileCommandsJsonParser.java:455) at org.eclipse.cdt.cmake.core.CMakeBuildConfiguration.processCompileCommandsFile(CMakeBuildConfiguration.java:361) at org.eclipse.cdt.cmake.core.CMakeBuildConfiguration.build(CMakeBuildConfiguration.java:241) This meant that source file includes were not indexed and could not be opened using Open Declaration (F3) and info markers of the following type appeared in the Problems view: gcc -E -P -dM -Wp,-v "...extCmakegcc\\build\\cmake.run.win32.x86_64.Local\\detect_compiler_builtins.c" Cannot run program "gcc": Launching failed Error: Program "gcc" not found in PATH PATH=[...] extCmakegcc Unknown Compiler Builtins Detector Problem gcc -E -P -dM -Wp,-v "...extCmakegcc\\build\\cmake.run.win32.x86_64.Local\\detect_compiler_builtins.c" Cannot run program "gcc": Launching failed This patch fixes the environment issue for Core Build projects, by calling ICBuildConfiguration.setBuildEnvironment(Map<String, String>) as part of the built-ins detection setup, thereby supporting absolute and relative compiler paths. Addresses Issue: CDT CMake Improvements #1000, IDE-82683-REQ-011 Source code navigation and Built-ins detection *: CMake produces relative compiler path When the CMAKE_<LANG>_COMPILER variable (eg CMAKE_C_COMPILER) is set in the CMakeLists.txt *after* the project() or language commands, it causes a relative path to be used. For example, in the CMakeLists.txt below, gcc is set after project() command: cmake_minimum_required(VERSION 3.10) project (track2) set(CMAKE_C_COMPILER gcc) add_executable(${PROJECT_NAME} track2.c) The above script creates a relative compiler path in compile_commands.json: "command": "gcc -O3 -DNDEBUG -o ... Normally the CMAKE_C_COMPILER variable should be set before the project() comannd. "command": "C:\\msys64\\mingw64\\bin\\c++.exe -IC... Co-authored-by: Jonah Graham <[email protected]>
1 parent 74c4844 commit e138646

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

jsoncdb/org.eclipse.cdt.jsoncdb.core/src/org/eclipse/cdt/jsoncdb/core/internal/builtins/CompilerBuiltinsDetector.java

+45-19
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
import java.util.HashMap;
1818
import java.util.List;
1919
import java.util.Objects;
20+
import java.util.Properties;
2021

2122
import org.eclipse.cdt.core.CCorePlugin;
2223
import org.eclipse.cdt.core.ConsoleOutputStream;
2324
import org.eclipse.cdt.core.ICommandLauncher;
25+
import org.eclipse.cdt.core.build.ICBuildConfiguration;
26+
import org.eclipse.cdt.core.build.ICBuildConfigurationManager;
2427
import org.eclipse.cdt.core.resources.IConsole;
2528
import org.eclipse.cdt.jsoncdb.core.IParserPreferences;
2629
import org.eclipse.cdt.jsoncdb.core.IParserPreferencesAccess;
@@ -29,6 +32,8 @@
2932
import org.eclipse.cdt.jsoncdb.core.participant.builtins.IBuiltinsDetectionBehavior;
3033
import org.eclipse.cdt.jsoncdb.core.participant.builtins.IBuiltinsOutputProcessor;
3134
import org.eclipse.cdt.jsoncdb.core.participant.builtins.OutputSniffer;
35+
import org.eclipse.cdt.utils.spawner.EnvironmentReader;
36+
import org.eclipse.core.resources.IBuildConfiguration;
3237
import org.eclipse.core.resources.IMarker;
3338
import org.eclipse.core.resources.IProject;
3439
import org.eclipse.core.runtime.CoreException;
@@ -185,25 +190,8 @@ private List<String> getCompilerArguments() {
185190
* return {@code null}.
186191
*/
187192
private String[] getEnvp(IProject project) {
188-
var map = new HashMap<String, String>();
189-
// The cc.exe from mingw64 (part of Msys2) on Windows needs the bin folder to be on the PATH to be executed.
190-
// e.g. 'C:\msys64\mingw64\bin' must be part of the PATH environment variable. That's why we need PATH here:
191-
// Fixes CDT #407
192-
try {
193-
final String path = "PATH"; //$NON-NLS-1$
194-
var variables = CCorePlugin.getDefault().getBuildEnvironmentManager()
195-
.getVariables(project.getActiveBuildConfig(), true);
196-
for (var variable : variables) {
197-
if (path.equalsIgnoreCase(variable.getName())) {
198-
map.put(path, variable.getValue());
199-
break;
200-
}
201-
}
202-
} catch (CoreException e) {
203-
Plugin.getDefault().getLog().error(
204-
String.format(Messages.CompilerBuiltinsDetector_errmsg_determine_PATH_failed, project.getName()),
205-
e);
206-
}
193+
var map = getProjectEnvp(project);
194+
207195
// On POSIX (Linux, UNIX) systems reset language variables to default (English)
208196
// with UTF-8 encoding since GNU compilers can handle only UTF-8 characters.
209197
// Include paths with locale characters will be handled properly regardless
@@ -227,6 +215,44 @@ private String[] getEnvp(IProject project) {
227215
return envArray;
228216
}
229217

218+
/**
219+
* Return the project's environment. This applies any project specific environment
220+
* to the system environment.
221+
*/
222+
private HashMap<String, String> getProjectEnvp(IProject project) {
223+
var map = new HashMap<String, String>();
224+
Properties environmentVariables = EnvironmentReader.getEnvVars();
225+
for (String key : environmentVariables.stringPropertyNames()) {
226+
String value = environmentVariables.getProperty(key);
227+
map.put(key, value);
228+
}
229+
230+
IBuildConfiguration active = null;
231+
try {
232+
active = project.getActiveBuildConfig();
233+
if (active == null) {
234+
// unreachable, getActiveBuildConfig is documented as not returning null.
235+
} else {
236+
var manager = CCorePlugin.getService(ICBuildConfigurationManager.class);
237+
ICBuildConfiguration cBuildConfiguration = manager.getBuildConfiguration(active);
238+
239+
if (cBuildConfiguration != null) {
240+
// If this project is Core Build, use its specialisation of getBuildEnvironmentManager
241+
// to get the environment.
242+
cBuildConfiguration.setBuildEnvironment(map);
243+
} else {
244+
CCorePlugin.getDefault().getBuildEnvironmentManager().setEnvironment(map, active, true);
245+
}
246+
}
247+
} catch (CoreException e) {
248+
Plugin.getDefault().getLog().error(
249+
String.format(Messages.CompilerBuiltinsDetector_errmsg_determine_PATH_failed, project.getName()),
250+
e);
251+
}
252+
253+
return map;
254+
}
255+
230256
/**
231257
* Gets a path to the source file which is the input for the compiler. The file
232258
* will be created with no content in the build directory.

0 commit comments

Comments
 (0)