Autogen: Add moc path prefix generation (AUTOMOC_PATH_PREFIX)

The new `AUTOMOC_PATH_PREFIX` boolean target property enables automatic
generation of the path prefix `-p` option for `moc`.
`AUTOMOC_PATH_PREFIX` is initialized from the variable
`CMAKE_AUTOMOC_PATH_PREFIX`, which is ON by default.

When `AUTOMOC_PATH_PREFIX` is enabled, CMake tests if a `moc`ed header file is
in one of the include directories.  If so, then the `-p` option, with the
relative path of the header parent directory to the respective include
directory, is added to the `moc` command.  If the header file is not in an
include directory, the `-p` option is omitted.

Closes: #18815 "AUTOMOC: generated files include full relative path,
                breaking certain reproducible builds"
This commit is contained in:
Sebastian Holtermann 2019-09-13 15:17:24 +02:00
parent 77983c8147
commit d018d27c10
5 changed files with 84 additions and 37 deletions

View File

@ -26,6 +26,7 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a")
set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON) set(CMAKE_AUTOGEN_ORIGIN_DEPENDS ON)
set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON) set(CMAKE_AUTOMOC_COMPILER_PREDEFINES ON)
set(CMAKE_AUTOMOC_PATH_PREFIX ON)
set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE") set(CMAKE_AUTOMOC_MACRO_NAMES "Q_OBJECT" "Q_GADGET" "Q_NAMESPACE")
# basically all general purpose OSs support shared libs # basically all general purpose OSs support shared libs

View File

