/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGeneratorInitializer.h" #include "cmAlgorithms.h" #include "cmCustomCommandLines.h" #include "cmFilePathUuid.h" #include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmOutputConverter.h" #include "cmSourceFile.h" #include "cmSourceFileLocation.h" #include "cmStateTypes.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmake.h" #if defined(_WIN32) && !defined(__CYGWIN__) #include "cmGlobalVisualStudioGenerator.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include static std::string GetAutogenTargetName(cmGeneratorTarget const* target) { std::string autogenTargetName = target->GetName(); autogenTargetName += "_automoc"; return autogenTargetName; } static std::string GetAutogenTargetDir(cmGeneratorTarget const* target) { cmMakefile* makefile = target->Target->GetMakefile(); std::string targetDir = makefile->GetCurrentBinaryDirectory(); targetDir += makefile->GetCMakeInstance()->GetCMakeFilesDirectory(); targetDir += "/"; targetDir += GetAutogenTargetName(target); targetDir += ".dir/"; return targetDir; } static std::string GetAutogenTargetBuildDir(cmGeneratorTarget const* target) { cmMakefile* makefile = target->Target->GetMakefile(); std::string targetDir = makefile->GetCurrentBinaryDirectory(); targetDir += "/"; targetDir += GetAutogenTargetName(target); targetDir += ".dir/"; return targetDir; } static void SetupSourceFiles(cmGeneratorTarget const* target, std::vector& skipMoc, std::vector& mocSources, std::vector& mocHeaders, std::vector& skipUic) { cmMakefile* makefile = target->Target->GetMakefile(); std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); std::vector newRccFiles; cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); bool skipFileForMoc = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); bool generated = cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED")); if (cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC"))) { skipUic.push_back(absFile); } std::string ext = sf->GetExtension(); if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { std::string rcc_output_file = GetAutogenTargetBuildDir(target); // Create output directory cmSystemTools::MakeDirectory(rcc_output_file.c_str()); rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", rcc_output_file.c_str(), false); makefile->GetOrCreateSource(rcc_output_file, true); newRccFiles.push_back(rcc_output_file); } } if (!generated) { if (skipFileForMoc) { skipMoc.push_back(absFile); } else { cmSystemTools::FileFormat fileType = cmSystemTools::GetFileFormat(ext.c_str()); if (fileType == cmSystemTools::CXX_FILE_FORMAT) { mocSources.push_back(absFile); } else if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { mocHeaders.push_back(absFile); } } } } for (std::vector::const_iterator fileIt = newRccFiles.begin(); fileIt != newRccFiles.end(); ++fileIt) { const_cast(target)->AddSource(*fileIt); } } static void GetCompileDefinitionsAndDirectories( cmGeneratorTarget const* target, const std::string& config, std::string& incs, std::string& defs) { std::vector includeDirs; cmLocalGenerator* localGen = target->GetLocalGenerator(); // Get the include dirs for this target, without stripping the implicit // include dirs off, see https://gitlab.kitware.com/cmake/cmake/issues/13667 localGen->GetIncludeDirectories(includeDirs, target, "CXX", config, false); incs = cmJoin(includeDirs, ";"); std::set defines; localGen->AddCompileDefinitions(defines, target, config, "CXX"); defs += cmJoin(defines, ";"); } static void SetupAutoMocTarget( cmGeneratorTarget const* target, const std::string& autogenTargetName, std::vector const& skipMoc, std::vector const& mocHeaders, std::map& configIncludes, std::map& configDefines) { cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); const char* tmp = target->GetProperty("AUTOMOC_MOC_OPTIONS"); std::string _moc_options = (tmp != CM_NULLPTR ? tmp : ""); makefile->AddDefinition( "_moc_options", cmOutputConverter::EscapeForCMake(_moc_options).c_str()); makefile->AddDefinition( "_skip_moc", cmOutputConverter::EscapeForCMake(cmJoin(skipMoc, ";")).c_str()); makefile->AddDefinition( "_moc_headers", cmOutputConverter::EscapeForCMake(cmJoin(mocHeaders, ";")).c_str()); bool relaxedMode = makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE"); makefile->AddDefinition("_moc_relaxed_mode", relaxedMode ? "TRUE" : "FALSE"); 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); makefile->AddDefinition( "_moc_incs", cmOutputConverter::EscapeForCMake(_moc_incs).c_str()); makefile->AddDefinition( "_moc_compile_defs", cmOutputConverter::EscapeForCMake(_moc_compile_defs).c_str()); 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; } } 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; } } } const char* qtVersion = makefile->GetDefinition("_target_qt_version"); if (strcmp(qtVersion, "5") == 0) { cmGeneratorTarget* qt5Moc = lg->FindGeneratorTargetToUse("Qt5::moc"); if (!qt5Moc) { cmSystemTools::Error("Qt5::moc target not found ", autogenTargetName.c_str()); return; } makefile->AddDefinition("_qt_moc_executable", qt5Moc->ImportedGetLocation("")); } else if (strcmp(qtVersion, "4") == 0) { cmGeneratorTarget* qt4Moc = lg->FindGeneratorTargetToUse("Qt4::moc"); if (!qt4Moc) { cmSystemTools::Error("Qt4::moc target not found ", autogenTargetName.c_str()); return; } makefile->AddDefinition("_qt_moc_executable", qt4Moc->ImportedGetLocation("")); } else { cmSystemTools::Error("The CMAKE_AUTOMOC feature supports only Qt 4 and " "Qt 5 ", autogenTargetName.c_str()); } } static void GetUicOpts(cmGeneratorTarget const* target, const std::string& config, std::string& optString) { std::vector opts; target->GetAutoUicOptions(opts, config); optString = cmJoin(opts, ";"); } static void SetupAutoUicTarget( cmGeneratorTarget const* target, std::vector const& skipUic, std::map& configUicOptions) { cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); std::set skipped; skipped.insert(skipUic.begin(), skipUic.end()); makefile->AddDefinition( "_skip_uic", cmOutputConverter::EscapeForCMake(cmJoin(skipUic, ";")).c_str()); std::vector uiFilesWithOptions = makefile->GetQtUiFilesWithOptions(); const char* qtVersion = makefile->GetDefinition("_target_qt_version"); std::string _uic_opts; std::vector configs; const std::string& config = makefile->GetConfigurations(configs); GetUicOpts(target, config, _uic_opts); if (!_uic_opts.empty()) { _uic_opts = cmOutputConverter::EscapeForCMake(_uic_opts); makefile->AddDefinition("_uic_target_options", _uic_opts.c_str()); } for (std::vector::const_iterator li = configs.begin(); li != configs.end(); ++li) { std::string config_uic_opts; GetUicOpts(target, *li, config_uic_opts); if (config_uic_opts != _uic_opts) { configUicOptions[*li] = cmOutputConverter::EscapeForCMake(config_uic_opts); if (_uic_opts.empty()) { _uic_opts = config_uic_opts; } } } std::string uiFileFiles; std::string uiFileOptions; const char* sep = ""; for (std::vector::const_iterator fileIt = uiFilesWithOptions.begin(); fileIt != uiFilesWithOptions.end(); ++fileIt) { cmSourceFile* sf = *fileIt; std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); if (!skipped.insert(absFile).second) { continue; } uiFileFiles += sep; uiFileFiles += absFile; uiFileOptions += sep; std::string opts = sf->GetProperty("AUTOUIC_OPTIONS"); cmSystemTools::ReplaceString(opts, ";", "@list_sep@"); uiFileOptions += opts; sep = ";"; } makefile->AddDefinition( "_qt_uic_options_files", cmOutputConverter::EscapeForCMake(uiFileFiles).c_str()); makefile->AddDefinition( "_qt_uic_options_options", cmOutputConverter::EscapeForCMake(uiFileOptions).c_str()); std::string targetName = target->GetName(); if (strcmp(qtVersion, "5") == 0) { cmGeneratorTarget* qt5Uic = lg->FindGeneratorTargetToUse("Qt5::uic"); if (!qt5Uic) { // Project does not use Qt5Widgets, but has AUTOUIC ON anyway } else { makefile->AddDefinition("_qt_uic_executable", qt5Uic->ImportedGetLocation("")); } } else if (strcmp(qtVersion, "4") == 0) { cmGeneratorTarget* qt4Uic = lg->FindGeneratorTargetToUse("Qt4::uic"); if (!qt4Uic) { cmSystemTools::Error("Qt4::uic target not found ", targetName.c_str()); return; } makefile->AddDefinition("_qt_uic_executable", qt4Uic->ImportedGetLocation("")); } else { cmSystemTools::Error("The CMAKE_AUTOUIC feature supports only Qt 4 and " "Qt 5 ", targetName.c_str()); } } static std::string GetRccExecutable(cmGeneratorTarget const* target) { cmLocalGenerator* lg = target->GetLocalGenerator(); cmMakefile* makefile = target->Target->GetMakefile(); const char* qtVersion = makefile->GetDefinition("_target_qt_version"); if (!qtVersion) { qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR"); if (!qtVersion) { qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); } if (const char* targetQtVersion = target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "")) { qtVersion = targetQtVersion; } } std::string targetName = target->GetName(); if (strcmp(qtVersion, "5") == 0) { cmGeneratorTarget* qt5Rcc = lg->FindGeneratorTargetToUse("Qt5::rcc"); if (!qt5Rcc) { cmSystemTools::Error("Qt5::rcc target not found ", targetName.c_str()); return std::string(); } return qt5Rcc->ImportedGetLocation(""); } if (strcmp(qtVersion, "4") == 0) { cmGeneratorTarget* qt4Rcc = lg->FindGeneratorTargetToUse("Qt4::rcc"); if (!qt4Rcc) { cmSystemTools::Error("Qt4::rcc target not found ", targetName.c_str()); return std::string(); } return qt4Rcc->ImportedGetLocation(""); } cmSystemTools::Error("The CMAKE_AUTORCC feature supports only Qt 4 and " "Qt 5 ", targetName.c_str()); return std::string(); } static void MergeRccOptions(std::vector& opts, const std::vector& fileOpts, bool isQt5) { static const char* valueOptions[] = { "name", "root", "compress", "threshold" }; std::vector extraOpts; for (std::vector::const_iterator it = fileOpts.begin(); it != fileOpts.end(); ++it) { std::vector::iterator existingIt = std::find(opts.begin(), opts.end(), *it); if (existingIt != opts.end()) { const char* o = it->c_str(); if (*o == '-') { ++o; } if (isQt5 && *o == '-') { ++o; } if (std::find_if(cmArrayBegin(valueOptions), cmArrayEnd(valueOptions), cmStrCmp(*it)) != cmArrayEnd(valueOptions)) { assert(existingIt + 1 != opts.end()); *(existingIt + 1) = *(it + 1); ++it; } } else { extraOpts.push_back(*it); } } opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } static void copyTargetProperty(cmTarget* destinationTarget, cmTarget* sourceTarget, const std::string& propertyName) { const char* propertyValue = sourceTarget->GetProperty(propertyName); if (propertyValue) { destinationTarget->SetProperty(propertyName, propertyValue); } } static std::string cmQtAutoGeneratorsStripCR(std::string const& line) { // Strip CR characters rcc may have printed (possibly more than one!). std::string::size_type cr = line.find('\r'); if (cr != line.npos) { return line.substr(0, cr); } return line; } static std::string ReadAll(const std::string& filename) { cmsys::ifstream file(filename.c_str()); std::ostringstream stream; stream << file.rdbuf(); file.close(); return stream.str(); } /// @brief Reads the resource files list from from a .qrc file - Qt5 version /// @return True if the .qrc file was successfully parsed static bool ListQt5RccInputs(cmSourceFile* sf, cmGeneratorTarget const* target, std::vector& depends) { std::string rccCommand = GetRccExecutable(target); bool hasDashDashList = false; // Read rcc features { std::vector command; command.push_back(rccCommand); command.push_back("--help"); std::string rccStdOut; std::string rccStdErr; int retVal = 0; bool result = cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, CM_NULLPTR, cmSystemTools::OUTPUT_NONE); if (result && retVal == 0 && rccStdOut.find("--list") != std::string::npos) { hasDashDashList = true; } } // Run rcc list command std::vector command; command.push_back(rccCommand); command.push_back(hasDashDashList ? "--list" : "-list"); std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); command.push_back(absFile); std::string rccStdOut; std::string rccStdErr; int retVal = 0; bool result = cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, CM_NULLPTR, cmSystemTools::OUTPUT_NONE); if (!result || retVal) { std::ostringstream err; err << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath() << " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl; cmSystemTools::Error(err.str().c_str()); return false; } // Parse rcc list output { std::istringstream ostr(rccStdOut); std::string oline; while (std::getline(ostr, oline)) { oline = cmQtAutoGeneratorsStripCR(oline); if (!oline.empty()) { depends.push_back(oline); } } } { std::istringstream estr(rccStdErr); std::string eline; while (std::getline(estr, eline)) { eline = cmQtAutoGeneratorsStripCR(eline); if (cmHasLiteralPrefix(eline, "RCC: Error in")) { static std::string searchString = "Cannot find file '"; std::string::size_type pos = eline.find(searchString); if (pos == std::string::npos) { std::ostringstream err; err << "AUTOGEN: error: Rcc lists unparsable output " << eline << std::endl; cmSystemTools::Error(err.str().c_str()); return false; } pos += searchString.length(); std::string::size_type sz = eline.size() - pos - 1; depends.push_back(eline.substr(pos, sz)); } } } return true; } /// @brief Reads the resource files list from from a .qrc file - Qt4 version /// @return True if the .qrc file was successfully parsed static bool ListQt4RccInputs(cmSourceFile* sf, std::vector& depends) { const std::string qrcContents = ReadAll(sf->GetFullPath()); cmsys::RegularExpression fileMatchRegex("(]*>)"); fileReplaceRegex.find(qrcEntry); std::string tag = fileReplaceRegex.match(1); qrcEntry = qrcEntry.substr(tag.size()); if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry; } depends.push_back(qrcEntry); } return true; } /// @brief Reads the resource files list from from a .qrc file /// @return True if the rcc file was successfully parsed static bool ListQtRccInputs(const std::string& qtMajorVersion, cmSourceFile* sf, cmGeneratorTarget const* target, std::vector& depends) { if (qtMajorVersion == "5") { return ListQt5RccInputs(sf, target, depends); } return ListQt4RccInputs(sf, depends); } static void SetupAutoRccTarget(cmGeneratorTarget const* target) { std::string _rcc_files; const char* sepRccFiles = ""; cmMakefile* makefile = target->Target->GetMakefile(); std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); std::string qrcInputs; const char* qrcInputsSep = ""; std::string rccFileFiles; std::string rccFileOptions; const char* optionSep = ""; const char* qtVersion = makefile->GetDefinition("_target_qt_version"); std::vector rccOptions; if (const char* opts = target->GetProperty("AUTORCC_OPTIONS")) { cmSystemTools::ExpandListArgument(opts, rccOptions); } std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); if (qtMajorVersion == "") { qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); } for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; std::string ext = sf->GetExtension(); if (ext == "qrc") { std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); bool skip = cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")); if (!skip) { _rcc_files += sepRccFiles; _rcc_files += absFile; sepRccFiles = ";"; if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { std::vector optsVec; cmSystemTools::ExpandListArgument(prop, optsVec); MergeRccOptions(rccOptions, optsVec, strcmp(qtVersion, "5") == 0); } if (!rccOptions.empty()) { rccFileFiles += optionSep; rccFileFiles += absFile; rccFileOptions += optionSep; } const char* listSep = ""; for (std::vector::const_iterator it = rccOptions.begin(); it != rccOptions.end(); ++it) { rccFileOptions += listSep; rccFileOptions += *it; listSep = "@list_sep@"; } optionSep = ";"; std::string entriesList; if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { std::vector depends; if (ListQtRccInputs(qtMajorVersion, sf, target, depends)) { entriesList = cmJoin(depends, "@list_sep@"); } else { return; } } qrcInputs += qrcInputsSep; qrcInputs += entriesList; qrcInputsSep = ";"; } } } makefile->AddDefinition( "_qt_rcc_inputs_" + target->GetName(), cmOutputConverter::EscapeForCMake(qrcInputs).c_str()); makefile->AddDefinition( "_rcc_files", cmOutputConverter::EscapeForCMake(_rcc_files).c_str()); makefile->AddDefinition( "_qt_rcc_options_files", cmOutputConverter::EscapeForCMake(rccFileFiles).c_str()); makefile->AddDefinition( "_qt_rcc_options_options", cmOutputConverter::EscapeForCMake(rccFileOptions).c_str()); makefile->AddDefinition("_qt_rcc_executable", GetRccExecutable(target).c_str()); } void cmQtAutoGeneratorInitializer::InitializeAutogenSources( cmGeneratorTarget* target) { cmMakefile* makefile = target->Target->GetMakefile(); if (target->GetPropertyAsBool("AUTOMOC")) { std::string automocTargetName = GetAutogenTargetName(target); std::string mocCppFile = makefile->GetCurrentBinaryDirectory(); mocCppFile += "/"; mocCppFile += automocTargetName; mocCppFile += ".cpp"; makefile->GetOrCreateSource(mocCppFile, true); makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", mocCppFile.c_str(), false); target->AddSource(mocCppFile); } } void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( cmLocalGenerator* lg, cmGeneratorTarget* target) { cmMakefile* makefile = target->Target->GetMakefile(); std::string qtMajorVersion = makefile->GetSafeDefinition("QT_VERSION_MAJOR"); if (qtMajorVersion == "") { qtMajorVersion = makefile->GetSafeDefinition("Qt5Core_VERSION_MAJOR"); } // create a custom target for running generators at buildtime: std::string autogenTargetName = GetAutogenTargetName(target); std::string targetDir = GetAutogenTargetDir(target); cmCustomCommandLine currentLine; currentLine.push_back(cmSystemTools::GetCMakeCommand()); currentLine.push_back("-E"); currentLine.push_back("cmake_autogen"); currentLine.push_back(targetDir); currentLine.push_back("$"); cmCustomCommandLines commandLines; commandLines.push_back(currentLine); std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); std::vector depends; if (const char* autogenDepends = target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { cmSystemTools::ExpandListArgument(autogenDepends, depends); } std::vector toolNames; if (target->GetPropertyAsBool("AUTOMOC")) { toolNames.push_back("moc"); } if (target->GetPropertyAsBool("AUTOUIC")) { toolNames.push_back("uic"); } if (target->GetPropertyAsBool("AUTORCC")) { toolNames.push_back("rcc"); } std::string tools = toolNames[0]; toolNames.erase(toolNames.begin()); while (toolNames.size() > 1) { tools += ", " + toolNames[0]; toolNames.erase(toolNames.begin()); } if (toolNames.size() == 1) { tools += " and " + toolNames[0]; } std::string autogenComment = "Automatic " + tools + " for target "; autogenComment += target->GetName(); #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; cmGlobalGenerator* gg = lg->GetGlobalGenerator(); if (gg->GetName().find("Visual Studio") != std::string::npos) { cmGlobalVisualStudioGenerator* vsgg = static_cast(gg); // Under VS >= 7 use a PRE_BUILD event instead of a separate target to // reduce the number of targets loaded into the IDE. // This also works around a VS 11 bug that may skip updating the target: // https://connect.microsoft.com/VisualStudio/feedback/details/769495 usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7; if (usePRE_BUILD) { for (std::vector::iterator it = depends.begin(); it != depends.end(); ++it) { if (!makefile->FindTargetToUse(it->c_str())) { usePRE_BUILD = false; break; } } } } #endif std::vector rcc_output; bool const isNinja = lg->GetGlobalGenerator()->GetName() == "Ninja"; if (isNinja #if defined(_WIN32) && !defined(__CYGWIN__) || usePRE_BUILD #endif ) { std::vector srcFiles; target->GetConfigCommonSourceFiles(srcFiles); cmFilePathUuid fpathUuid(makefile); for (std::vector::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); std::string ext = sf->GetExtension(); if (target->GetPropertyAsBool("AUTORCC")) { if (ext == "qrc" && !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { { std::string rcc_output_file = GetAutogenTargetBuildDir(target); // Create output directory cmSystemTools::MakeDirectory(rcc_output_file.c_str()); rcc_output_file += fpathUuid.get(absFile, "qrc_", ".cpp"); rcc_output.push_back(rcc_output_file); } if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { ListQtRccInputs(qtMajorVersion, sf, target, depends); #if defined(_WIN32) && !defined(__CYGWIN__) // Cannot use PRE_BUILD because the resource files themselves // may not be sources within the target so VS may not know the // target needs to re-build at all. usePRE_BUILD = false; #endif } } } } } #if defined(_WIN32) && !defined(__CYGWIN__) if (usePRE_BUILD) { // Add the pre-build command directly to bypass the OBJECT_LIBRARY // rejection in cmMakefile::AddCustomCommandToTarget because we know // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. std::vector no_output; std::vector no_byproducts; cmCustomCommand cc(makefile, no_output, no_byproducts, depends, commandLines, autogenComment.c_str(), workingDirectory.c_str()); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); target->Target->AddPreBuildCommand(cc); } else #endif { cmTarget* autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), /*byproducts=*/rcc_output, depends, commandLines, false, autogenComment.c_str()); cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg); lg->AddGeneratorTarget(gt); // Set target folder const char* autogenFolder = makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); if (!autogenFolder) { autogenFolder = makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); } if (autogenFolder && *autogenFolder) { autogenTarget->SetProperty("FOLDER", autogenFolder); } else { // inherit FOLDER property from target (#13688) copyTargetProperty(gt->Target, target->Target, "FOLDER"); } target->Target->AddUtility(autogenTargetName); } } void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( cmGeneratorTarget const* target) { cmMakefile* makefile = target->Target->GetMakefile(); // forget the variables added here afterwards again: cmMakefile::ScopePushPop varScope(makefile); static_cast(varScope); // create a custom target for running generators at buildtime: std::string autogenTargetName = GetAutogenTargetName(target); makefile->AddDefinition( "_moc_target_name", cmOutputConverter::EscapeForCMake(autogenTargetName).c_str()); makefile->AddDefinition( "_origin_target_name", cmOutputConverter::EscapeForCMake(target->GetName()).c_str()); std::string targetDir = GetAutogenTargetDir(target); const char* qtVersion = makefile->GetDefinition("Qt5Core_VERSION_MAJOR"); if (!qtVersion) { qtVersion = makefile->GetDefinition("QT_VERSION_MAJOR"); } if (const char* targetQtVersion = target->GetLinkInterfaceDependentStringProperty("QT_MAJOR_VERSION", "")) { qtVersion = targetQtVersion; } if (qtVersion) { makefile->AddDefinition("_target_qt_version", qtVersion); } std::vector skipUic; std::vector skipMoc; std::vector mocSources; std::vector mocHeaders; std::map configIncludes; std::map configDefines; std::map configUicOptions; if (target->GetPropertyAsBool("AUTOMOC") || target->GetPropertyAsBool("AUTOUIC") || target->GetPropertyAsBool("AUTORCC")) { SetupSourceFiles(target, skipMoc, mocSources, mocHeaders, skipUic); } makefile->AddDefinition( "_cpp_files", cmOutputConverter::EscapeForCMake(cmJoin(mocSources, ";")).c_str()); if (target->GetPropertyAsBool("AUTOMOC")) { SetupAutoMocTarget(target, autogenTargetName, skipMoc, mocHeaders, configIncludes, configDefines); } if (target->GetPropertyAsBool("AUTOUIC")) { SetupAutoUicTarget(target, skipUic, configUicOptions); } if (target->GetPropertyAsBool("AUTORCC")) { SetupAutoRccTarget(target); } std::string inputFile = cmSystemTools::GetCMakeRoot(); inputFile += "/Modules/AutogenInfo.cmake.in"; std::string outputFile = targetDir; outputFile += "/AutogenInfo.cmake"; makefile->AddDefinition( "_qt_rcc_inputs", makefile->GetDefinition("_qt_rcc_inputs_" + target->GetName())); makefile->ConfigureFile(inputFile.c_str(), outputFile.c_str(), false, true, false); // Ensure we have write permission in case .in was read-only. mode_t perm = 0; #if defined(_WIN32) && !defined(__CYGWIN__) mode_t mode_write = S_IWRITE; #else mode_t mode_write = S_IWUSR; #endif cmSystemTools::GetPermissions(outputFile, perm); if (!(perm & mode_write)) { cmSystemTools::SetPermissions(outputFile, perm | mode_write); } if (!configDefines.empty() || !configIncludes.empty() || !configUicOptions.empty()) { 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()); return; } if (!configDefines.empty()) { for (std::map::iterator it = configDefines.begin(), end = configDefines.end(); it != end; ++it) { infoFile << "set(AM_MOC_COMPILE_DEFINITIONS_" << it->first << " " << it->second << ")\n"; } } if (!configIncludes.empty()) { for (std::map::iterator it = configIncludes.begin(), end = configIncludes.end(); it != end; ++it) { infoFile << "set(AM_MOC_INCLUDES_" << 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"; } } } }