Ninja: Remove shell workaround from compilation database

Commit 1528113bdf (instrumentation: Prevent inherited process metrics in
chained commands, 2026-09-14) added an extra command to successfully
track process metrics for instrumentation, working around shell exec
optimizations . However, this workaround gets exported into
`compile_commands.json` when using the Ninja generator, which breaks
some tools that consume the database.

Append this no-op command only when generating the actual build files.
This commit is contained in:
Martin Duffy authored and Brad King committed 2026-10-14 10:44:39 -04:00
1 parent 07ebd37501
commit 7690970a9c
5 files changed
+67 -6

No files matched your search

+8 -3
View File
@@ -509,7 +509,7 @@ bool RuleNeedsCMD(std::string const& cmd)
std::string cmLocalNinjaGenerator::BuildCommandLine(
std::vector<std::string> const& cmdLines, std::string const& outputConfig,
std::string const& commandConfig, std::string const& customStep,
cmGeneratorTarget const* target) const
cmGeneratorTarget const* target, CommandLineContext context) const
{
// If we have no commands but we need to build a command anyway, use noop.
// This happens when building a POST_BUILD value for link targets that
@@ -549,6 +549,7 @@ std::string cmLocalNinjaGenerator::BuildCommandLine(
std::ostringstream cmd;
#ifdef _WIN32
(void)context;
cmGlobalNinjaGenerator const* gg = this->GetGlobalNinjaGenerator();
bool const needCMD =
cmdLines.size() > 1 || (customStep.empty() && RuleNeedsCMD(cmdLines[0]));
@@ -577,12 +578,16 @@ std::string cmLocalNinjaGenerator::BuildCommandLine(
cmd << *li;
}
# ifndef CMAKE_BOOTSTRAP
if (this->GetCMakeInstance()->GetInstrumentation()->HasOption(
if (context == CommandLineContext::Build &&
this->GetCMakeInstance()->GetInstrumentation()->HasOption(
cmInstrumentationQuery::Option::ProcessMetrics)) {
// Prevent shell exec optimization from passing accumulated child resource
// usage to the final instrumentation wrapper.
// usage to the final instrumentation wrapper. Keep this build-only shell
// syntax out of compile_commands.json, for compiler tooling support
cmd << " && :";
}
# else
(void)context;
# endif
#endif
return cmd.str();
+8 -1
View File
@@ -65,11 +65,18 @@ public:
cmStateEnums::IntermediateDirKind kind =
cmStateEnums::IntermediateDirKind::ObjectFiles) const override;
enum class CommandLineContext
{
Build,
CompileCommands
};
std::string BuildCommandLine(
std::vector<std::string> const& cmdLines, std::string const& outputConfig,
std::string const& commandConfig,
std::string const& customStep = std::string(),
cmGeneratorTarget const* target = nullptr) const;
cmGeneratorTarget const* target = nullptr,
CommandLineContext context = CommandLineContext::Build) const;
void AppendTargetOutputs(cmGeneratorTarget* target, cmNinjaDeps& outputs,
std::string const& config);
+4 -2
View File
@@ -2682,7 +2682,8 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
}
std::string cmdLine = this->GetLocalGenerator()->BuildCommandLine(
compileCmds, outputConfig, outputConfig);
compileCmds, outputConfig, outputConfig, {}, nullptr,
cmLocalNinjaGenerator::CommandLineContext::CompileCommands);
this->GetGlobalGenerator()->AddCXXCompileCommand(cmdLine, sourceFileName,
objectFileName);
@@ -2755,7 +2756,8 @@ void cmNinjaTargetGenerator::ExportSwiftObjectCompileCommand(
}
std::string commandLine = this->GetLocalGenerator()->BuildCommandLine(
compileCmds, outputConfig, outputConfig);
compileCmds, outputConfig, outputConfig, {}, nullptr,
cmLocalNinjaGenerator::CommandLineContext::CompileCommands);
this->GetGlobalGenerator()->AddCXXCompileCommand(
commandLine, sourceFilename, objectFilename);
@@ -342,3 +342,49 @@ if (ARGS_BUILD_MAKE_PROGRAM)
add_error("No snippet files of role \"build\" were found in ${v1}")
endif()
endif()
if (ARGS_PROCESS_METRICS_QUERY)
# The process-metrics "&& :" suffix belongs only in build-tool shell commands,
# not exported compile commands.
set(compilation_database "${RunCMake_TEST_BINARY_DIR}/compile_commands.json")
if (EXISTS "${compilation_database}")
file(READ "${compilation_database}" compile_commands)
string(JSON command_count LENGTH "${compile_commands}")
if (command_count GREATER 0)
math(EXPR last_command "${command_count} - 1")
foreach(i RANGE 0 ${last_command})
string(JSON arguments_type ERROR_VARIABLE no_arguments
TYPE "${compile_commands}" ${i} arguments)
if (arguments_type STREQUAL "ARRAY")
# FASTBuild exports an argument array rather than a command string.
set(arguments)
string(JSON argument_count LENGTH "${compile_commands}" ${i} arguments)
if (argument_count GREATER 0)
math(EXPR last_argument "${argument_count} - 1")
foreach(j RANGE 0 ${last_argument})
string(JSON argument GET "${compile_commands}" ${i} arguments ${j})
list(APPEND arguments "${argument}")
endforeach()
endif()
else()
string(JSON command GET "${compile_commands}" ${i} command)
separate_arguments(arguments NATIVE_COMMAND "${command}")
endif()
list(LENGTH arguments argument_count)
if (argument_count EQUAL 0)
add_error("Compile command ${i} has no arguments")
elseif (argument_count GREATER_EQUAL 2)
list(GET arguments -2 penultimate_argument)
list(GET arguments -1 last_argument)
if (penultimate_argument STREQUAL "&&" AND last_argument STREQUAL ":")
add_error("Compile command contains process-metrics shell suffix: ${arguments}")
endif()
endif()
endforeach()
else()
add_error("No commands in ${compilation_database}")
endif()
else()
add_error("Missing ${compilation_database}")
endif()
endif()
@@ -1,4 +1,5 @@
set_property(GLOBAL PROPERTY INSTALL_PARALLEL ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1.2