@ -1376,6 +1376,8 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo()
ofs.Write("AM_MOC_OPTIONS", ofs.Write("AM_MOC_OPTIONS",
this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS"));
ofs.Write("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); ofs.Write("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE"));
ofs.Write("AM_MOC_PATH_PREFIX",
this->GenTarget->GetSafeProperty("AUTOMOC_PATH_PREFIX"));
ofs.Write("AM_MOC_MACRO_NAMES", ofs.Write("AM_MOC_MACRO_NAMES",
this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES")); this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES"));
ofs.Write("AM_MOC_DEPEND_FILTERS", ofs.Write("AM_MOC_DEPEND_FILTERS",

View File

@ -279,12 +279,10 @@ void cmQtAutoMocUic::JobMocPredefsT::Process()
{ {
// Compose command // Compose command
std::vector<std::string> cmd = MocConst().PredefsCmd; std::vector<std::string> cmd = MocConst().PredefsCmd;
// Add includes
cmAppend(cmd, MocConst().Includes);
// Add definitions // Add definitions
for (std::string const& def : MocConst().Definitions) { cmAppend(cmd, MocConst().OptionsDefinitions);
cmd.emplace_back("-D" + def); // Add includes
} cmAppend(cmd, MocConst().OptionsIncludes);
// Execute command // Execute command
if (!RunProcess(GenT::MOC, result, cmd, reason.get())) { if (!RunProcess(GenT::MOC, result, cmd, reason.get())) {
LogCommandError(GenT::MOC, LogCommandError(GenT::MOC,
@ -1385,17 +1383,50 @@ void cmQtAutoMocUic::JobCompileMocT::Process()
// Compose moc command // Compose moc command
std::vector<std::string> cmd; std::vector<std::string> cmd;
cmd.push_back(MocConst().Executable); {
// Add options // Reserve large enough
cmAppend(cmd, MocConst().AllOptions); cmd.reserve(MocConst().OptionsDefinitions.size() +
// Add predefs include MocConst().OptionsIncludes.size() +
if (!MocConst().PredefsFileAbs.empty()) { MocConst().OptionsExtra.size() + 16);
cmd.emplace_back("--include"); cmd.push_back(MocConst().Executable);
cmd.push_back(MocConst().PredefsFileAbs); // Add definitions
cmAppend(cmd, MocConst().OptionsDefinitions);
// Add includes
cmAppend(cmd, MocConst().OptionsIncludes);
// Add predefs include
if (!MocConst().PredefsFileAbs.empty()) {
cmd.emplace_back("--include");
cmd.push_back(MocConst().PredefsFileAbs);
}
// Add path prefix on demand
if (MocConst().PathPrefix && Mapping->SourceFile->IsHeader) {
for (std::string const& dir : MocConst().IncludePaths) {
cm::string_view prefix = sourceFile;
if (cmHasPrefix(prefix, dir)) {
prefix.remove_prefix(dir.size());
if (cmHasPrefix(prefix, '/')) {
prefix.remove_prefix(1);
auto slashPos = prefix.rfind('/');
if (slashPos != cm::string_view::npos) {
cmd.emplace_back("-p");
cmd.emplace_back(prefix.substr(0, slashPos));
} else {
cmd.emplace_back("-p");
cmd.emplace_back("./");
}
break;
}
}
}
}
// Add extra options
cmAppend(cmd, MocConst().OptionsExtra);
// Add output file
cmd.emplace_back("-o");
cmd.push_back(outputFile);
// Add source file
cmd.push_back(sourceFile);
} }
cmd.emplace_back("-o");
cmd.push_back(outputFile);
cmd.push_back(sourceFile);
// Execute moc command // Execute moc command
cmWorkerPool::ProcessResultT result; cmWorkerPool::ProcessResultT result;
@ -1654,8 +1685,11 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
} }
MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS");
MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES"); MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES");
MocConst_.Options = InfoGetList("AM_MOC_OPTIONS"); MocConst_.OptionsExtra = InfoGetList("AM_MOC_OPTIONS");
MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE");
MocConst_.PathPrefix = InfoGetBool("AM_MOC_PATH_PREFIX");
for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) { for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) {
MocConst_.MacroFilters.emplace_back( MocConst_.MacroFilters.emplace_back(
item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]"));
@ -1846,9 +1880,9 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
// Compose moc includes list // Compose moc includes list
{ {
// Compute framework paths
std::set<std::string> frameworkPaths; std::set<std::string> frameworkPaths;
for (std::string const& path : MocConst().IncludePaths) { for (std::string const& path : MocConst().IncludePaths) {
MocConst_.Includes.push_back("-I" + path);
// Extract framework path // Extract framework path
if (cmHasLiteralSuffix(path, ".framework/Headers")) { if (cmHasLiteralSuffix(path, ".framework/Headers")) {
// Go up twice to get to the framework root // Go up twice to get to the framework root
@ -1858,26 +1892,26 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile)
pathComponents.begin(), pathComponents.end() - 2)); pathComponents.begin(), pathComponents.end() - 2));
} }
} }
// Reserve options
MocConst_.OptionsIncludes.reserve(MocConst().IncludePaths.size() +
frameworkPaths.size() * 2);
// Append includes
for (std::string const& path : MocConst().IncludePaths) {
MocConst_.OptionsIncludes.emplace_back("-I" + path);
}
// Append framework includes // Append framework includes
for (std::string const& path : frameworkPaths) { for (std::string const& path : frameworkPaths) {
MocConst_.Includes.emplace_back("-F"); MocConst_.OptionsIncludes.emplace_back("-F");
MocConst_.Includes.push_back(path); MocConst_.OptionsIncludes.push_back(path);
} }
} }
// Setup single list with all options
// Compose moc definitions list
{ {
// Add includes MocConst_.OptionsDefinitions.reserve(MocConst().Definitions.size());
MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
MocConst().Includes.begin(),
MocConst().Includes.end());
// Add definitions
for (std::string const& def : MocConst().Definitions) { for (std::string const& def : MocConst().Definitions) {
MocConst_.AllOptions.push_back("-D" + def); MocConst_.OptionsDefinitions.emplace_back("-D" + def);
} }
// Add options
MocConst_.AllOptions.insert(MocConst_.AllOptions.end(),
MocConst().Options.begin(),
MocConst().Options.end());
} }
} }
@ -1971,10 +2005,18 @@ void cmQtAutoMocUic::SettingsFileRead()
if (MocConst_.Enabled) { if (MocConst_.Enabled) {
cryptoHash.Initialize(); cryptoHash.Initialize();
cha(MocConst().Executable); cha(MocConst().Executable);
std::for_each(MocConst().AllOptions.begin(), MocConst().AllOptions.end(), for (auto const& item : MocConst().OptionsDefinitions) {
cha); cha(item);
std::for_each(MocConst().PredefsCmd.begin(), MocConst().PredefsCmd.end(), }
cha); for (auto const& item : MocConst().OptionsIncludes) {
cha(item);
}
for (auto const& item : MocConst().OptionsExtra) {
cha(item);
}
for (auto const& item : MocConst().PredefsCmd) {
cha(item);
}
for (auto const& filter : MocConst().DependFilters) { for (auto const& filter : MocConst().DependFilters) {
cha(filter.Key); cha(filter.Key);
} }

View File

@ -212,16 +212,17 @@ public:
bool Enabled = false; bool Enabled = false;
bool SettingsChanged = false; bool SettingsChanged = false;
bool RelaxedMode = false; bool RelaxedMode = false;
bool PathPrefix = false;
cmFileTime ExecutableTime; cmFileTime ExecutableTime;
std::string Executable; std::string Executable;
std::string CompFileAbs; std::string CompFileAbs;
std::string PredefsFileAbs; std::string PredefsFileAbs;
std::unordered_set<std::string> SkipList; std::unordered_set<std::string> SkipList;
std::vector<std::string> IncludePaths; std::vector<std::string> IncludePaths;
std::vector<std::string> Includes;
std::vector<std::string> Definitions; std::vector<std::string> Definitions;
std::vector<std::string> Options; std::vector<std::string> OptionsIncludes;
std::vector<std::string> AllOptions; std::vector<std::string> OptionsDefinitions;
std::vector<std::string> OptionsExtra;
std::vector<std::string> PredefsCmd; std::vector<std::string> PredefsCmd;
std::vector<KeyExpT> DependFilters; std::vector<KeyExpT> DependFilters;
std::vector<KeyExpT> MacroFilters; std::vector<KeyExpT> MacroFilters;

View File

@ -312,6 +312,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("AUTOMOC_MACRO_NAMES"); initProp("AUTOMOC_MACRO_NAMES");
initProp("AUTOMOC_MOC_OPTIONS"); initProp("AUTOMOC_MOC_OPTIONS");
initProp("AUTOUIC_OPTIONS"); initProp("AUTOUIC_OPTIONS");
initProp("AUTOMOC_PATH_PREFIX");
initProp("AUTOUIC_SEARCH_PATHS"); initProp("AUTOUIC_SEARCH_PATHS");
initProp("AUTORCC_OPTIONS"); initProp("AUTORCC_OPTIONS");
initProp("LINK_DEPENDS_NO_SHARED"); initProp("LINK_DEPENDS_NO_SHARED");