Merge topic 'automoc-predefs-msvc'

7c3ca57b91 MSVC,Clang: Set CMAKE_CXX_COMPILER_PREDEFINES_COMMAND for the MSVC ABI
0fd711348c Autogen: Pass WIN32 to moc when targeting the MSVC ABI
4a4a654814 Autogen: Keep stderr out of the generated moc_predefs.h
1c1258ad95 cmWorkerPool: Allow capturing process stderr separately

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: buildbot <buildbot@kitware.com>
Merge-request: !12517
This commit is contained in:
Brad King
2026-09-22 10:14:46 -04:00
committed by Kitware Robot
9 changed files with 91 additions and 16 deletions
+3
View File
@@ -0,0 +1,3 @@
// An empty translation unit for CMAKE_<LANG>_COMPILER_PREDEFINES_COMMAND.
// MSVC-like compilers echo the preprocessed source along with the macro
// definitions, so the input must contribute no output of its own.
+25
View File
@@ -20,6 +20,31 @@ if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_DRIVER_MODE "cl")
endif()
# 'Compiler/GNU' is not included when clang simulates MSVC, so the predefines
# command is not set up there.
if(NOT DEFINED CMAKE_CXX_COMPILER_PREDEFINES_COMMAND)
set(CMAKE_CXX_COMPILER_PREDEFINES_COMMAND "${CMAKE_CXX_COMPILER}")
if(CMAKE_CXX_COMPILER_ARG1)
separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_CXX_COMPILER_ARG1}")
list(APPEND CMAKE_CXX_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
unset(_COMPILER_ARGS)
endif()
if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
# '-dM' is a cc1 option in this driver mode, and '-EP' also echoes the
# preprocessed source, hence the empty translation unit.
list(APPEND CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
"-nologo" "-w" "-Xclang" "-dM" "-EP"
"${CMAKE_ROOT}/Modules/CMakeCXXCompilerPredefines.cpp")
else()
list(APPEND CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
"-w" "-dM" "-E" "${CMAKE_ROOT}/Modules/CMakeCXXCompilerABI.cpp")
endif()
if(CMAKE_CXX_COMPILER_TARGET)
list(APPEND CMAKE_CXX_COMPILER_PREDEFINES_COMMAND
"--target=${CMAKE_CXX_COMPILER_TARGET}")
endif()
endif()
if((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0 AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") OR
(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.1 AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
if (CMAKE_CXX_COMPILER_CLANG_RESOURCE_DIR)
+17
View File
@@ -23,5 +23,22 @@ macro(__compiler_msvc lang)
set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang}_WARNING "-external:W0 ")
endif ()
# '/PD' dumps the predefined macros, but it needs the conforming
# preprocessor and one of '/E', '/EP' or '/P'. VS 2019 16.7 and older
# ignore it with warning D9002, so require 16.8. '/EP' also echoes the
# preprocessed source, hence the empty translation unit.
if("${lang}" STREQUAL "CXX" AND
CMAKE_${lang}_COMPILER_VERSION VERSION_GREATER_EQUAL 19.28)
set(CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND "${CMAKE_${lang}_COMPILER}")
if(CMAKE_${lang}_COMPILER_ARG1)
separate_arguments(_COMPILER_ARGS NATIVE_COMMAND "${CMAKE_${lang}_COMPILER_ARG1}")
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND ${_COMPILER_ARGS})
unset(_COMPILER_ARGS)
endif()
list(APPEND CMAKE_${lang}_COMPILER_PREDEFINES_COMMAND
"-nologo" "-w" "-Zc:preprocessor" "-PD" "-EP"
"${CMAKE_ROOT}/Modules/CMakeCXXCompilerPredefines.cpp")
endif()
set(CMAKE_${lang}_LINK_MODE LINKER)
endmacro()
+13 -4
View File
@@ -713,6 +713,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets()
return true;
}
bool cmQtAutoGenInitializer::IsMsvcAbi() const
{
return this->Makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") ==
"MSVC" ||
this->Makefile->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") == "MSVC";
}
bool cmQtAutoGenInitializer::InitMoc()
{
// Mocs compilation file
@@ -814,10 +821,12 @@ bool cmQtAutoGenInitializer::InitMoc()
auto getDefs = [this](std::string const& cfg) -> std::set<std::string> {
std::set<std::string> defines;
this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines);
if (this->Moc.PredefsCmd.empty() &&
this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") ==
"Windows") {
// Add WIN32 definition if we don't have a moc_predefs.h
if (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") ==
"Windows" &&
(this->Moc.PredefsCmd.empty() || this->IsMsvcAbi())) {
// Add WIN32 definition if moc_predefs.h cannot supply it. Targeting
// the MSVC ABI it comes from our default flags rather than from the
// compiler, so it never appears in moc_predefs.h.
defines.insert("WIN32");
}
return defines;
+3
View File
@@ -111,6 +111,9 @@ private:
return (this->Moc.Enabled || this->Uic.Enabled);
}
/** Whether the CXX compiler targets the MSVC ABI. */
bool IsMsvcAbi() const;
bool InitMoc();
bool InitUic();
bool InitRcc();
+10 -6
View File
@@ -359,7 +359,8 @@ public:
/** @brief Run an external process. Use only during Process() call! */
bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result,
std::vector<std::string> const& command,
std::string* infoMessage = nullptr);
std::string* infoMessage = nullptr,
bool mergedOutput = true);
};
/** Fence job utility class. */
@@ -863,7 +864,8 @@ void cmQtAutoMocUicT::JobT::MaybeWriteResponseFile(
bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
cmWorkerPool::ProcessResultT& result,
std::vector<std::string> const& command,
std::string* infoMessage)
std::string* infoMessage,
bool mergedOutput)
{
// Log command
if (this->Log().Verbose()) {
@@ -878,7 +880,7 @@ bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType,
}
// Run command
return this->cmWorkerPool::JobT::RunProcess(
result, command, this->BaseConst().AutogenBuildDir);
result, command, this->BaseConst().AutogenBuildDir, mergedOutput);
}
void cmQtAutoMocUicT::JobMocPredefsT::Process()
@@ -904,13 +906,15 @@ void cmQtAutoMocUicT::JobMocPredefsT::Process()
// Check if response file is necessary
MaybeWriteResponseFile(this->MocConst().PredefsFileAbs, cmd);
// Execute command
if (!this->RunProcess(GenT::MOC, result, cmd, reason.get())) {
// Execute command. Keep stderr out of the captured stdout, which is
// written to the predefs file verbatim: MSVC-like compilers echo the
// name of the source file they preprocess.
if (!this->RunProcess(GenT::MOC, result, cmd, reason.get(), false)) {
this->LogCommandError(GenT::MOC,
cmStrCat("The content generation command for ",
this->MessagePath(predefsFileAbs),
" failed.\n", result.ErrorMessage),
cmd, result.StdOut);
cmd, result.StdOut + result.StdErr);
return;
}
}
+8 -5
View File
@@ -401,7 +401,7 @@ public:
*/
bool RunProcess(cmWorkerPool::ProcessResultT& result,
std::vector<std::string> command,
std::string const& workingDirectory);
std::string const& workingDirectory, bool mergedOutput);
private:
// -- Libuv callbacks
@@ -434,7 +434,8 @@ cmWorkerPoolWorker::~cmWorkerPoolWorker()
bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
std::vector<std::string> command,
std::string const& workingDirectory)
std::string const& workingDirectory,
bool mergedOutput)
{
if (command.empty()) {
return false;
@@ -443,7 +444,7 @@ bool cmWorkerPoolWorker::RunProcess(cmWorkerPool::ProcessResultT& result,
{
std::lock_guard<std::mutex> lock(this->Proc_.Mutex);
this->Proc_.ROP = cm::make_unique<cmUVReadOnlyProcess>();
this->Proc_.ROP->setup(&result, true, std::move(command),
this->Proc_.ROP->setup(&result, mergedOutput, std::move(command),
workingDirectory);
}
// Send asynchronous process start request to libuv loop
@@ -737,11 +738,13 @@ cmWorkerPool::JobT::~JobT() = default;
bool cmWorkerPool::JobT::RunProcess(ProcessResultT& result,
std::vector<std::string> command,
std::string const& workingDirectory)
std::string const& workingDirectory,
bool mergedOutput)
{
// Get worker by index
auto* worker = this->Pool_->Int_->Workers.at(this->WorkerIndex_).get();
return worker->RunProcess(result, std::move(command), workingDirectory);
return worker->RunProcess(result, std::move(command), workingDirectory,
mergedOutput);
}
cmWorkerPool::cmWorkerPool()
+4 -1
View File
@@ -101,9 +101,12 @@ public:
/**
* Run an external read only process.
* Use only during JobT::Process() call!
* @arg mergedOutput Append the process stderr to ProcessResultT::StdOut
* instead of ProcessResultT::StdErr.
*/
bool RunProcess(ProcessResultT& result, std::vector<std::string> command,
std::string const& workingDirectory);
std::string const& workingDirectory,
bool mergedOutput = true);
private:
//! Needs access to Work()
@@ -11,6 +11,14 @@ set(CMAKE_CXX_EXTENSIONS OFF)
add_library(MocPredefs MocPredefs.cxx)
if(NOT DEFINED CMAKE_CXX_COMPILER_PREDEFINES_COMMAND)
# Do not silently skip on toolchains that are expected to provide it.
if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND MSVC_VERSION GREATER_EQUAL 1928)
OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"
AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC"))
message(FATAL_ERROR
"CMAKE_CXX_COMPILER_PREDEFINES_COMMAND is not defined for "
"${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}.")
endif()
return()
endif()