From dbda590628868e37956838c1d93d54050ab3e7c1 Mon Sep 17 00:00:00 2001 From: Sebastian Holtermann Date: Mon, 15 May 2017 11:05:58 +0200 Subject: Autogen: Per-config file suffixes. New AUTOGEN_BUILD_DIR target property. Closes #14760 Closes #14313 --- Help/manual/cmake-properties.7.rst | 1 + Help/manual/cmake-qt.7.rst | 23 +- Help/prop_tgt/AUTOGEN_BUILD_DIR.rst | 17 ++ Help/prop_tgt/AUTOMOC.rst | 35 ++- Help/prop_tgt/AUTOUIC.rst | 9 +- Help/release/dev/Autogen_build_dir.rst | 6 + Modules/AutogenInfo.cmake.in | 3 - Source/cmQtAutoGeneratorInitializer.cxx | 376 ++++++++++++++++++++------------ Source/cmQtAutoGenerators.cxx | 142 +++++++----- Source/cmQtAutoGenerators.h | 18 +- Tests/QtAutoUicInterface/CMakeLists.txt | 4 +- 11 files changed, 403 insertions(+), 231 deletions(-) create mode 100644 Help/prop_tgt/AUTOGEN_BUILD_DIR.rst create mode 100644 Help/release/dev/Autogen_build_dir.rst diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 38cc0d8..ec25596 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -119,6 +119,7 @@ Properties on Targets /prop_tgt/ARCHIVE_OUTPUT_DIRECTORY /prop_tgt/ARCHIVE_OUTPUT_NAME_CONFIG /prop_tgt/ARCHIVE_OUTPUT_NAME + /prop_tgt/AUTOGEN_BUILD_DIR /prop_tgt/AUTOGEN_TARGET_DEPENDS /prop_tgt/AUTOMOC_DEPEND_FILTERS /prop_tgt/AUTOMOC_MOC_OPTIONS diff --git a/Help/manual/cmake-qt.7.rst b/Help/manual/cmake-qt.7.rst index 3b95b05..9f3968c 100644 --- a/Help/manual/cmake-qt.7.rst +++ b/Help/manual/cmake-qt.7.rst @@ -68,14 +68,24 @@ be included by the user in the C++ implementation file with a preprocessor ``#include``. Included ``moc_*.cpp`` and ``*.moc`` files will be generated in the -``/_autogen/include`` directory which is +``/include`` directory which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. (This differs from CMake 3.7 and below; see their documentation for details.) +* For multi configuration generators, except Xcode, the include directory is + ``/include_``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. + Not included ``moc_.cpp`` files will be generated in custom folders to avoid name collisions and included in a separate -``/_autogen/moc_compilation.cpp`` -file which is compiled into the target. +``/mocs_compilation.cpp`` file which is compiled +into the target. + +* For multi configuration generators, except Xcode, the file is + ``/mocs_compilation_.cpp``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. The ``moc`` command line will consume the :prop_tgt:`COMPILE_DEFINITIONS` and :prop_tgt:`INCLUDE_DIRECTORIES` target properties from the target it is being @@ -109,10 +119,15 @@ searched for first in the vicinity of including file and afterwards in the optional :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target. The generated generated ``ui_*.h`` files are placed in the -``/_autogen/include`` directory which is +``/include`` directory which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. (This differs from CMake 3.7 and below; see their documentation for details.) +* For multi configuration generators, except Xcode, the include directory is + ``/include_``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. + The :prop_tgt:`AUTOUIC` target property may be pre-set for all following targets by setting the :variable:`CMAKE_AUTOUIC` variable. The :prop_tgt:`AUTOUIC_OPTIONS` target property may be populated to set options diff --git a/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst new file mode 100644 index 0000000..8db6ede --- /dev/null +++ b/Help/prop_tgt/AUTOGEN_BUILD_DIR.rst @@ -0,0 +1,17 @@ +AUTOGEN_BUILD_DIR +----------------- + +Directory where :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC` +generate files for the target. + +The directory is created on demand and automatically added to the +:prop_dir:`ADDITIONAL_MAKE_CLEAN_FILES`. + +When unset or empty the directory ``/_autogen`` is used where +```` is :variable:`CMAKE_CURRENT_BINARY_DIR` and ```` +is :prop_tgt:`NAME`. + +By default :prop_tgt:`AUTOGEN_BUILD_DIR` is unset. + +See the :manual:`cmake-qt(7)` manual for more information on using CMake +with Qt. diff --git a/Help/prop_tgt/AUTOMOC.rst b/Help/prop_tgt/AUTOMOC.rst index 7e10fde..81eff82 100644 --- a/Help/prop_tgt/AUTOMOC.rst +++ b/Help/prop_tgt/AUTOMOC.rst @@ -13,13 +13,17 @@ source files at build time and invoke moc accordingly. * If an ``#include`` statement like ``#include "moc_.cpp"`` is found, the ``Q_OBJECT`` or ``Q_GADGET`` macros are expected in an otherwise empty - line of the ``.h(xx)`` header file. ``moc`` is run on the header file to - generate ``moc_.cpp`` in the - ``/_autogen/include`` directory - which is automatically added to the target's - :prop_tgt:`INCLUDE_DIRECTORIES`. This allows the compiler to find the - included ``moc_.cpp`` file regardless of the location the - original source. + line of the ``.h(xx)`` header file. ``moc`` is run on the header + file to generate ``moc_.cpp`` in the + ``/include`` directory which is automatically added + to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. + This allows the compiler to find the included ``moc_.cpp`` file + regardless of the location the original source. + + * For multi configuration generators, except Xcode, the include directory is + ``/include_``. + + * See :prop_tgt:`AUTOGEN_BUILD_DIR`. * If an ``#include`` statement like ``#include ".moc"`` is found, then ``Q_OBJECT`` or ``Q_GADGET`` macros are expected in the current source @@ -28,10 +32,19 @@ source files at build time and invoke moc accordingly. * Header files that are not included by an ``#include "moc_.cpp"`` statement are nonetheless scanned for ``Q_OBJECT`` or ``Q_GADGET`` macros. The resulting ``moc_.cpp`` files are generated in custom - directories and automatically included in the generated - ``/_autogen/moc_compilation.cpp`` file, - which is compiled as part of the target. The custom directories help to - avoid name collisions for moc files with the same ````. + directories and automatically included in a generated + ``/mocs_compilation.cpp`` file, + which is compiled as part of the target. + + * For multi configuration generators, except Xcode, the file names are + ``moc__.cpp`` and + ``/mocs_compilation_.cpp``. + + * The custom directories with checksum + based names help to avoid name collisions for moc files with the same + ````. + + * See :prop_tgt:`AUTOGEN_BUILD_DIR`. * Additionally, header files with the same base name as a source file, (like ``.h``) or ``_p`` appended to the base name (like diff --git a/Help/prop_tgt/AUTOUIC.rst b/Help/prop_tgt/AUTOUIC.rst index 91d95e5..4a08072 100644 --- a/Help/prop_tgt/AUTOUIC.rst +++ b/Help/prop_tgt/AUTOUIC.rst @@ -14,8 +14,13 @@ and invoke ``uic`` accordingly. If an ``#include`` statement like searched for first in the vicinity of ``source.cpp`` and afterwards in the optional :prop_tgt:`AUTOUIC_SEARCH_PATHS` of the target. ``uic`` is run on the ``foo.ui`` file to generate ``ui_foo.h`` in the directory -``/_autogen/include``, -which is added to the target's :prop_tgt:`INCLUDE_DIRECTORIES` automatically. +``/include``, +which is automatically added to the target's :prop_tgt:`INCLUDE_DIRECTORIES`. + +* For multi configuration generators, except Xcode, the include directory is + ``/include_``. + +* See :prop_tgt:`AUTOGEN_BUILD_DIR`. This property is initialized by the value of the :variable:`CMAKE_AUTOUIC` variable if it is set when a target is created. diff --git a/Help/release/dev/Autogen_build_dir.rst b/Help/release/dev/Autogen_build_dir.rst new file mode 100644 index 0000000..d11c00b --- /dev/null +++ b/Help/release/dev/Autogen_build_dir.rst @@ -0,0 +1,6 @@ +AutoGen build dir +----------------- + +* The new target property :prop_tgt:`AUTOGEN_BUILD_DIR` was introduced which + allows to set a custom output directory for + :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTOUIC` and :prop_tgt:`AUTORCC`. diff --git a/Modules/AutogenInfo.cmake.in b/Modules/AutogenInfo.cmake.in index 9b4941c..4e85474 100644 --- a/Modules/AutogenInfo.cmake.in +++ b/Modules/AutogenInfo.cmake.in @@ -1,6 +1,3 @@ -# Target names -set(AM_TARGET_NAME @_autogen_target_name@) -set(AM_ORIGIN_TARGET_NAME @_origin_target_name@) # Directories and files set(AM_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@/") set(AM_CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/") diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index bc5095d..6b85c66 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -7,6 +7,7 @@ #include "cmCustomCommandLines.h" #include "cmFilePathChecksum.h" #include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" @@ -73,10 +74,13 @@ static std::string GetAutogenTargetFilesDir(cmGeneratorTarget const* target) static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) { - cmMakefile* makefile = target->Target->GetMakefile(); - std::string targetDir = makefile->GetCurrentBinaryDirectory(); - targetDir += "/"; - targetDir += GetAutogenTargetName(target); + std::string targetDir = GetSafeProperty(target, "AUTOGEN_BUILD_DIR"); + if (targetDir.empty()) { + cmMakefile* makefile = target->Target->GetMakefile(); + targetDir = makefile->GetCurrentBinaryDirectory(); + targetDir += "/"; + targetDir += GetAutogenTargetName(target); + } return targetDir; } @@ -150,6 +154,50 @@ static void GetCompileDefinitionsAndDirectories( } } +static bool IsMultiConfig(cmGlobalGenerator* globalGen) +{ + // FIXME: Xcode does not support per-config sources, yet. + // (EXCLUDED_SOURCE_FILE_NAMES) + // Treat it as a single configuration generator meanwhile. + if (globalGen->GetName().find("Xcode") != std::string::npos) { + return false; + } + return globalGen->IsMultiConfig(); +} + +static std::vector GetConfigurations( + cmMakefile* makefile, std::string* config = CM_NULLPTR) +{ + std::vector configs; + { + std::string cfg = makefile->GetConfigurations(configs); + if (config != CM_NULLPTR) { + *config = cfg; + } + } + // Add empty configuration on demand + if (configs.empty()) { + configs.push_back(""); + } + return configs; +} + +static std::vector GetConfigurationSuffixes(cmMakefile* makefile) +{ + std::vector suffixes; + if (IsMultiConfig(makefile->GetGlobalGenerator())) { + makefile->GetConfigurations(suffixes); + for (std::vector::iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + it->insert(0, "_"); + } + } + if (suffixes.empty()) { + suffixes.push_back(""); + } + return suffixes; +} + static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, const std::string& value) { @@ -219,6 +267,17 @@ static bool AddToSourceGroup(cmMakefile* makefile, const std::string& fileName, return true; } +static void AddGeneratedSource(cmMakefile* makefile, + const std::string& filename, + cmQtAutoGeneratorCommon::GeneratorType genType) +{ + cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true); + gFile->SetProperty("GENERATED", "1"); + gFile->SetProperty("SKIP_AUTOGEN", "On"); + + AddToSourceGroup(makefile, filename, genType); +} + static void AcquireScanFiles(cmGeneratorTarget const* target, std::vector& mocUicSources, std::vector& mocUicHeaders, @@ -275,10 +334,11 @@ static void AcquireScanFiles(cmGeneratorTarget const* target, static void MocSetupAutoTarget( cmGeneratorTarget const* target, const std::string& autogenTargetName, - const std::string& qtMajorVersion, + std::string const& qtMajorVersion, std::string const& config, + std::vector const& configs, std::vector const& mocSkipList, - std::map& configIncludes, - std::map& configDefines) + std::map& configMocIncludes, + std::map& configMocDefines) { cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); @@ -300,35 +360,26 @@ static void MocSetupAutoTarget( } // Moc includes and compile definitions { - std::string _moc_incs; - std::string _moc_compile_defs; - std::vector configs; - { - const std::string& config = makefile->GetConfigurations(configs); - GetCompileDefinitionsAndDirectories(target, config, _moc_incs, - _moc_compile_defs); - AddDefinitionEscaped(makefile, "_moc_incs", _moc_incs); - AddDefinitionEscaped(makefile, "_moc_compile_defs", _moc_compile_defs); - } + // Default settings + std::string incs; + std::string compileDefs; + GetCompileDefinitionsAndDirectories(target, config, incs, compileDefs); + AddDefinitionEscaped(makefile, "_moc_incs", incs); + AddDefinitionEscaped(makefile, "_moc_compile_defs", compileDefs); + + // Configuration specific settings for (std::vector::const_iterator li = configs.begin(); li != configs.end(); ++li) { - std::string config_moc_incs; - std::string config_moc_compile_defs; - GetCompileDefinitionsAndDirectories(target, *li, config_moc_incs, - config_moc_compile_defs); - if (config_moc_incs != _moc_incs) { - configIncludes[*li] = - cmOutputConverter::EscapeForCMake(config_moc_incs); - if (_moc_incs.empty()) { - _moc_incs = config_moc_incs; - } + std::string configIncs; + std::string configCompileDefs; + GetCompileDefinitionsAndDirectories(target, *li, configIncs, + configCompileDefs); + if (configIncs != incs) { + configMocIncludes[*li] = cmOutputConverter::EscapeForCMake(configIncs); } - if (config_moc_compile_defs != _moc_compile_defs) { - configDefines[*li] = - cmOutputConverter::EscapeForCMake(config_moc_compile_defs); - if (_moc_compile_defs.empty()) { - _moc_compile_defs = config_moc_compile_defs; - } + if (configCompileDefs != compileDefs) { + configMocDefines[*li] = + cmOutputConverter::EscapeForCMake(configCompileDefs); } } } @@ -374,7 +425,8 @@ static void UicGetOpts(cmGeneratorTarget const* target, } static void UicSetupAutoTarget( - cmGeneratorTarget const* target, const std::string& qtMajorVersion, + cmGeneratorTarget const* target, std::string const& qtMajorVersion, + std::string const& config, std::vector const& configs, std::vector const& uicSkipList, std::map& configUicOptions) { @@ -395,25 +447,21 @@ static void UicSetupAutoTarget( } AddDefinitionEscaped(makefile, "_uic_search_paths", uicSearchPaths); } - // Uic target options { - std::string _uic_opts; - std::vector configs; - UicGetOpts(target, makefile->GetConfigurations(configs), _uic_opts); - - AddDefinitionEscaped(makefile, "_uic_target_options", _uic_opts); + // Default settings + std::string uicOpts; + UicGetOpts(target, config, uicOpts); + AddDefinitionEscaped(makefile, "_uic_target_options", uicOpts); + // Configuration specific settings for (std::vector::const_iterator li = configs.begin(); li != configs.end(); ++li) { - std::string config_uic_opts; - UicGetOpts(target, *li, config_uic_opts); - if (config_uic_opts != _uic_opts) { + std::string configUicOpts; + UicGetOpts(target, *li, configUicOpts); + if (configUicOpts != uicOpts) { configUicOptions[*li] = - cmOutputConverter::EscapeForCMake(config_uic_opts); - if (_uic_opts.empty()) { - _uic_opts = config_uic_opts; - } + cmOutputConverter::EscapeForCMake(configUicOpts); } } } @@ -622,14 +670,24 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenSources( { if (target->GetPropertyAsBool("AUTOMOC")) { cmMakefile* makefile = target->Target->GetMakefile(); - std::string mocCppFile = GetAutogenTargetBuildDir(target); - mocCppFile += "/moc_compilation.cpp"; - { - cmSourceFile* gFile = makefile->GetOrCreateSource(mocCppFile, true); - gFile->SetProperty("SKIP_AUTOGEN", "On"); + const std::vector suffixes = + GetConfigurationSuffixes(makefile); + // Get build directory + const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); + // Register all compilation files as generated + for (std::vector::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string mcFile = autogenBuildDir + "/mocs_compilation"; + mcFile += *it; + mcFile += ".cpp"; + AddGeneratedSource(makefile, mcFile, cmQtAutoGeneratorCommon::MOC); + } + // Mocs compilation file + if (IsMultiConfig(target->GetGlobalGenerator())) { + target->AddSource(autogenBuildDir + "/mocs_compilation_$.cpp"); + } else { + target->AddSource(autogenBuildDir + "/mocs_compilation.cpp"); } - target->AddSource(mocCppFile); - AddToSourceGroup(makefile, mocCppFile, cmQtAutoGeneratorCommon::MOC); } } @@ -642,21 +700,30 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); + const bool multiConfig = IsMultiConfig(target->GetGlobalGenerator()); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); const std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); const std::string qtMajorVersion = GetQtMajorVersion(target); const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); + const std::vector suffixes = GetConfigurationSuffixes(makefile); std::vector autogenDepends; std::vector autogenProvides; + // Remove build directories on cleanup + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + autogenBuildDir.c_str(), false); + // Remove old settings on cleanup { - std::string fname = GetAutogenTargetFilesDir(target); - fname += "/AutogenOldSettings.cmake"; - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), - false); + std::string base = GetAutogenTargetFilesDir(target); + for (std::vector::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string fname = base + "/AutogenOldSettings" + *it + ".cmake"; + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", fname.c_str(), + false); + } } // Compose command lines @@ -697,22 +764,26 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( autogenComment = "Automatic " + tools + " for target " + target->GetName(); } - // Create autogen target build directory and add it to the clean files - cmSystemTools::MakeDirectory(autogenBuildDir); - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - autogenBuildDir.c_str(), false); + // Add moc compilation to generated files list + if (mocEnabled) { + for (std::vector::const_iterator it = suffixes.begin(); + it != suffixes.end(); ++it) { + std::string mcFile = autogenBuildDir + "/mocs_compilation"; + mcFile += *it; + mcFile += ".cpp"; + autogenProvides.push_back(mcFile); + } + } - // Create autogen target includes directory and - // add it to the origin target INCLUDE_DIRECTORIES + // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES if (mocEnabled || uicEnabled) { - const std::string incsDir = autogenBuildDir + "/include"; - cmSystemTools::MakeDirectory(incsDir); - target->AddIncludeDirectory(incsDir, true); - } + if (multiConfig) { + target->AddIncludeDirectory(autogenBuildDir + "/include_$", + true); - // Register moc compilation file as generated - if (mocEnabled) { - autogenProvides.push_back(autogenBuildDir + "/moc_compilation.cpp"); + } else { + target->AddIncludeDirectory(autogenBuildDir + "/include", true); + } } #if defined(_WIN32) && !defined(__CYGWIN__) @@ -783,24 +854,29 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // Compose rcc output file name { - std::string rccOut = autogenBuildDir; - rccOut += "/"; - rccOut += fpathCheckSum.getPart(absFile); - rccOut += "/qrc_"; - rccOut += + std::string rccOutBase = autogenBuildDir + "/"; + rccOutBase += fpathCheckSum.getPart(absFile); + rccOutBase += "/qrc_"; + rccOutBase += cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - rccOut += ".cpp"; - - // Register rcc output file as generated - autogenProvides.push_back(rccOut); + // Register rcc ouput file as generated + for (std::vector::const_iterator it = + suffixes.begin(); + it != suffixes.end(); ++it) { + std::string rccOutCfg = rccOutBase; + rccOutCfg += *it; + rccOutCfg += ".cpp"; + AddGeneratedSource(makefile, rccOutCfg, + cmQtAutoGeneratorCommon::RCC); + autogenProvides.push_back(rccOutCfg); + } // Add rcc output file to origin target sources - { - cmSourceFile* gFile = makefile->GetOrCreateSource(rccOut, true); - gFile->SetProperty("SKIP_AUTOGEN", "On"); + if (multiConfig) { + target->AddSource(rccOutBase + "_$.cpp"); + } else { + target->AddSource(rccOutBase + ".cpp"); } - target->AddSource(rccOut); - AddToSourceGroup(makefile, rccOut, cmQtAutoGeneratorCommon::RCC); } if (PropertyEnabled(sf, "GENERATED")) { @@ -889,9 +965,25 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( cmMakefile::ScopePushPop varScope(makefile); static_cast(varScope); + // Get configurations + std::string config; + const std::vector configs(GetConfigurations(makefile, &config)); + + // Configurations settings buffers + std::map configSuffix; std::map configMocIncludes; std::map configMocDefines; std::map configUicOptions; + + // Configuration suffix + if (IsMultiConfig(target->GetGlobalGenerator())) { + for (std::vector::const_iterator it = configs.begin(); + it != configs.end(); ++it) { + configSuffix[*it] = "_" + *it; + } + } + + // Basic setup { const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); @@ -899,20 +991,21 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( const std::string autogenTargetName = GetAutogenTargetName(target); const std::string qtMajorVersion = GetQtMajorVersion(target); - std::vector _sources; - std::vector _headers; + std::vector sources; + std::vector headers; if (mocEnabled || uicEnabled || rccEnabled) { std::vector mocSkipList; std::vector uicSkipList; - AcquireScanFiles(target, _sources, _headers, mocSkipList, uicSkipList); + AcquireScanFiles(target, sources, headers, mocSkipList, uicSkipList); if (mocEnabled) { - MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, - mocSkipList, configMocIncludes, configMocDefines); + MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, config, + configs, mocSkipList, configMocIncludes, + configMocDefines); } if (uicEnabled) { - UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, - configUicOptions); + UicSetupAutoTarget(target, qtMajorVersion, config, configs, + uicSkipList, configUicOptions); } if (rccEnabled) { RccSetupAutoTarget(target, qtMajorVersion); @@ -921,25 +1014,23 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( AddDefinitionEscaped(makefile, "_autogen_build_dir", GetAutogenTargetBuildDir(target)); - AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); - AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); - AddDefinitionEscaped(makefile, "_sources", _sources); - AddDefinitionEscaped(makefile, "_headers", _headers); + AddDefinitionEscaped(makefile, "_sources", sources); + AddDefinitionEscaped(makefile, "_headers", headers); } - // Generate config file - std::string inputFile = cmSystemTools::GetCMakeRoot(); - inputFile += "/Modules/AutogenInfo.cmake.in"; - std::string outputFile = GetAutogenTargetFilesDir(target); - outputFile += "/AutogenInfo.cmake"; - - makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, - false); + // Generate info file + std::string infoFile = GetAutogenTargetFilesDir(target); + infoFile += "/AutogenInfo.cmake"; + { + std::string inf = cmSystemTools::GetCMakeRoot(); + inf += "/Modules/AutogenInfo.cmake.in"; + makefile->ConfigureFile(inf.c_str(), infoFile.c_str(), false, true, false); + } - // Append custom config definitions to info file - if (!configMocDefines.empty() || !configMocIncludes.empty() || - !configUicOptions.empty()) { + // Append custom definitions to info file on demand + if (!configSuffix.empty() || !configMocDefines.empty() || + !configMocIncludes.empty() || !configUicOptions.empty()) { // Ensure we have write permission in case .in was read-only. mode_t perm = 0; @@ -948,46 +1039,49 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( #else mode_t mode_write = S_IWUSR; #endif - cmSystemTools::GetPermissions(outputFile, perm); + cmSystemTools::GetPermissions(infoFile, perm); if (!(perm & mode_write)) { - cmSystemTools::SetPermissions(outputFile, perm | mode_write); + cmSystemTools::SetPermissions(infoFile, perm | mode_write); } - cmsys::ofstream infoFile(outputFile.c_str(), std::ios::app); - if (!infoFile) { - std::string error = "Internal CMake error when trying to open file: "; - error += outputFile; - error += " for writing."; - cmSystemTools::Error(error.c_str()); - } else { - infoFile << "# Configuration specific options\n"; - if (!configMocDefines.empty()) { - for (std::map::iterator - it = configMocDefines.begin(), - end = configMocDefines.end(); - it != end; ++it) { - infoFile << "set(AM_MOC_DEFINITIONS_" << it->first << " " - << it->second << ")\n"; - } + // Open and write file + cmsys::ofstream ofs(infoFile.c_str(), std::ios::app); + if (ofs) { + ofs << "# Configuration specific options\n"; + for (std::map::iterator + it = configSuffix.begin(), + end = configSuffix.end(); + it != end; ++it) { + ofs << "set(AM_CONFIG_SUFFIX_" << it->first << " " << it->second + << ")\n"; } - if (!configMocIncludes.empty()) { - for (std::map::iterator - it = configMocIncludes.begin(), - end = configMocIncludes.end(); - it != end; ++it) { - infoFile << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second - << ")\n"; - } + for (std::map::iterator + it = configMocDefines.begin(), + end = configMocDefines.end(); + it != end; ++it) { + ofs << "set(AM_MOC_DEFINITIONS_" << it->first << " " << it->second + << ")\n"; } - if (!configUicOptions.empty()) { - for (std::map::iterator - it = configUicOptions.begin(), - end = configUicOptions.end(); - it != end; ++it) { - infoFile << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " - << it->second << ")\n"; - } + for (std::map::iterator + it = configMocIncludes.begin(), + end = configMocIncludes.end(); + it != end; ++it) { + ofs << "set(AM_MOC_INCLUDES_" << it->first << " " << it->second + << ")\n"; + } + for (std::map::iterator + it = configUicOptions.begin(), + end = configUicOptions.end(); + it != end; ++it) { + ofs << "set(AM_UIC_TARGET_OPTIONS_" << it->first << " " << it->second + << ")\n"; } + } else { + // File open error + std::string error = "Internal CMake error when trying to open file: "; + error += cmQtAutoGeneratorCommon::Quoted(infoFile); + error += " for writing."; + cmSystemTools::Error(error.c_str()); } } } diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index 19ae47a..27e4928 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -78,8 +78,8 @@ static void InfoGet(cmMakefile* makefile, const char* key, cmSystemTools::ExpandListArgument(makefile->GetSafeDefinition(key), list); } -static void InfoGet(cmMakefile* makefile, const char* key, - const std::string& config, std::vector& list) +static void InfoGetConfig(cmMakefile* makefile, const char* key, + const std::string& config, std::string& value) { const char* valueConf = CM_NULLPTR; { @@ -93,7 +93,16 @@ static void InfoGet(cmMakefile* makefile, const char* key, if (valueConf == CM_NULLPTR) { valueConf = makefile->GetSafeDefinition(key); } - cmSystemTools::ExpandListArgument(valueConf, list); + value = valueConf; +} + +static void InfoGetConfig(cmMakefile* makefile, const char* key, + const std::string& config, + std::vector& list) +{ + std::string value; + InfoGetConfig(makefile, key, config, value); + cmSystemTools::ExpandListArgument(value, list); } inline static bool SettingsMatch(cmMakefile* makefile, const char* key, @@ -270,6 +279,7 @@ cmQtAutoGenerators::cmQtAutoGenerators() } } + // Moc macro filters this->MocMacroFilters[0].first = "Q_OBJECT"; this->MocMacroFilters[0].second.compile("[\n][ \t]*Q_OBJECT[^a-zA-Z0-9_]"); this->MocMacroFilters[1].first = "Q_GADGET"; @@ -358,12 +368,13 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( { this->SettingsFile = cmSystemTools::CollapseFullPath(targetDirectory); cmSystemTools::ConvertToUnixSlashes(this->SettingsFile); - this->SettingsFile += "/AutogenOldSettings.cmake"; + this->SettingsFile += "/AutogenOldSettings"; + this->SettingsFile += this->ConfigSuffix; + this->SettingsFile += ".cmake"; } - // - Target names - InfoGet(makefile, "AM_TARGET_NAME", this->AutogenTargetName); - InfoGet(makefile, "AM_ORIGIN_TARGET_NAME", this->OriginTargetName); + // -- Meta + InfoGetConfig(makefile, "AM_CONFIG_SUFFIX", config, this->ConfigSuffix); // - Files and directories InfoGet(makefile, "AM_CMAKE_SOURCE_DIR", this->ProjectSourceDir); @@ -373,6 +384,10 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( InfoGet(makefile, "AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", this->IncludeProjectDirsBefore); InfoGet(makefile, "AM_BUILD_DIR", this->AutogenBuildDir); + if (this->AutogenBuildDir.empty()) { + this->LogError("AutoGen: Error: Missing autogen build directory "); + return false; + } InfoGet(makefile, "AM_SOURCES", this->Sources); InfoGet(makefile, "AM_HEADERS", this->Headers); @@ -396,7 +411,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Moc if (this->MocEnabled()) { InfoGet(makefile, "AM_MOC_SKIP", this->MocSkipList); - InfoGet(makefile, "AM_MOC_DEFINITIONS", config, this->MocDefinitions); + InfoGetConfig(makefile, "AM_MOC_DEFINITIONS", config, + this->MocDefinitions); #ifdef _WIN32 { const std::string win32("WIN32"); @@ -405,7 +421,7 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } } #endif - InfoGet(makefile, "AM_MOC_INCLUDES", config, this->MocIncludePaths); + InfoGetConfig(makefile, "AM_MOC_INCLUDES", config, this->MocIncludePaths); InfoGet(makefile, "AM_MOC_OPTIONS", this->MocOptions); InfoGet(makefile, "AM_MOC_RELAXED_MODE", this->MocRelaxedMode); { @@ -440,7 +456,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( if (this->UicEnabled()) { InfoGet(makefile, "AM_UIC_SKIP", this->UicSkipList); InfoGet(makefile, "AM_UIC_SEARCH_PATHS", this->UicSearchPaths); - InfoGet(makefile, "AM_UIC_TARGET_OPTIONS", config, this->UicTargetOptions); + InfoGetConfig(makefile, "AM_UIC_TARGET_OPTIONS", config, + this->UicTargetOptions); { std::vector uicFilesVec; std::vector uicOptionsVec; @@ -616,9 +633,17 @@ bool cmQtAutoGenerators::SettingsFileWrite() void cmQtAutoGenerators::Init(cmMakefile* makefile) { - this->MocCppFilenameRel = "moc_compilation.cpp"; - this->MocCppFilenameAbs = cmSystemTools::CollapseCombinedPath( - this->AutogenBuildDir, this->MocCppFilenameRel); + // Mocs compilation file + this->MocCompFileRel = "mocs_compilation"; + this->MocCompFileRel += this->ConfigSuffix; + this->MocCompFileRel += ".cpp"; + this->MocCompFileAbs = cmSystemTools::CollapseCombinedPath( + this->AutogenBuildDir, this->MocCompFileRel); + + // Mocs include directory + this->AutogenIncludeDir = "include"; + this->AutogenIncludeDir += this->ConfigSuffix; + this->AutogenIncludeDir += "/"; // Moc predefs file if (!this->MocPredefsCmd.empty()) { @@ -697,10 +722,10 @@ bool cmQtAutoGenerators::RunAutogen() // the program goes through all .cpp files to see which moc files are // included. It is not really interesting how the moc file is named, but // what file the moc is created from. Once a moc is included the same moc - // may not be included in the moc_compilation.cpp file anymore. OTOH if - // there's a header containing Q_OBJECT where no corresponding moc file - // is included anywhere a moc_.cpp file is created and included - // in the moc_compilation.cpp file. + // may not be included in the mocs_compilation_$.cpp file anymore. + // OTOH if there's a header containing Q_OBJECT where no corresponding + // moc file is included anywhere a moc_.cpp file is created and + // included in the mocs_compilation_$.cpp file. // key = moc source filepath, value = moc output filepath std::map mocsIncluded; @@ -1105,7 +1130,7 @@ void cmQtAutoGenerators::MocParseHeaderContent( if (this->MocRequired(contentText)) { // Register moc job mocsNotIncluded[absFilename] = - this->ChecksumedPath(absFilename, "moc_", ".cpp"); + this->ChecksumedPath(absFilename, "moc_", this->ConfigSuffix + ".cpp"); this->MocFindDepends(absFilename, contentText, mocDepends); } } @@ -1255,37 +1280,31 @@ bool cmQtAutoGenerators::MocGenerateAll( } // Generate moc files that are included by source files. - { - const std::string subDir = "include/"; - for (std::map::const_iterator it = - mocsIncluded.begin(); - it != mocsIncluded.end(); ++it) { - if (!this->MocGenerateFile(it->first, it->second, subDir, mocDepends)) { - if (this->MocRunFailed) { - return false; - } + for (std::map::const_iterator it = + mocsIncluded.begin(); + it != mocsIncluded.end(); ++it) { + if (!this->MocGenerateFile(it->first, it->second, mocDepends, true)) { + if (this->MocRunFailed) { + return false; } } } // Generate moc files that are _not_ included by source files. bool mocCompFileGenerated = false; - { - const std::string subDir; - for (std::map::const_iterator it = - mocsNotIncluded.begin(); - it != mocsNotIncluded.end(); ++it) { - if (this->MocGenerateFile(it->first, it->second, subDir, mocDepends)) { - mocCompFileGenerated = true; - } else { - if (this->MocRunFailed) { - return false; - } + for (std::map::const_iterator it = + mocsNotIncluded.begin(); + it != mocsNotIncluded.end(); ++it) { + if (this->MocGenerateFile(it->first, it->second, mocDepends, false)) { + mocCompFileGenerated = true; + } else { + if (this->MocRunFailed) { + return false; } } } - // Compose moc_compilation.cpp content + // Compose mocs compilation file content std::string automocSource; { std::ostringstream ost; @@ -1304,18 +1323,18 @@ bool cmQtAutoGenerators::MocGenerateAll( automocSource = ost.str(); } - if (this->FileDiffers(this->MocCppFilenameAbs, automocSource)) { - // Actually write moc_compilation.cpp - this->LogBold("Generating MOC compilation " + this->MocCppFilenameRel); - if (!this->FileWrite("AutoMoc", this->MocCppFilenameAbs, automocSource)) { + if (this->FileDiffers(this->MocCompFileAbs, automocSource)) { + // Actually write mocs compilation file + this->LogBold("Generating MOC compilation " + this->MocCompFileRel); + if (!this->FileWrite("AutoMoc", this->MocCompFileAbs, automocSource)) { return false; } } else if (mocCompFileGenerated) { - // Only touch moc_compilation.cpp + // Only touch mocs compilation file if (this->Verbose) { - this->LogInfo("Touching MOC compilation " + this->MocCppFilenameRel); + this->LogInfo("Touching MOC compilation " + this->MocCompFileRel); } - cmSystemTools::Touch(this->MocCppFilenameAbs, false); + cmSystemTools::Touch(this->MocCompFileAbs, false); } return true; @@ -1326,14 +1345,14 @@ bool cmQtAutoGenerators::MocGenerateAll( */ bool cmQtAutoGenerators::MocGenerateFile( const std::string& sourceFile, const std::string& mocFileName, - const std::string& subDir, - const std::map >& mocDepends) + const std::map >& mocDepends, + bool included) { bool mocGenerated = false; bool generateMoc = this->MocSettingsChanged || this->MocPredefsChanged; const std::string mocFileRel = - cmSystemTools::CollapseCombinedPath(subDir, mocFileName); + included ? (this->AutogenIncludeDir + mocFileName) : mocFileName; const std::string mocFileAbs = cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, mocFileRel); @@ -1523,8 +1542,7 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, bool uicGenerated = false; bool generateUic = this->UicSettingsChanged; - const std::string uicFileRel = - cmSystemTools::CollapseCombinedPath("include", uiOutputFile); + const std::string uicFileRel = this->AutogenIncludeDir + uiOutputFile; const std::string uicFileAbs = cmSystemTools::CollapseCombinedPath(this->AutogenBuildDir, uicFileRel); @@ -1590,11 +1608,17 @@ bool cmQtAutoGenerators::RccGenerateAll() // generate single map with input / output names std::map qrcGenMap; - for (std::vector::const_iterator si = this->RccSources.begin(); - si != this->RccSources.end(); ++si) { - const std::string ext = cmsys::SystemTools::GetFilenameLastExtension(*si); - if (ext == ".qrc") { - qrcGenMap[*si] = this->ChecksumedPath(*si, "qrc_", ".cpp"); + { + const std::string qrcPrefix = "qrc_"; + const std::string qrcSuffix = this->ConfigSuffix + ".cpp"; + for (std::vector::const_iterator si = + this->RccSources.begin(); + si != this->RccSources.end(); ++si) { + const std::string ext = + cmsys::SystemTools::GetFilenameLastExtension(*si); + if (ext == ".qrc") { + qrcGenMap[*si] = this->ChecksumedPath(*si, qrcPrefix, qrcSuffix); + } } } @@ -1827,9 +1851,9 @@ bool cmQtAutoGenerators::NameCollisionTest( * @brief Generates a file path based on the checksum of the source file path * @return The path */ -std::string cmQtAutoGenerators::ChecksumedPath(const std::string& sourceFile, - const char* basePrefix, - const char* baseSuffix) const +std::string cmQtAutoGenerators::ChecksumedPath( + const std::string& sourceFile, const std::string& basePrefix, + const std::string& baseSuffix) const { std::string res = FPathChecksum.getPart(sourceFile); res += "/"; diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 9f329ac..b525364 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -107,8 +107,8 @@ private: const std::map >& mocDepends); bool MocGenerateFile( const std::string& sourceFile, const std::string& mocFileName, - const std::string& subDir, - const std::map >& mocDepends); + const std::map >& mocDepends, + bool included); // -- Uic file generation bool UicFindIncludedFile(std::string& absFile, const std::string& sourceFile, @@ -139,8 +139,8 @@ private: const std::map& genFiles, std::multimap& collisions) const; std::string ChecksumedPath(const std::string& sourceFile, - const char* basePrefix, - const char* baseSuffix) const; + const std::string& basePrefix, + const std::string& baseSuffix) const; bool MakeParentDirectory(const char* logPrefix, const std::string& filename) const; bool FileDiffers(const std::string& filename, const std::string& content); @@ -157,15 +157,15 @@ private: bool MocFindIncludedFile(std::string& absFile, const std::string& sourceFile, const std::string& includeString) const; - // -- Target names - std::string OriginTargetName; - std::string AutogenTargetName; + // -- Meta + std::string ConfigSuffix; // -- Directories std::string ProjectSourceDir; std::string ProjectBinaryDir; std::string CurrentSourceDir; std::string CurrentBinaryDir; std::string AutogenBuildDir; + std::string AutogenIncludeDir; // -- Qt environment std::string QtMajorVersion; std::string MocExecutable; @@ -189,8 +189,8 @@ private: bool MocPredefsChanged; bool MocRelaxedMode; bool MocRunFailed; - std::string MocCppFilenameRel; - std::string MocCppFilenameAbs; + std::string MocCompFileRel; + std::string MocCompFileAbs; std::string MocPredefsFileRel; std::string MocPredefsFileAbs; std::vector MocSkipList; diff --git a/Tests/QtAutoUicInterface/CMakeLists.txt b/Tests/QtAutoUicInterface/CMakeLists.txt index 70175fb..f57c6e7 100644 --- a/Tests/QtAutoUicInterface/CMakeLists.txt +++ b/Tests/QtAutoUicInterface/CMakeLists.txt @@ -64,6 +64,6 @@ target_link_libraries(MyWidget KI18n ${QT_GUI_TARGET}) add_executable(QtAutoUicInterface main.cpp) target_compile_definitions(QtAutoUicInterface PRIVATE - UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/include/ui_libwidget.h" - UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/include/ui_mywidget.h" + UI_LIBWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/LibWidget_autogen/include_${CMAKE_BUILD_TYPE}/ui_libwidget.h" + UI_MYWIDGET_H="${CMAKE_CURRENT_BINARY_DIR}/MyWidget_autogen/include_${CMAKE_BUILD_TYPE}/ui_mywidget.h" ) -- cgit v0.12