diff options
Diffstat (limited to 'Source')
55 files changed, 1277 insertions, 1074 deletions
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 628cc6f..bfddbc6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1047,6 +1047,9 @@ target_link_libraries(cmake CMakeLib) add_library(CMakeServerLib cmConnection.h cmConnection.cxx cmFileMonitor.cxx cmFileMonitor.h + cmJsonObjectDictionary.h + cmJsonObjects.h + cmJsonObjects.cxx cmPipeConnection.cxx cmPipeConnection.h cmServer.cxx cmServer.h cmServerConnection.cxx cmServerConnection.h diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index ee31122..1f51aa4 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 12) -set(CMake_VERSION_PATCH 20180916) +set(CMake_VERSION_PATCH 20180926) #set(CMake_VERSION_RC 1) diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 8863dc8..667a8ba 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -151,9 +151,9 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(), this->Quiet); } else { - const char* bdir = + std::string const& bdir = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY"); - if (bdir) { + if (!bdir.empty()) { this->CTest->SetCTestConfiguration( "BuildDirectory", cmSystemTools::CollapseFullPath(bdir).c_str(), this->Quiet); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index cbed40e..c7f3f39 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -425,6 +425,29 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, ((url.find('?') == std::string::npos) ? '?' : '&') + "FileName=" + ofile; + cmCTestCurl ctest_curl(this->CTest); + upload_as += "&build="; + upload_as += + ctest_curl.Escape(this->CTest->GetCTestConfiguration("BuildName")); + upload_as += "&site="; + upload_as += + ctest_curl.Escape(this->CTest->GetCTestConfiguration("Site")); + upload_as += "&stamp="; + upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag()); + upload_as += "-"; + upload_as += ctest_curl.Escape(this->CTest->GetTestModelString()); + cmCTestScriptHandler* ch = + static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script")); + cmake* cm = ch->GetCMake(); + if (cm) { + const char* subproject = + cm->GetState()->GetGlobalProperty("SubProject"); + if (subproject) { + upload_as += "&subproject="; + upload_as += ctest_curl.Escape(subproject); + } + } + upload_as += "&MD5="; if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) { diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 2646c9a..7b980a0 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -150,7 +150,7 @@ int main(int argc, char** argv) typedef cmsys::CommandLineArguments argT; arg.AddArgument("-B", argT::CONCAT_ARGUMENT, &binaryDirectory, "Binary Directory"); - arg.AddArgument("-H", argT::CONCAT_ARGUMENT, &sourceDirectory, + arg.AddArgument("-S", argT::CONCAT_ARGUMENT, &sourceDirectory, "Source Directory"); // do not complain about unknown options arg.StoreUnusedArguments(true); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 2107d32..a3e135f 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1725,7 +1725,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, } const char* stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX"); - const char* installPrefix = + std::string const& installPrefix = this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); cmSystemTools::ConvertToUnixSlashes(rootPath); std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath(); diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index 4716e14..6f1afd7 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -36,7 +36,7 @@ bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends) std::string srcLang = "CMAKE_DEPENDS_CHECK_"; srcLang += this->Language; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - const char* srcStr = mf->GetSafeDefinition(srcLang); + std::string const& srcStr = mf->GetSafeDefinition(srcLang); std::vector<std::string> pairs; cmSystemTools::ExpandListArgument(srcStr, pairs); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 67df6fd..d6573b8 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -195,7 +195,7 @@ static bool checkInterfaceDirs(const std::string& prepro, cmGeneratorTarget* target, const std::string& prop) { - const char* installDir = + std::string const& installDir = target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); std::string const& topSourceDir = target->GetLocalGenerator()->GetSourceDirectory(); diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index fbf6560..07a60de 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -666,7 +666,7 @@ std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) pureFortran = true; } - std::string compilerId = mf->GetSafeDefinition(compilerIdVar); + std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar); std::string compiler = "gcc"; // default to gcc if (compilerId == "MSVC") { if (mf->IsDefinitionSet("MSVC10")) { diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index fe5c7bb..28106d1 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -599,7 +599,7 @@ std::string cmExtraCodeLiteGenerator::GetCodeLiteCompilerName( compilerIdVar = "CMAKE_C_COMPILER_ID"; } - std::string compilerId = mf->GetSafeDefinition(compilerIdVar); + std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar); std::string compiler = "gnu g++"; // default to g++ // Since we need the compiler for parsing purposes only diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 16ac88c..f901215 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -580,10 +580,11 @@ struct CompilerIdNode : public cmGeneratorExpressionNode cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { - const char* compilerId = context->LG->GetMakefile()->GetSafeDefinition( - "CMAKE_" + lang + "_COMPILER_ID"); + std::string const& compilerId = + context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + + "_COMPILER_ID"); if (parameters.empty()) { - return compilerId ? compilerId : ""; + return compilerId; } static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$"); if (!compilerIdValidator.find(*parameters.begin())) { @@ -591,15 +592,16 @@ struct CompilerIdNode : public cmGeneratorExpressionNode "Expression syntax not recognized."); return std::string(); } - if (!compilerId) { + if (compilerId.empty()) { return parameters.front().empty() ? "1" : "0"; } - if (strcmp(parameters.begin()->c_str(), compilerId) == 0) { + if (strcmp(parameters.begin()->c_str(), compilerId.c_str()) == 0) { return "1"; } - if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0) { + if (cmsysString_strcasecmp(parameters.begin()->c_str(), + compilerId.c_str()) == 0) { switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) { case cmPolicies::WARN: { std::ostringstream e; @@ -676,11 +678,11 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { - const char* compilerVersion = + std::string const& compilerVersion = context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_VERSION"); if (parameters.empty()) { - return compilerVersion ? compilerVersion : ""; + return compilerVersion; } static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$"); @@ -689,13 +691,13 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode "Expression syntax not recognized."); return std::string(); } - if (!compilerVersion) { + if (compilerVersion.empty()) { return parameters.front().empty() ? "1" : "0"; } return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, parameters.begin()->c_str(), - compilerVersion) + compilerVersion.c_str()) ? "1" : "0"; } @@ -757,17 +759,17 @@ struct PlatformIdNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - const char* platformId = + std::string const& platformId = context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME"); if (parameters.empty()) { - return platformId ? platformId : ""; + return platformId; } - if (!platformId) { + if (platformId.empty()) { return parameters.front().empty() ? "1" : "0"; } - if (strcmp(parameters.begin()->c_str(), platformId) == 0) { + if (*parameters.begin() == platformId) { return "1"; } return "0"; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index efcfaf7..a58d3cb 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -138,8 +138,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg) this->SourceEntries, true); this->DLLPlatform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); this->PolicyMap = t->PolicyMap; } @@ -3496,11 +3495,11 @@ void cmGeneratorTarget::GetFullNameInternal( // if there is no prefix on the target use the cmake definition if (!targetPrefix && prefixVar) { - targetPrefix = this->Makefile->GetSafeDefinition(prefixVar); + targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str(); } // if there is no suffix on the target use the cmake definition if (!targetSuffix && suffixVar) { - targetSuffix = this->Makefile->GetSafeDefinition(suffixVar); + targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str(); } // frameworks have directory prefix but no suffix diff --git a/Source/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index bf464d9..0d4d653 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -65,7 +65,7 @@ bool cmGetDirectoryPropertyCommand::InitialPass( "providing the name of the variable to get."); return false; } - std::string output = dir->GetSafeDefinition(*i); + std::string const& output = dir->GetSafeDefinition(*i); this->Makefile->AddDefinition(variable, output.c_str()); return true; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 24dc593..71e844e 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -828,10 +828,8 @@ void cmGlobalGenerator::EnableLanguage( std::string sharedLibFlagsVar = "CMAKE_SHARED_LIBRARY_"; sharedLibFlagsVar += lang; sharedLibFlagsVar += "_FLAGS"; - const char* sharedLibFlags = mf->GetSafeDefinition(sharedLibFlagsVar); - if (sharedLibFlags) { - this->LanguageToOriginalSharedLibFlags[lang] = sharedLibFlags; - } + this->LanguageToOriginalSharedLibFlags[lang] = + mf->GetSafeDefinition(sharedLibFlagsVar); // Translate compiler ids for compatibility. this->CheckCompilerIdCompatibility(mf, lang); @@ -1092,7 +1090,7 @@ void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l, { std::string extensionsVar = std::string("CMAKE_") + std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS"); - std::string exts = mf->GetSafeDefinition(extensionsVar); + const std::string& exts = mf->GetSafeDefinition(extensionsVar); std::vector<std::string> extensionList; cmSystemTools::ExpandListArgument(exts, extensionList); for (std::string const& i : extensionList) { @@ -1112,7 +1110,7 @@ bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const return this->Makefiles[0]->IsOn(name); } -const char* cmGlobalGenerator::GetSafeGlobalSetting( +std::string cmGlobalGenerator::GetSafeGlobalSetting( std::string const& name) const { assert(!this->Makefiles.empty()); @@ -1596,7 +1594,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() for (std::string const& li : langs) { std::string const standardIncludesVar = "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES"; - std::string const standardIncludesStr = + std::string const& standardIncludesStr = mf->GetSafeDefinition(standardIncludesVar); std::vector<std::string> standardIncludesVec; cmSystemTools::ExpandListArgument(standardIncludesStr, @@ -2456,7 +2454,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( std::string edit_cmd = this->GetEditCacheCommand(); if (!edit_cmd.empty()) { singleLine.push_back(std::move(edit_cmd)); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.Message = "Running CMake cache editor..."; gti.UsesTerminal = true; @@ -2486,7 +2484,7 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache( gti.UsesTerminal = true; cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCMakeCommand()); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.CommandLines.push_back(std::move(singleLine)); targets.push_back(std::move(gti)); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index f240f1d..1ea2d24 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -233,7 +233,7 @@ public: const char* GetGlobalSetting(std::string const& name) const; bool GlobalSettingIsOn(std::string const& name) const; - const char* GetSafeGlobalSetting(std::string const& name) const; + std::string GetSafeGlobalSetting(std::string const& name) const; /** Add a file to the manifest of generated targets for a configuration. */ void AddToManifest(std::string const& f); diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 0c80910..f513403 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -651,13 +651,13 @@ void cmGlobalNinjaGenerator::EnableLanguage( this->ResolveLanguageCompiler(l, mf, optional); } #ifdef _WIN32 - if (strcmp(mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID"), "MSVC") != 0 && - strcmp(mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"), "MSVC") != 0 && + if ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") && + (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") && (mf->IsOn("CMAKE_COMPILER_IS_MINGW") || - strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "Clang") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "Clang") == 0)) { + (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") || + (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") || + (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") || + (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang"))) { this->UsingGCCOnWindows = true; } #endif @@ -1340,7 +1340,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) std::ostringstream cmd; cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL) - << " -H" + << " -S" << lg->ConvertToOutputFormat(lg->GetSourceDirectory(), cmOutputConverter::SHELL) << " -B" diff --git a/Source/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 6eb597c..63e6903 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -111,6 +111,8 @@ public: bool FindMakeProgram(cmMakefile* mf) override; + bool IsIPOSupported() const override { return true; } + static std::string GetInstalledNsightTegraVersion(); cmIDEFlagTable const* GetClFlagTable() const; diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index b0db146..c3ddb3e 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -212,6 +212,12 @@ bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const cmSystemTools::KeyWOW64_32); } +std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion() const +{ + // The last Windows 10 SDK version that VS 2015 can target is 10.0.14393.0. + return "10.0.14393.0"; +} + #if defined(_WIN32) && !defined(__CYGWIN__) struct NoWindowsH { @@ -220,6 +226,20 @@ struct NoWindowsH return !cmSystemTools::FileExists(p + "/um/windows.h", true); } }; +class WindowsSDKTooRecent +{ + std::string const& MaxVersion; + +public: + WindowsSDKTooRecent(std::string const& maxVersion) + : MaxVersion(maxVersion) + { + } + bool operator()(std::string const& v) + { + return cmSystemTools::VersionCompareGreater(v, MaxVersion); + } +}; #endif std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() @@ -276,6 +296,12 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() // Sort the results to make sure we select the most recent one. std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater); + // Skip SDKs that cannot be used with our toolset. + std::string maxVersion = this->GetWindows10SDKMaxVersion(); + if (!maxVersion.empty()) { + cmEraseIf(sdks, WindowsSDKTooRecent(maxVersion)); + } + // Look for a SDK exactly matching the requested target version. for (std::string const& i : sdks) { if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) { diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index 4868df0..9f5bb4e 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -37,6 +37,10 @@ protected: // of the toolset is installed bool IsWindowsStoreToolsetInstalled() const; + // Used to make sure that the Windows 10 SDK selected can work with the + // version of the toolset. + virtual std::string GetWindows10SDKMaxVersion() const; + const char* GetIDEVersion() override { return "14.0"; } virtual bool SelectWindows10SDK(cmMakefile* mf, bool required); diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index 9983a43..23fd2d5 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -258,6 +258,11 @@ bool cmGlobalVisualStudio15Generator::IsWin81SDKInstalled() const return false; } +std::string cmGlobalVisualStudio15Generator::GetWindows10SDKMaxVersion() const +{ + return std::string(); +} + std::string cmGlobalVisualStudio15Generator::FindMSBuildCommand() { std::string msbuild; diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index cdc97ad..8ab63f1 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -52,6 +52,8 @@ protected: // Check for a Win 8 SDK known to the registry or VS installer tool. bool IsWin81SDKInstalled() const; + std::string GetWindows10SDKMaxVersion() const override; + std::string FindMSBuildCommand() override; std::string FindDevEnvCommand() override; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 117d051..ba138c2 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -177,9 +177,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // Create a rule to re-run CMake. cmCustomCommandLine commandLine; commandLine.push_back(cmSystemTools::GetCMakeCommand()); - std::string argH = "-H"; - argH += lg->GetSourceDirectory(); - commandLine.push_back(argH); + std::string argS = "-S"; + argS += lg->GetSourceDirectory(); + commandLine.push_back(argS); std::string argB = "-B"; argB += lg->GetBinaryDirectory(); commandLine.push_back(argB); diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index d7fe777..6e33cf7 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -5,7 +5,6 @@ #include "cmsys/Glob.hxx" #include <sstream> #include <stddef.h> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -350,8 +349,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Check whether this is a DLL platform. bool dll_platform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); for (std::string const& tgt : targetList.GetVector()) { diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h new file mode 100644 index 0000000..a4d41f3 --- /dev/null +++ b/Source/cmJsonObjectDictionary.h @@ -0,0 +1,46 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <string> + +// Vocabulary: + +static const std::string kARTIFACTS_KEY = "artifacts"; +static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; +static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; +static const std::string kCONFIGURATIONS_KEY = "configurations"; +static const std::string kDEFINES_KEY = "defines"; +static const std::string kFILE_GROUPS_KEY = "fileGroups"; +static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; +static const std::string kFULL_NAME_KEY = "fullName"; +static const std::string kINCLUDE_PATH_KEY = "includePath"; +static const std::string kIS_CMAKE_KEY = "isCMake"; +static const std::string kIS_GENERATED_KEY = "isGenerated"; +static const std::string kIS_SYSTEM_KEY = "isSystem"; +static const std::string kIS_TEMPORARY_KEY = "isTemporary"; +static const std::string kKEY_KEY = "key"; +static const std::string kLANGUAGE_KEY = "language"; +static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; +static const std::string kLINK_FLAGS_KEY = "linkFlags"; +static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags"; +static const std::string kLINK_LIBRARIES_KEY = "linkLibraries"; +static const std::string kLINK_PATH_KEY = "linkPath"; +static const std::string kNAME_KEY = "name"; +static const std::string kPATH_KEY = "path"; +static const std::string kPROJECTS_KEY = "projects"; +static const std::string kPROPERTIES_KEY = "properties"; +static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; +static const std::string kSOURCES_KEY = "sources"; +static const std::string kSYSROOT_KEY = "sysroot"; +static const std::string kTARGETS_KEY = "targets"; +static const std::string kTYPE_KEY = "type"; +static const std::string kVALUE_KEY = "value"; +static const std::string kHAS_INSTALL_RULE = "hasInstallRule"; +static const std::string kINSTALL_PATHS = "installPaths"; +static const std::string kCTEST_NAME = "ctestName"; +static const std::string kCTEST_COMMAND = "ctestCommand"; +static const std::string kCTEST_INFO = "ctestInfo"; +static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; +static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; +static const std::string kIS_INTERFACE_SOURCES_KEY = "isInterfaceSources"; diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx new file mode 100644 index 0000000..a7db75f --- /dev/null +++ b/Source/cmJsonObjects.cxx @@ -0,0 +1,823 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmJsonObjects.h" // IWYU pragma: keep + +#include "cmGeneratorExpression.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmInstallGenerator.h" +#include "cmInstallTargetGenerator.h" +#include "cmJsonObjectDictionary.h" +#include "cmJsonObjects.h" +#include "cmLinkLineComputer.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmProperty.h" +#include "cmSourceFile.h" +#include "cmState.h" +#include "cmStateDirectory.h" +#include "cmStateSnapshot.h" +#include "cmStateTypes.h" +#include "cmSystemTools.h" +#include "cmTarget.h" +#include "cmTest.h" +#include "cmake.h" + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <limits> +#include <map> +#include <set> +#include <string> +#include <unordered_map> +#include <utility> +#include <vector> + +namespace { + +std::vector<std::string> getConfigurations(const cmake* cm) +{ + std::vector<std::string> configurations; + auto makefiles = cm->GetGlobalGenerator()->GetMakefiles(); + if (makefiles.empty()) { + return configurations; + } + + makefiles[0]->GetConfigurations(configurations); + if (configurations.empty()) { + configurations.push_back(""); + } + return configurations; +} + +bool hasString(const Json::Value& v, const std::string& s) +{ + return !v.isNull() && + std::any_of(v.begin(), v.end(), + [s](const Json::Value& i) { return i.asString() == s; }); +} + +template <class T> +Json::Value fromStringList(const T& in) +{ + Json::Value result = Json::arrayValue; + for (std::string const& i : in) { + result.append(i); + } + return result; +} + +} // namespace + +void cmGetCMakeInputs(const cmGlobalGenerator* gg, + const std::string& sourceDir, + const std::string& buildDir, + std::vector<std::string>* internalFiles, + std::vector<std::string>* explicitFiles, + std::vector<std::string>* tmpFiles) +{ + const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; + std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles(); + for (cmMakefile const* mf : makefiles) { + for (std::string const& lf : mf->GetListFiles()) { + + const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); + const bool isInternal = (startOfFile == cmakeRootDir); + const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0); + + std::string toAdd = lf; + if (!sourceDir.empty()) { + const std::string& relative = + cmSystemTools::RelativePath(sourceDir, lf); + if (toAdd.size() > relative.size()) { + toAdd = relative; + } + } + + if (isInternal) { + if (internalFiles) { + internalFiles->push_back(std::move(toAdd)); + } + } else { + if (isTemporary) { + if (tmpFiles) { + tmpFiles->push_back(std::move(toAdd)); + } + } else { + if (explicitFiles) { + explicitFiles->push_back(std::move(toAdd)); + } + } + } + } + } +} + +Json::Value cmDumpCMakeInputs(const cmake* cm) +{ + const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); + const std::string& buildDir = cm->GetHomeOutputDirectory(); + const std::string& sourceDir = cm->GetHomeDirectory(); + + std::vector<std::string> internalFiles; + std::vector<std::string> explicitFiles; + std::vector<std::string> tmpFiles; + cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles, + &tmpFiles); + + Json::Value array = Json::arrayValue; + + Json::Value tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = true; + tmp[kIS_TEMPORARY_KEY] = false; + tmp[kSOURCES_KEY] = fromStringList(internalFiles); + array.append(tmp); + + tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = false; + tmp[kIS_TEMPORARY_KEY] = false; + tmp[kSOURCES_KEY] = fromStringList(explicitFiles); + array.append(tmp); + + tmp = Json::objectValue; + tmp[kIS_CMAKE_KEY] = false; + tmp[kIS_TEMPORARY_KEY] = true; + tmp[kSOURCES_KEY] = fromStringList(tmpFiles); + array.append(tmp); + + return array; +} + +const std::string kInterfaceSourcesLanguageDataKey = + "INTERFACE_SOURCES_LD_KEY"; +class LanguageData +{ +public: + bool operator==(const LanguageData& other) const; + + void SetDefines(const std::set<std::string>& defines); + + bool IsGenerated = false; + std::string Language; + std::string Flags; + std::vector<std::string> Defines; + std::vector<std::pair<std::string, bool>> IncludePathList; +}; + +bool LanguageData::operator==(const LanguageData& other) const +{ + return Language == other.Language && Defines == other.Defines && + Flags == other.Flags && IncludePathList == other.IncludePathList && + IsGenerated == other.IsGenerated; +} + +void LanguageData::SetDefines(const std::set<std::string>& defines) +{ + std::vector<std::string> result; + result.reserve(defines.size()); + for (std::string const& i : defines) { + result.push_back(i); + } + std::sort(result.begin(), result.end()); + Defines = std::move(result); +} + +struct FileGroupSources +{ + bool IsInterfaceSources; + std::vector<std::string> Files; +}; + +namespace std { + +template <> +struct hash<LanguageData> +{ + std::size_t operator()(const LanguageData& in) const + { + using std::hash; + size_t result = + hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags); + for (auto const& i : in.IncludePathList) { + result = result ^ + (hash<std::string>()(i.first) ^ + (i.second ? std::numeric_limits<size_t>::max() : 0)); + } + for (auto const& i : in.Defines) { + result = result ^ hash<std::string>()(i); + } + result = + result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0); + return result; + } +}; + +} // namespace std + +static Json::Value DumpSourceFileGroup(const LanguageData& data, + bool isInterfaceSource, + const std::vector<std::string>& files, + const std::string& baseDir) +{ + Json::Value result = Json::objectValue; + + if (isInterfaceSource) { + result[kIS_INTERFACE_SOURCES_KEY] = true; + } + if (!data.Language.empty()) { + result[kLANGUAGE_KEY] = data.Language; + } + if (!data.Flags.empty()) { + result[kCOMPILE_FLAGS_KEY] = data.Flags; + } + if (!data.IncludePathList.empty()) { + Json::Value includes = Json::arrayValue; + for (auto const& i : data.IncludePathList) { + Json::Value tmp = Json::objectValue; + tmp[kPATH_KEY] = i.first; + if (i.second) { + tmp[kIS_SYSTEM_KEY] = i.second; + } + includes.append(tmp); + } + result[kINCLUDE_PATH_KEY] = includes; + } + if (!data.Defines.empty()) { + result[kDEFINES_KEY] = fromStringList(data.Defines); + } + + result[kIS_GENERATED_KEY] = data.IsGenerated; + + Json::Value sourcesValue = Json::arrayValue; + for (auto const& i : files) { + const std::string relPath = cmSystemTools::RelativePath(baseDir, i); + sourcesValue.append(relPath.size() < i.size() ? relPath : i); + } + + result[kSOURCES_KEY] = sourcesValue; + return result; +} + +static void PopulateFileGroupData( + cmGeneratorTarget* target, bool isInterfaceSources, + const std::vector<cmSourceFile*>& files, const std::string& config, + const std::map<std::string, LanguageData>& languageDataMap, + std::unordered_map<LanguageData, FileGroupSources>& fileGroups) +{ + for (cmSourceFile* file : files) { + LanguageData fileData; + fileData.Language = file->GetLanguage(); + if (!fileData.Language.empty() || isInterfaceSources) { + const LanguageData& ld = isInterfaceSources + ? languageDataMap.at(kInterfaceSourcesLanguageDataKey) + : languageDataMap.at(fileData.Language); + cmLocalGenerator* lg = target->GetLocalGenerator(); + cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target, + fileData.Language); + + std::string compileFlags = ld.Flags; + const std::string COMPILE_FLAGS("COMPILE_FLAGS"); + if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) { + lg->AppendFlags(compileFlags, + genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); + } + const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); + if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) { + lg->AppendCompileOptions( + compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); + } + fileData.Flags = compileFlags; + + // Add include directories from source file properties. + std::vector<std::string> includes; + + const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); + if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { + const std::string& evaluatedIncludes = + genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); + lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); + + for (const auto& include : includes) { + // INTERFACE_LIBRARY targets do not support the + // IsSystemIncludeDirectory call so just set it to false. + const bool isSystemInclude = isInterfaceSources + ? false + : target->IsSystemIncludeDirectory(include, config, + fileData.Language); + fileData.IncludePathList.push_back( + std::make_pair(include, isSystemInclude)); + } + } + + fileData.IncludePathList.insert(fileData.IncludePathList.end(), + ld.IncludePathList.begin(), + ld.IncludePathList.end()); + + const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); + std::set<std::string> defines; + if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) { + lg->AppendDefines( + defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS)); + } + + const std::string defPropName = + "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); + if (const char* config_defs = file->GetProperty(defPropName)) { + lg->AppendDefines( + defines, + genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS)); + } + + defines.insert(ld.Defines.begin(), ld.Defines.end()); + + fileData.SetDefines(defines); + } + + fileData.IsGenerated = file->GetPropertyAsBool("GENERATED"); + FileGroupSources& groupFileList = fileGroups[fileData]; + groupFileList.IsInterfaceSources = isInterfaceSources; + groupFileList.Files.push_back(file->GetFullPath()); + } +} + +static Json::Value DumpSourceFilesList( + cmGeneratorTarget* target, const std::string& config, + const std::map<std::string, LanguageData>& languageDataMap) +{ + const cmStateEnums::TargetType type = target->GetType(); + std::unordered_map<LanguageData, FileGroupSources> fileGroups; + + // Collect sourcefile groups: + + std::vector<cmSourceFile*> files; + if (type == cmStateEnums::INTERFACE_LIBRARY) { + // INTERFACE_LIBRARY targets do not create all the data structures + // associated with regular targets. If properties are explicitly specified + // for files in INTERFACE_SOURCES then we can get them through the Makefile + // rather than the target. + files = target->Makefile->GetSourceFiles(); + } else { + target->GetSourceFiles(files, config); + PopulateFileGroupData(target, false /* isInterfaceSources */, files, + config, languageDataMap, fileGroups); + } + + // Collect interface sourcefile groups: + + auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES"); + if (targetProp != nullptr) { + cmGeneratorExpressionInterpreter genexInterpreter( + target->GetLocalGenerator(), config, target); + + auto evaluatedSources = cmsys::SystemTools::SplitString( + genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';'); + + std::map<std::string, cmSourceFile*> filesMap; + for (auto file : files) { + filesMap[file->GetFullPath()] = file; + } + + std::vector<cmSourceFile*> interfaceSourceFiles; + for (const std::string& interfaceSourceFilePath : evaluatedSources) { + auto entry = filesMap.find(interfaceSourceFilePath); + if (entry != filesMap.end()) { + // use what we have since it has all the associated properties + interfaceSourceFiles.push_back(entry->second); + } else { + interfaceSourceFiles.push_back( + new cmSourceFile(target->Makefile, interfaceSourceFilePath)); + } + } + + PopulateFileGroupData(target, true /* isInterfaceSources */, + interfaceSourceFiles, config, languageDataMap, + fileGroups); + } + + const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory(); + Json::Value result = Json::arrayValue; + for (auto const& it : fileGroups) { + Json::Value group = DumpSourceFileGroup( + it.first, it.second.IsInterfaceSources, it.second.Files, baseDir); + if (!group.isNull()) { + result.append(group); + } + } + + return result; +} + +static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo, + const std::string& config) +{ + Json::Value result = Json::objectValue; + result[kCTEST_NAME] = testInfo->GetName(); + + // Concat command entries together. After the first should be the arguments + // for the command + std::string command; + for (auto const& cmd : testInfo->GetCommand()) { + command.append(cmd); + command.append(" "); + } + + // Remove any config specific variables from the output. + cmGeneratorExpression ge; + auto cge = ge.Parse(command); + const std::string& processed = cge->Evaluate(lg, config); + result[kCTEST_COMMAND] = processed; + + // Build up the list of properties that may have been specified + Json::Value properties = Json::arrayValue; + for (auto& prop : testInfo->GetProperties()) { + Json::Value entry = Json::objectValue; + entry[kKEY_KEY] = prop.first; + + // Remove config variables from the value too. + auto cge_value = ge.Parse(prop.second.GetValue()); + const std::string& processed_value = cge_value->Evaluate(lg, config); + entry[kVALUE_KEY] = processed_value; + properties.append(entry); + } + result[kPROPERTIES_KEY] = properties; + + return result; +} + +static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config, + Json::Value* result) +{ + auto mf = lg->GetMakefile(); + std::vector<cmTest*> tests; + mf->GetTests(config, tests); + for (auto test : tests) { + Json::Value tmp = DumpCTestInfo(lg, test, config); + if (!tmp.isNull()) { + result->append(tmp); + } + } +} + +static Json::Value DumpCTestProjectList(const cmake* cm, + std::string const& config) +{ + Json::Value result = Json::arrayValue; + + auto globalGen = cm->GetGlobalGenerator(); + + for (const auto& projectIt : globalGen->GetProjectMap()) { + Json::Value pObj = Json::objectValue; + pObj[kNAME_KEY] = projectIt.first; + + Json::Value tests = Json::arrayValue; + + // Gather tests for every generator + for (const auto& lg : projectIt.second) { + // Make sure they're generated. + lg->GenerateTestFiles(); + DumpMakefileTests(lg, config, &tests); + } + + pObj[kCTEST_INFO] = tests; + + result.append(pObj); + } + + return result; +} + +static Json::Value DumpCTestConfiguration(const cmake* cm, + const std::string& config) +{ + Json::Value result = Json::objectValue; + result[kNAME_KEY] = config; + + result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config); + + return result; +} + +static Json::Value DumpCTestConfigurationsList(const cmake* cm) +{ + Json::Value result = Json::arrayValue; + + for (const std::string& c : getConfigurations(cm)) { + result.append(DumpCTestConfiguration(cm, c)); + } + + return result; +} + +Json::Value cmDumpCTestInfo(const cmake* cm) +{ + Json::Value result = Json::objectValue; + result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm); + return result; +} + +static void GetTargetProperty( + cmGeneratorExpressionInterpreter& genexInterpreter, + cmGeneratorTarget* target, const char* propertyName, + std::vector<std::string>& propertyValue) +{ + auto targetProp = target->Target->GetProperty(propertyName); + if (targetProp != nullptr) { + propertyValue = cmsys::SystemTools::SplitString( + genexInterpreter.Evaluate(targetProp, propertyName), ';'); + } +} + +static void CreateInterfaceSourcesEntry( + cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config, + std::map<std::string, LanguageData>& languageDataMap) +{ + LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey]; + ld.Language = ""; + + cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target); + std::vector<std::string> propertyValue; + GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES", + propertyValue); + for (std::string const& i : propertyValue) { + ld.IncludePathList.push_back( + std::make_pair(i, false /* isSystemInclude */)); + } + + propertyValue.clear(); + GetTargetProperty(genexInterpreter, target, + "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", propertyValue); + for (std::string const& i : propertyValue) { + ld.IncludePathList.push_back( + std::make_pair(i, true /* isSystemInclude */)); + } + + propertyValue.clear(); + GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_OPTIONS", + propertyValue); + for (const auto& s : propertyValue) { + ld.Flags += " " + s; + } + + propertyValue.clear(); + GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_DEFINITIONS", + propertyValue); + if (!propertyValue.empty()) { + std::set<std::string> defines(propertyValue.begin(), propertyValue.end()); + ld.SetDefines(defines); + } +} + +static Json::Value DumpTarget(cmGeneratorTarget* target, + const std::string& config) +{ + cmLocalGenerator* lg = target->GetLocalGenerator(); + const cmState* state = lg->GetState(); + + const cmStateEnums::TargetType type = target->GetType(); + const std::string typeName = state->GetTargetTypeName(type); + + Json::Value ttl = Json::arrayValue; + ttl.append("EXECUTABLE"); + ttl.append("STATIC_LIBRARY"); + ttl.append("SHARED_LIBRARY"); + ttl.append("MODULE_LIBRARY"); + ttl.append("OBJECT_LIBRARY"); + ttl.append("UTILITY"); + ttl.append("INTERFACE_LIBRARY"); + + if (!hasString(ttl, typeName) || target->IsImported()) { + return Json::Value(); + } + + Json::Value result = Json::objectValue; + result[kNAME_KEY] = target->GetName(); + result[kIS_GENERATOR_PROVIDED_KEY] = + target->Target->GetIsGeneratorProvided(); + result[kTYPE_KEY] = typeName; + result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); + result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); + result[kFULL_NAME_KEY] = target->GetFullName(config); + + if (target->Target->GetHaveInstallRule()) { + result[kHAS_INSTALL_RULE] = true; + + Json::Value installPaths = Json::arrayValue; + auto targetGenerators = target->Makefile->GetInstallGenerators(); + for (auto installGenerator : targetGenerators) { + auto installTargetGenerator = + dynamic_cast<cmInstallTargetGenerator*>(installGenerator); + if (installTargetGenerator != nullptr && + installTargetGenerator->GetTarget()->Target == target->Target) { + auto dest = installTargetGenerator->GetDestination(config); + + std::string installPath; + if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) { + installPath = dest; + } else { + std::string installPrefix = + target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); + installPath = installPrefix + '/' + dest; + } + + installPaths.append(installPath); + } + } + + result[kINSTALL_PATHS] = installPaths; + } + + if (target->HaveWellDefinedOutputFiles()) { + Json::Value artifacts = Json::arrayValue; + artifacts.append( + target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact)); + if (target->IsDLLPlatform()) { + artifacts.append( + target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); + const cmGeneratorTarget::OutputInfo* output = + target->GetOutputInfo(config); + if (output && !output->PdbDir.empty()) { + artifacts.append(output->PdbDir + '/' + target->GetPDBName(config)); + } + } + result[kARTIFACTS_KEY] = artifacts; + + result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config); + + std::string linkLibs; + std::string linkFlags; + std::string linkLanguageFlags; + std::string frameworkPath; + std::string linkPath; + cmLinkLineComputer linkLineComputer(lg, + lg->GetStateSnapshot().GetDirectory()); + lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags, + linkFlags, frameworkPath, linkPath, target); + + linkLibs = cmSystemTools::TrimWhitespace(linkLibs); + linkFlags = cmSystemTools::TrimWhitespace(linkFlags); + linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags); + frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath); + linkPath = cmSystemTools::TrimWhitespace(linkPath); + + if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) { + result[kLINK_LIBRARIES_KEY] = linkLibs; + } + if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) { + result[kLINK_FLAGS_KEY] = linkFlags; + } + if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) { + result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags; + } + if (!frameworkPath.empty()) { + result[kFRAMEWORK_PATH_KEY] = frameworkPath; + } + if (!linkPath.empty()) { + result[kLINK_PATH_KEY] = linkPath; + } + const std::string sysroot = + lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT"); + if (!sysroot.empty()) { + result[kSYSROOT_KEY] = sysroot; + } + } + + std::set<std::string> languages; + std::map<std::string, LanguageData> languageDataMap; + if (type == cmStateEnums::INTERFACE_LIBRARY) { + // INTERFACE_LIBRARY targets do not create all the data structures + // associated with regular targets. If properties are explicitly specified + // for files in INTERFACE_SOURCES then we can get them through the Makefile + // rather than the target. + for (auto file : target->Makefile->GetSourceFiles()) { + const std::string& language = file->GetLanguage(); + if (!language.empty()) { + languages.insert(language); + } + } + } else { + target->GetLanguages(languages, config); + } + + for (std::string const& lang : languages) { + LanguageData& ld = languageDataMap[lang]; + ld.Language = lang; + lg->GetTargetCompileFlags(target, config, lang, ld.Flags); + std::set<std::string> defines; + lg->GetTargetDefines(target, config, lang, defines); + ld.SetDefines(defines); + std::vector<std::string> includePathList; + lg->GetIncludeDirectories(includePathList, target, lang, config, true); + for (std::string const& i : includePathList) { + ld.IncludePathList.push_back( + std::make_pair(i, target->IsSystemIncludeDirectory(i, config, lang))); + } + } + + if (target->Target->GetProperty("INTERFACE_SOURCES") != nullptr) { + // Create an entry in the languageDataMap for interface sources. + CreateInterfaceSourcesEntry(lg, target, config, languageDataMap); + } + + Json::Value sourceGroupsValue = + DumpSourceFilesList(target, config, languageDataMap); + if (!sourceGroupsValue.empty()) { + result[kFILE_GROUPS_KEY] = sourceGroupsValue; + } + + return result; +} + +static Json::Value DumpTargetsList( + const std::vector<cmLocalGenerator*>& generators, const std::string& config) +{ + Json::Value result = Json::arrayValue; + + std::vector<cmGeneratorTarget*> targetList; + for (auto const& lgIt : generators) { + const auto& list = lgIt->GetGeneratorTargets(); + targetList.insert(targetList.end(), list.begin(), list.end()); + } + std::sort(targetList.begin(), targetList.end()); + + for (cmGeneratorTarget* target : targetList) { + Json::Value tmp = DumpTarget(target, config); + if (!tmp.isNull()) { + result.append(tmp); + } + } + + return result; +} + +static Json::Value DumpProjectList(const cmake* cm, std::string const& config) +{ + Json::Value result = Json::arrayValue; + + auto globalGen = cm->GetGlobalGenerator(); + + for (auto const& projectIt : globalGen->GetProjectMap()) { + Json::Value pObj = Json::objectValue; + pObj[kNAME_KEY] = projectIt.first; + + // All Projects must have at least one local generator + assert(!projectIt.second.empty()); + const cmLocalGenerator* lg = projectIt.second.at(0); + + // Project structure information: + const cmMakefile* mf = lg->GetMakefile(); + auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); + pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : ""; + pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory(); + pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory(); + pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config); + + // For a project-level install rule it might be defined in any of its + // associated generators. + bool hasInstallRule = false; + for (const auto generator : projectIt.second) { + hasInstallRule = + generator->GetMakefile()->GetInstallGenerators().empty() == false; + + if (hasInstallRule) { + break; + } + } + + pObj[kHAS_INSTALL_RULE] = hasInstallRule; + + result.append(pObj); + } + + return result; +} + +static Json::Value DumpConfiguration(const cmake* cm, + const std::string& config) +{ + Json::Value result = Json::objectValue; + result[kNAME_KEY] = config; + + result[kPROJECTS_KEY] = DumpProjectList(cm, config); + + return result; +} + +static Json::Value DumpConfigurationsList(const cmake* cm) +{ + Json::Value result = Json::arrayValue; + + for (std::string const& c : getConfigurations(cm)) { + result.append(DumpConfiguration(cm, c)); + } + + return result; +} + +Json::Value cmDumpCodeModel(const cmake* cm) +{ + Json::Value result = Json::objectValue; + result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm); + return result; +} diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h new file mode 100644 index 0000000..cd4da94 --- /dev/null +++ b/Source/cmJsonObjects.h @@ -0,0 +1,27 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmJsonObjects_h +#define cmJsonObjects_h + +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cm_jsoncpp_value.h" + +#include <string> +#include <vector> + +class cmake; +class cmGlobalGenerator; + +extern void cmGetCMakeInputs(const cmGlobalGenerator* gg, + const std::string& sourceDir, + const std::string& buildDir, + std::vector<std::string>* internalFiles, + std::vector<std::string>* explicitFiles, + std::vector<std::string>* tmpFiles); + +extern Json::Value cmDumpCodeModel(const cmake* cm); +extern Json::Value cmDumpCTestInfo(const cmake* cm); +extern Json::Value cmDumpCMakeInputs(const cmake* cm); + +#endif diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index b468257..e465e1a 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -11,6 +11,7 @@ #include <algorithm> #include <assert.h> +#include <memory> #include <sstream> cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=( @@ -285,91 +286,66 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token, return true; } -struct cmListFileBacktrace::Entry : public cmListFileContext +// We hold either the bottom scope of a directory or a call/file context. +// Discriminate these cases via the parent pointer. +struct cmListFileBacktrace::Entry { - Entry(cmListFileContext const& lfc, Entry* up) - : cmListFileContext(lfc) - , Up(up) - , RefCount(0) + Entry(cmStateSnapshot bottom) + : Bottom(bottom) { - if (this->Up) { - this->Up->Ref(); - } } - ~Entry() + + Entry(std::shared_ptr<Entry const> parent, cmListFileContext lfc) + : Context(std::move(lfc)) + , Parent(std::move(parent)) { - if (this->Up) { - this->Up->Unref(); - } } - void Ref() { ++this->RefCount; } - void Unref() + + ~Entry() { - if (--this->RefCount == 0) { - delete this; + if (this->Parent) { + this->Context.~cmListFileContext(); + } else { + this->Bottom.~cmStateSnapshot(); } } - Entry* Up; - unsigned int RefCount; -}; -cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& bottom, - Entry* up, - cmListFileContext const& lfc) - : Bottom(bottom) - , Cur(new Entry(lfc, up)) -{ - assert(this->Bottom.IsValid()); - this->Cur->Ref(); -} - -cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& bottom, - Entry* cur) - : Bottom(bottom) - , Cur(cur) -{ - if (this->Cur) { - assert(this->Bottom.IsValid()); - this->Cur->Ref(); - } -} + bool IsBottom() const { return !this->Parent; } -cmListFileBacktrace::cmListFileBacktrace() - : Bottom() - , Cur(nullptr) -{ -} + union + { + cmStateSnapshot Bottom; + cmListFileContext Context; + }; + std::shared_ptr<Entry const> Parent; +}; cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& snapshot) - : Bottom(snapshot.GetCallStackBottom()) - , Cur(nullptr) + : TopEntry(std::make_shared<Entry const>(snapshot.GetCallStackBottom())) { } -cmListFileBacktrace::cmListFileBacktrace(cmListFileBacktrace const& r) - : Bottom(r.Bottom) - , Cur(r.Cur) +cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> parent, + cmListFileContext const& lfc) + : TopEntry(std::make_shared<Entry const>(std::move(parent), lfc)) { - if (this->Cur) { - assert(this->Bottom.IsValid()); - this->Cur->Ref(); - } } -cmListFileBacktrace& cmListFileBacktrace::operator=( - cmListFileBacktrace const& r) +cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> top) + : TopEntry(std::move(top)) { - cmListFileBacktrace tmp(r); - std::swap(this->Cur, tmp.Cur); - std::swap(this->Bottom, tmp.Bottom); - return *this; } -cmListFileBacktrace::~cmListFileBacktrace() +cmStateSnapshot cmListFileBacktrace::GetBottom() const { - if (this->Cur) { - this->Cur->Unref(); + cmStateSnapshot bottom; + if (Entry const* cur = this->TopEntry.get()) { + while (Entry const* parent = cur->Parent.get()) { + cur = parent; + } + bottom = cur->Bottom; } + return bottom; } cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const @@ -380,54 +356,61 @@ cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const // skipped during call stack printing. cmListFileContext lfc; lfc.FilePath = file; - return cmListFileBacktrace(this->Bottom, this->Cur, lfc); + return this->Push(lfc); } cmListFileBacktrace cmListFileBacktrace::Push( cmListFileContext const& lfc) const { - return cmListFileBacktrace(this->Bottom, this->Cur, lfc); + assert(this->TopEntry); + assert(!this->TopEntry->IsBottom() || this->TopEntry->Bottom.IsValid()); + return cmListFileBacktrace(this->TopEntry, lfc); } cmListFileBacktrace cmListFileBacktrace::Pop() const { - assert(this->Cur); - return cmListFileBacktrace(this->Bottom, this->Cur->Up); + assert(this->TopEntry); + assert(!this->TopEntry->IsBottom()); + return cmListFileBacktrace(this->TopEntry->Parent); } cmListFileContext const& cmListFileBacktrace::Top() const { - if (this->Cur) { - return *this->Cur; - } - static cmListFileContext const empty; - return empty; + assert(this->TopEntry); + return this->TopEntry->Context; } void cmListFileBacktrace::PrintTitle(std::ostream& out) const { - if (!this->Cur) { + // The title exists only if we have a call on top of the bottom. + if (!this->TopEntry || this->TopEntry->IsBottom()) { return; } - cmOutputConverter converter(this->Bottom); - cmListFileContext lfc = *this->Cur; - if (!this->Bottom.GetState()->GetIsInTryCompile()) { + cmListFileContext lfc = this->TopEntry->Context; + cmStateSnapshot bottom = this->GetBottom(); + cmOutputConverter converter(bottom); + if (!bottom.GetState()->GetIsInTryCompile()) { lfc.FilePath = converter.ConvertToRelativePath( - this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath); + bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } out << (lfc.Line ? " at " : " in ") << lfc; } void cmListFileBacktrace::PrintCallStack(std::ostream& out) const { - if (!this->Cur || !this->Cur->Up) { + // The call stack exists only if we have at least two calls on top + // of the bottom. + if (!this->TopEntry || this->TopEntry->IsBottom() || + this->TopEntry->Parent->IsBottom()) { return; } bool first = true; - cmOutputConverter converter(this->Bottom); - for (Entry* i = this->Cur->Up; i; i = i->Up) { - if (i->Name.empty()) { + cmStateSnapshot bottom = this->GetBottom(); + cmOutputConverter converter(bottom); + for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom(); + cur = cur->Parent.get()) { + if (cur->Context.Name.empty()) { // Skip this whole-file scope. When we get here we already will // have printed a more-specific context within the file. continue; @@ -436,10 +419,10 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const first = false; out << "Call Stack (most recent call first):\n"; } - cmListFileContext lfc = *i; - if (!this->Bottom.GetState()->GetIsInTryCompile()) { + cmListFileContext lfc = cur->Context; + if (!bottom.GetState()->GetIsInTryCompile()) { lfc.FilePath = converter.ConvertToRelativePath( - this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath); + bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } out << " " << lfc << "\n"; } @@ -448,16 +431,19 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const size_t cmListFileBacktrace::Depth() const { size_t depth = 0; - if (this->Cur == nullptr) { - return 0; - } - - for (Entry* i = this->Cur->Up; i; i = i->Up) { - depth++; + if (Entry const* cur = this->TopEntry.get()) { + for (; !cur->IsBottom(); cur = cur->Parent.get()) { + ++depth; + } } return depth; } +bool cmListFileBacktrace::Empty() const +{ + return !this->TopEntry || this->TopEntry->IsBottom(); +} + std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc) { os << lfc.FilePath; diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h index 70f7166..2c91f7a 100644 --- a/Source/cmListFileCache.h +++ b/Source/cmListFileCache.h @@ -6,6 +6,7 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <iosfwd> +#include <memory> // IWYU pragma: keep #include <stddef.h> #include <string> #include <vector> @@ -115,18 +116,20 @@ public: // Default-constructed backtrace may not be used until after // set via assignment from a backtrace constructed with a // valid snapshot. - cmListFileBacktrace(); + cmListFileBacktrace() = default; // Construct an empty backtrace whose bottom sits in the directory // indicated by the given valid snapshot. cmListFileBacktrace(cmStateSnapshot const& snapshot); - // Backtraces may be copied and assigned as values. - cmListFileBacktrace(cmListFileBacktrace const& r); - cmListFileBacktrace& operator=(cmListFileBacktrace const& r); - ~cmListFileBacktrace(); + // Backtraces may be copied, moved, and assigned as values. + cmListFileBacktrace(cmListFileBacktrace const&) = default; + cmListFileBacktrace(cmListFileBacktrace&&) noexcept = default; + cmListFileBacktrace& operator=(cmListFileBacktrace const&) = default; + cmListFileBacktrace& operator=(cmListFileBacktrace&&) noexcept = default; + ~cmListFileBacktrace() = default; - cmStateSnapshot GetBottom() const { return this->Bottom; } + cmStateSnapshot GetBottom() const; // Get a backtrace with the given file scope added to the top. // May not be called until after construction with a valid snapshot. @@ -153,14 +156,15 @@ public: // Get the number of 'frames' in this backtrace size_t Depth() const; + // Return true if this backtrace is empty. + bool Empty() const; + private: struct Entry; - - cmStateSnapshot Bottom; - Entry* Cur; - cmListFileBacktrace(cmStateSnapshot const& bottom, Entry* up, + std::shared_ptr<Entry const> TopEntry; + cmListFileBacktrace(std::shared_ptr<Entry const> parent, cmListFileContext const& lfc); - cmListFileBacktrace(cmStateSnapshot const& bottom, Entry* cur); + cmListFileBacktrace(std::shared_ptr<Entry const> top); }; struct cmListFile diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4f8f2e7..7030725 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -683,7 +683,7 @@ std::string cmLocalGenerator::GetIncludeFlags( std::string flagVar = "CMAKE_INCLUDE_FLAG_"; flagVar += lang; - const char* includeFlag = this->Makefile->GetSafeDefinition(flagVar); + std::string const& includeFlag = this->Makefile->GetSafeDefinition(flagVar); flagVar = "CMAKE_INCLUDE_FLAG_SEP_"; flagVar += lang; const char* sep = this->Makefile->GetDefinition(flagVar); @@ -1824,9 +1824,9 @@ bool cmLocalGenerator::GetShouldUseOldFlags(bool shared, std::string flagsVar = "CMAKE_SHARED_LIBRARY_"; flagsVar += lang; flagsVar += "_FLAGS"; - const char* flags = this->Makefile->GetSafeDefinition(flagsVar); + std::string const& flags = this->Makefile->GetSafeDefinition(flagsVar); - if (flags && flags != originalFlags) { + if (flags != originalFlags) { switch (this->GetPolicyStatus(cmPolicies::CMP0018)) { case cmPolicies::WARN: { std::ostringstream e; @@ -1859,7 +1859,7 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, std::string const& lang, int targetType) { - const char* picFlags = nullptr; + std::string picFlags; if (targetType == cmStateEnums::EXECUTABLE) { std::string flagsVar = "CMAKE_"; @@ -1867,13 +1867,13 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, flagsVar += "_COMPILE_OPTIONS_PIE"; picFlags = this->Makefile->GetSafeDefinition(flagsVar); } - if (!picFlags) { + if (picFlags.empty()) { std::string flagsVar = "CMAKE_"; flagsVar += lang; flagsVar += "_COMPILE_OPTIONS_PIC"; picFlags = this->Makefile->GetSafeDefinition(flagsVar); } - if (picFlags) { + if (!picFlags.empty()) { std::vector<std::string> options; cmSystemTools::ExpandListArgument(picFlags, options); for (std::string const& o : options) { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 690b827..4d19b3a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -773,7 +773,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); cmakefileName += "Makefile.cmake"; std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; runRule += this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); @@ -1422,7 +1422,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( this->WriteDisclaimer(internalRuleFileStream); // for each language we need to scan, scan it - const char* langStr = mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"); + std::string const& langStr = + mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"); std::vector<std::string> langs; cmSystemTools::ExpandListArgument(langStr, langs); for (std::string const& lang : langs) { @@ -1682,7 +1683,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( cmakefileName += "Makefile.cmake"; { std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; runRule += this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index c05b085..8428672 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -260,7 +260,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() std::string comment = "Building Custom Rule "; comment += makefileIn; std::string args; - args = "-H"; + args = "-S"; args += this->GetSourceDirectory(); commandLine.push_back(args); args = "-B"; @@ -1082,7 +1082,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( // Use the NOINHERIT macro to avoid getting VS project default // libraries which may be set by the user to something bad. fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) " - << this->Makefile->GetSafeDefinition(standardLibsVar.c_str()); + << this->Makefile->GetSafeDefinition(standardLibsVar); if (this->FortranProject) { this->Internal->OutputObjects(fout, target, configName, " "); } @@ -1167,7 +1167,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( // Use the NOINHERIT macro to avoid getting VS project default // libraries which may be set by the user to something bad. fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) " - << this->Makefile->GetSafeDefinition(standardLibsVar.c_str()); + << this->Makefile->GetSafeDefinition(standardLibsVar); if (this->FortranProject) { this->Internal->OutputObjects(fout, target, configName, " "); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index fdcf0a8..354da4e 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -2401,7 +2401,7 @@ bool cmMakefile::IsDefinitionSet(const std::string& name) const return def != nullptr; } -const char* cmMakefile::GetDefinition(const std::string& name) const +const std::string* cmMakefile::GetDef(const std::string& name) const { const std::string* def = this->StateSnapshot.GetDefinition(name); if (!def) { @@ -2427,16 +2427,26 @@ const char* cmMakefile::GetDefinition(const std::string& name) const } } #endif - return (def ? def->c_str() : nullptr); + return def; } -const char* cmMakefile::GetSafeDefinition(const std::string& def) const +const char* cmMakefile::GetDefinition(const std::string& name) const { - const char* ret = this->GetDefinition(def); - if (!ret) { - return ""; + const std::string* def = GetDef(name); + if (!def) { + return nullptr; } - return ret; + return def->c_str(); +} + +const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const +{ + static std::string const empty; + const std::string* def = GetDef(name); + if (!def) { + return empty; + } + return *def; } std::vector<std::string> cmMakefile::GetDefinitions() const @@ -4184,7 +4194,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0054) { + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0063) { this->IssueMessage(cmake::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 54730b5..bb01c0b 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -432,7 +432,8 @@ public: * cache is then queried. */ const char* GetDefinition(const std::string&) const; - const char* GetSafeDefinition(const std::string&) const; + const std::string* GetDef(const std::string&) const; + const std::string& GetSafeDefinition(const std::string&) const; std::string GetRequiredDefinition(const std::string& name) const; bool IsDefinitionSet(const std::string&) const; /** diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index ebcc501..7ac8d1b 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -10,7 +10,6 @@ #include <map> #include <memory> // IWYU pragma: keep #include <sstream> -#include <string.h> #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" @@ -174,9 +173,8 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const { - return strcmp(this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" + - lang), - "msvc") == 0; + return (this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" + + lang) == "msvc"); } // TODO: Refactor with diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index ba50fb8..5caea7d 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -135,7 +135,7 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy, cmPolicies::PolicyStatus* defaultSetting) { std::string defaultVar = "CMAKE_POLICY_DEFAULT_" + policy; - std::string defaultValue = mf->GetSafeDefinition(defaultVar); + std::string const& defaultValue = mf->GetSafeDefinition(defaultVar); if (defaultValue == "NEW") { *defaultSetting = cmPolicies::NEW; } else if (defaultValue == "OLD") { diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 4ffe803..f99cc0f 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -234,7 +234,10 @@ class cmMakefile; SELECT( \ POLICY, CMP0079, \ "target_link_libraries allows use with targets in other directories.", 3, \ - 13, 0, cmPolicies::WARN) + 13, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0080, \ + "BundleUtilities cannot be included at configure time", 3, 13, 0, \ + cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) #define CM_FOR_EACH_POLICY_ID(POLICY) \ diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 8bd985a..8a202a2 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1126,7 +1126,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } }; auto MfDef = [makefile](const char* key) { - return std::string(makefile->GetSafeDefinition(key)); + return makefile->GetSafeDefinition(key); }; // Write diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index c364700..2e6f90f 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1204,7 +1204,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { - valueConf = makefile->GetSafeDefinition(key); + return makefile->GetSafeDefinition(key); } return std::string(valueConf); }; @@ -1226,7 +1226,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG"); { unsigned long num = Base_.NumThreads; - if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL"), &num)) { + if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) { num = std::max<unsigned long>(num, 1); num = std::min<unsigned long>(num, ParallelMax); Base_.NumThreads = static_cast<unsigned int>(num); @@ -1264,7 +1264,8 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) // - Qt environment { unsigned long qtv = Base_.QtVersionMajor; - if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), &qtv)) { + if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(), + &qtv)) { Base_.QtVersionMajor = static_cast<unsigned int>(qtv); } } diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 6caa0d8..65c6741 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -52,7 +52,7 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { - valueConf = makefile->GetSafeDefinition(key); + return makefile->GetSafeDefinition(key); } return std::string(valueConf); }; diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx index 1b04ca2..f15a14a 100644 --- a/Source/cmServer.cxx +++ b/Source/cmServer.cxx @@ -5,6 +5,7 @@ #include "cmAlgorithms.h" #include "cmConnection.h" #include "cmFileMonitor.h" +#include "cmJsonObjectDictionary.h" #include "cmServerDictionary.h" #include "cmServerProtocol.h" #include "cmSystemTools.h" diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h index ebf16eb..961e4b7 100644 --- a/Source/cmServerDictionary.h +++ b/Source/cmServerDictionary.h @@ -25,78 +25,40 @@ static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings"; static const std::string kSIGNAL_TYPE = "signal"; static const std::string kCTEST_INFO_TYPE = "ctestInfo"; -static const std::string kARTIFACTS_KEY = "artifacts"; -static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; static const std::string kBUILD_FILES_KEY = "buildFiles"; static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments"; static const std::string kCACHE_KEY = "cache"; static const std::string kCAPABILITIES_KEY = "capabilities"; static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars"; static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory"; -static const std::string kCOMPILE_FLAGS_KEY = "compileFlags"; -static const std::string kCONFIGURATIONS_KEY = "configurations"; static const std::string kCOOKIE_KEY = "cookie"; static const std::string kDEBUG_OUTPUT_KEY = "debugOutput"; -static const std::string kDEFINES_KEY = "defines"; static const std::string kERROR_MESSAGE_KEY = "errorMessage"; static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; -static const std::string kFILE_GROUPS_KEY = "fileGroups"; -static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath"; -static const std::string kFULL_NAME_KEY = "fullName"; static const std::string kGENERATOR_KEY = "generator"; -static const std::string kINCLUDE_PATH_KEY = "includePath"; -static const std::string kIS_CMAKE_KEY = "isCMake"; static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental"; -static const std::string kIS_GENERATED_KEY = "isGenerated"; -static const std::string kIS_SYSTEM_KEY = "isSystem"; -static const std::string kIS_TEMPORARY_KEY = "isTemporary"; -static const std::string kKEY_KEY = "key"; static const std::string kKEYS_KEY = "keys"; -static const std::string kLANGUAGE_KEY = "language"; -static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage"; -static const std::string kLINK_FLAGS_KEY = "linkFlags"; -static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags"; -static const std::string kLINK_LIBRARIES_KEY = "linkLibraries"; -static const std::string kLINK_PATH_KEY = "linkPath"; static const std::string kMAJOR_KEY = "major"; static const std::string kMESSAGE_KEY = "message"; static const std::string kMINOR_KEY = "minor"; -static const std::string kNAME_KEY = "name"; -static const std::string kPATH_KEY = "path"; static const std::string kPLATFORM_KEY = "platform"; static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent"; static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum"; static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage"; static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum"; -static const std::string kPROJECTS_KEY = "projects"; -static const std::string kPROPERTIES_KEY = "properties"; static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion"; static const std::string kREPLY_TO_KEY = "inReplyTo"; -static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; -static const std::string kSOURCES_KEY = "sources"; static const std::string kSUPPORTED_PROTOCOL_VERSIONS = "supportedProtocolVersions"; -static const std::string kSYSROOT_KEY = "sysroot"; -static const std::string kTARGETS_KEY = "targets"; static const std::string kTITLE_KEY = "title"; static const std::string kTOOLSET_KEY = "toolset"; static const std::string kTRACE_EXPAND_KEY = "traceExpand"; static const std::string kTRACE_KEY = "trace"; -static const std::string kTYPE_KEY = "type"; -static const std::string kVALUE_KEY = "value"; static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized"; static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli"; static const std::string kWARN_UNUSED_KEY = "warnUnused"; static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories"; static const std::string kWATCHED_FILES_KEY = "watchedFiles"; -static const std::string kHAS_INSTALL_RULE = "hasInstallRule"; -static const std::string kINSTALL_PATHS = "installPaths"; -static const std::string kCTEST_NAME = "ctestName"; -static const std::string kCTEST_COMMAND = "ctestCommand"; -static const std::string kCTEST_INFO = "ctestInfo"; -static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion"; -static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided"; -static const std::string kIS_INTERFACE_SOURCES_KEY = "isInterfaceSources"; static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==["; static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]"; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx index 2cad657..f75a5ce 100644 --- a/Source/cmServerProtocol.cxx +++ b/Source/cmServerProtocol.cxx @@ -5,38 +5,21 @@ #include "cmAlgorithms.h" #include "cmExternalMakefileProjectGenerator.h" #include "cmFileMonitor.h" -#include "cmGeneratorExpression.h" -#include "cmGeneratorTarget.h" #include "cmGlobalGenerator.h" -#include "cmInstallGenerator.h" -#include "cmInstallTargetGenerator.h" -#include "cmLinkLineComputer.h" -#include "cmLocalGenerator.h" -#include "cmMakefile.h" -#include "cmProperty.h" +#include "cmJsonObjectDictionary.h" +#include "cmJsonObjects.h" #include "cmServer.h" #include "cmServerDictionary.h" -#include "cmSourceFile.h" #include "cmState.h" -#include "cmStateDirectory.h" -#include "cmStateSnapshot.h" -#include "cmStateTypes.h" #include "cmSystemTools.h" -#include "cmTarget.h" -#include "cmTest.h" #include "cm_uv.h" #include "cmake.h" #include <algorithm> #include <cassert> -#include <cstddef> #include <functional> -#include <limits> -#include <map> #include <memory> -#include <set> #include <string> -#include <unordered_map> #include <vector> // Get rid of some windows macros: @@ -44,38 +27,6 @@ namespace { -std::vector<std::string> getConfigurations(const cmake* cm) -{ - std::vector<std::string> configurations; - auto makefiles = cm->GetGlobalGenerator()->GetMakefiles(); - if (makefiles.empty()) { - return configurations; - } - - makefiles[0]->GetConfigurations(configurations); - if (configurations.empty()) { - configurations.push_back(""); - } - return configurations; -} - -bool hasString(const Json::Value& v, const std::string& s) -{ - return !v.isNull() && - std::any_of(v.begin(), v.end(), - [s](const Json::Value& i) { return i.asString() == s; }); -} - -template <class T> -Json::Value fromStringList(const T& in) -{ - Json::Value result = Json::arrayValue; - for (std::string const& i : in) { - result.append(i); - } - return result; -} - std::vector<std::string> toStringList(const Json::Value& in) { std::vector<std::string> result; @@ -85,49 +36,6 @@ std::vector<std::string> toStringList(const Json::Value& in) return result; } -void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir, - const std::string& buildDir, - std::vector<std::string>* internalFiles, - std::vector<std::string>* explicitFiles, - std::vector<std::string>* tmpFiles) -{ - const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/'; - std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles(); - for (cmMakefile const* mf : makefiles) { - for (std::string const& lf : mf->GetListFiles()) { - - const std::string startOfFile = lf.substr(0, cmakeRootDir.size()); - const bool isInternal = (startOfFile == cmakeRootDir); - const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0); - - std::string toAdd = lf; - if (!sourceDir.empty()) { - const std::string& relative = - cmSystemTools::RelativePath(sourceDir, lf); - if (toAdd.size() > relative.size()) { - toAdd = relative; - } - } - - if (isInternal) { - if (internalFiles) { - internalFiles->push_back(std::move(toAdd)); - } - } else { - if (isTemporary) { - if (tmpFiles) { - tmpFiles->push_back(std::move(toAdd)); - } - } else { - if (explicitFiles) { - explicitFiles->push_back(std::move(toAdd)); - } - } - } - } - } -} - } // namespace cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection, @@ -558,704 +466,16 @@ cmServerResponse cmServerProtocol1::ProcessCMakeInputs( } const cmake* cm = this->CMakeInstance(); - const cmGlobalGenerator* gg = cm->GetGlobalGenerator(); const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot(); - const std::string& buildDir = cm->GetHomeOutputDirectory(); const std::string& sourceDir = cm->GetHomeDirectory(); Json::Value result = Json::objectValue; result[kSOURCE_DIRECTORY_KEY] = sourceDir; result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir; - - std::vector<std::string> internalFiles; - std::vector<std::string> explicitFiles; - std::vector<std::string> tmpFiles; - getCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles, - &tmpFiles); - - Json::Value array = Json::arrayValue; - - Json::Value tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = true; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(internalFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = false; - tmp[kSOURCES_KEY] = fromStringList(explicitFiles); - array.append(tmp); - - tmp = Json::objectValue; - tmp[kIS_CMAKE_KEY] = false; - tmp[kIS_TEMPORARY_KEY] = true; - tmp[kSOURCES_KEY] = fromStringList(tmpFiles); - array.append(tmp); - - result[kBUILD_FILES_KEY] = array; - + result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm); return request.Reply(result); } -const std::string kInterfaceSourcesLanguageDataKey = - "INTERFACE_SOURCES_LD_KEY"; -class LanguageData -{ -public: - bool operator==(const LanguageData& other) const; - - void SetDefines(const std::set<std::string>& defines); - - bool IsGenerated = false; - std::string Language; - std::string Flags; - std::vector<std::string> Defines; - std::vector<std::pair<std::string, bool>> IncludePathList; -}; - -bool LanguageData::operator==(const LanguageData& other) const -{ - return Language == other.Language && Defines == other.Defines && - Flags == other.Flags && IncludePathList == other.IncludePathList && - IsGenerated == other.IsGenerated; -} - -void LanguageData::SetDefines(const std::set<std::string>& defines) -{ - std::vector<std::string> result; - result.reserve(defines.size()); - for (std::string const& i : defines) { - result.push_back(i); - } - std::sort(result.begin(), result.end()); - Defines = std::move(result); -} - -struct FileGroupSources -{ - bool IsInterfaceSources; - std::vector<std::string> Files; -}; - -namespace std { - -template <> -struct hash<LanguageData> -{ - std::size_t operator()(const LanguageData& in) const - { - using std::hash; - size_t result = - hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags); - for (auto const& i : in.IncludePathList) { - result = result ^ - (hash<std::string>()(i.first) ^ - (i.second ? std::numeric_limits<size_t>::max() : 0)); - } - for (auto const& i : in.Defines) { - result = result ^ hash<std::string>()(i); - } - result = - result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0); - return result; - } -}; - -} // namespace std - -static Json::Value DumpSourceFileGroup(const LanguageData& data, - bool isInterfaceSource, - const std::vector<std::string>& files, - const std::string& baseDir) -{ - Json::Value result = Json::objectValue; - - if (isInterfaceSource) { - result[kIS_INTERFACE_SOURCES_KEY] = true; - } - if (!data.Language.empty()) { - result[kLANGUAGE_KEY] = data.Language; - } - if (!data.Flags.empty()) { - result[kCOMPILE_FLAGS_KEY] = data.Flags; - } - if (!data.IncludePathList.empty()) { - Json::Value includes = Json::arrayValue; - for (auto const& i : data.IncludePathList) { - Json::Value tmp = Json::objectValue; - tmp[kPATH_KEY] = i.first; - if (i.second) { - tmp[kIS_SYSTEM_KEY] = i.second; - } - includes.append(tmp); - } - result[kINCLUDE_PATH_KEY] = includes; - } - if (!data.Defines.empty()) { - result[kDEFINES_KEY] = fromStringList(data.Defines); - } - - result[kIS_GENERATED_KEY] = data.IsGenerated; - - Json::Value sourcesValue = Json::arrayValue; - for (auto const& i : files) { - const std::string relPath = cmSystemTools::RelativePath(baseDir, i); - sourcesValue.append(relPath.size() < i.size() ? relPath : i); - } - - result[kSOURCES_KEY] = sourcesValue; - return result; -} - -static void PopulateFileGroupData( - cmGeneratorTarget* target, bool isInterfaceSources, - const std::vector<cmSourceFile*>& files, const std::string& config, - const std::map<std::string, LanguageData>& languageDataMap, - std::unordered_map<LanguageData, FileGroupSources>& fileGroups) -{ - for (cmSourceFile* file : files) { - LanguageData fileData; - fileData.Language = file->GetLanguage(); - if (!fileData.Language.empty() || isInterfaceSources) { - const LanguageData& ld = isInterfaceSources - ? languageDataMap.at(kInterfaceSourcesLanguageDataKey) - : languageDataMap.at(fileData.Language); - cmLocalGenerator* lg = target->GetLocalGenerator(); - cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target, - fileData.Language); - - std::string compileFlags = ld.Flags; - const std::string COMPILE_FLAGS("COMPILE_FLAGS"); - if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) { - lg->AppendFlags(compileFlags, - genexInterpreter.Evaluate(cflags, COMPILE_FLAGS)); - } - const std::string COMPILE_OPTIONS("COMPILE_OPTIONS"); - if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) { - lg->AppendCompileOptions( - compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS)); - } - fileData.Flags = compileFlags; - - // Add include directories from source file properties. - std::vector<std::string> includes; - - const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES"); - if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) { - const std::string& evaluatedIncludes = - genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES); - lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file); - - for (const auto& include : includes) { - // INTERFACE_LIBRARY targets do not support the - // IsSystemIncludeDirectory call so just set it to false. - const bool isSystemInclude = isInterfaceSources - ? false - : target->IsSystemIncludeDirectory(include, config, - fileData.Language); - fileData.IncludePathList.push_back( - std::make_pair(include, isSystemInclude)); - } - } - - fileData.IncludePathList.insert(fileData.IncludePathList.end(), - ld.IncludePathList.begin(), - ld.IncludePathList.end()); - - const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS"); - std::set<std::string> defines; - if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) { - lg->AppendDefines( - defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS)); - } - - const std::string defPropName = - "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config); - if (const char* config_defs = file->GetProperty(defPropName)) { - lg->AppendDefines( - defines, - genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS)); - } - - defines.insert(ld.Defines.begin(), ld.Defines.end()); - - fileData.SetDefines(defines); - } - - fileData.IsGenerated = file->GetPropertyAsBool("GENERATED"); - FileGroupSources& groupFileList = fileGroups[fileData]; - groupFileList.IsInterfaceSources = isInterfaceSources; - groupFileList.Files.push_back(file->GetFullPath()); - } -} - -static Json::Value DumpSourceFilesList( - cmGeneratorTarget* target, const std::string& config, - const std::map<std::string, LanguageData>& languageDataMap) -{ - const cmStateEnums::TargetType type = target->GetType(); - std::unordered_map<LanguageData, FileGroupSources> fileGroups; - - // Collect sourcefile groups: - - std::vector<cmSourceFile*> files; - if (type == cmStateEnums::INTERFACE_LIBRARY) { - // INTERFACE_LIBRARY targets do not create all the data structures - // associated with regular targets. If properties are explicitly specified - // for files in INTERFACE_SOURCES then we can get them through the Makefile - // rather than the target. - files = target->Makefile->GetSourceFiles(); - } else { - target->GetSourceFiles(files, config); - PopulateFileGroupData(target, false /* isInterfaceSources */, files, - config, languageDataMap, fileGroups); - } - - // Collect interface sourcefile groups: - - auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES"); - if (targetProp != nullptr) { - cmGeneratorExpressionInterpreter genexInterpreter( - target->GetLocalGenerator(), config, target); - - auto evaluatedSources = cmsys::SystemTools::SplitString( - genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';'); - - std::map<std::string, cmSourceFile*> filesMap; - for (auto file : files) { - filesMap[file->GetFullPath()] = file; - } - - std::vector<cmSourceFile*> interfaceSourceFiles; - for (const std::string& interfaceSourceFilePath : evaluatedSources) { - auto entry = filesMap.find(interfaceSourceFilePath); - if (entry != filesMap.end()) { - // use what we have since it has all the associated properties - interfaceSourceFiles.push_back(entry->second); - } else { - interfaceSourceFiles.push_back( - new cmSourceFile(target->Makefile, interfaceSourceFilePath)); - } - } - - PopulateFileGroupData(target, true /* isInterfaceSources */, - interfaceSourceFiles, config, languageDataMap, - fileGroups); - } - - const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory(); - Json::Value result = Json::arrayValue; - for (auto const& it : fileGroups) { - Json::Value group = DumpSourceFileGroup( - it.first, it.second.IsInterfaceSources, it.second.Files, baseDir); - if (!group.isNull()) { - result.append(group); - } - } - - return result; -} - -static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kCTEST_NAME] = testInfo->GetName(); - - // Concat command entries together. After the first should be the arguments - // for the command - std::string command; - for (auto const& cmd : testInfo->GetCommand()) { - command.append(cmd); - command.append(" "); - } - - // Remove any config specific variables from the output. - cmGeneratorExpression ge; - auto cge = ge.Parse(command); - const std::string& processed = cge->Evaluate(lg, config); - result[kCTEST_COMMAND] = processed; - - // Build up the list of properties that may have been specified - Json::Value properties = Json::arrayValue; - for (auto& prop : testInfo->GetProperties()) { - Json::Value entry = Json::objectValue; - entry[kKEY_KEY] = prop.first; - - // Remove config variables from the value too. - auto cge_value = ge.Parse(prop.second.GetValue()); - const std::string& processed_value = cge_value->Evaluate(lg, config); - entry[kVALUE_KEY] = processed_value; - properties.append(entry); - } - result[kPROPERTIES_KEY] = properties; - - return result; -} - -static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config, - Json::Value* result) -{ - auto mf = lg->GetMakefile(); - std::vector<cmTest*> tests; - mf->GetTests(config, tests); - for (auto test : tests) { - Json::Value tmp = DumpCTestInfo(lg, test, config); - if (!tmp.isNull()) { - result->append(tmp); - } - } -} - -static Json::Value DumpCTestProjectList(const cmake* cm, - std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (const auto& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - Json::Value tests = Json::arrayValue; - - // Gather tests for every generator - for (const auto& lg : projectIt.second) { - // Make sure they're generated. - lg->GenerateTestFiles(); - DumpMakefileTests(lg, config, &tests); - } - - pObj[kCTEST_INFO] = tests; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpCTestConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config); - - return result; -} - -static Json::Value DumpCTestConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (const std::string& c : getConfigurations(cm)) { - result.append(DumpCTestConfiguration(cm, c)); - } - - return result; -} - -static void GetTargetProperty( - cmGeneratorExpressionInterpreter& genexInterpreter, - cmGeneratorTarget* target, const char* propertyName, - std::vector<std::string>& propertyValue) -{ - auto targetProp = target->Target->GetProperty(propertyName); - if (targetProp != nullptr) { - propertyValue = cmsys::SystemTools::SplitString( - genexInterpreter.Evaluate(targetProp, propertyName), ';'); - } -} - -static void CreateInterfaceSourcesEntry( - cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config, - std::map<std::string, LanguageData>& languageDataMap) -{ - LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey]; - ld.Language = ""; - - cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target); - std::vector<std::string> propertyValue; - GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES", - propertyValue); - for (std::string const& i : propertyValue) { - ld.IncludePathList.push_back( - std::make_pair(i, false /* isSystemInclude */)); - } - - propertyValue.clear(); - GetTargetProperty(genexInterpreter, target, - "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", propertyValue); - for (std::string const& i : propertyValue) { - ld.IncludePathList.push_back( - std::make_pair(i, true /* isSystemInclude */)); - } - - propertyValue.clear(); - GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_OPTIONS", - propertyValue); - for (const auto& s : propertyValue) { - ld.Flags += " " + s; - } - - propertyValue.clear(); - GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_DEFINITIONS", - propertyValue); - if (!propertyValue.empty()) { - std::set<std::string> defines(propertyValue.begin(), propertyValue.end()); - ld.SetDefines(defines); - } -} - -static Json::Value DumpTarget(cmGeneratorTarget* target, - const std::string& config) -{ - cmLocalGenerator* lg = target->GetLocalGenerator(); - const cmState* state = lg->GetState(); - - const cmStateEnums::TargetType type = target->GetType(); - const std::string typeName = state->GetTargetTypeName(type); - - Json::Value ttl = Json::arrayValue; - ttl.append("EXECUTABLE"); - ttl.append("STATIC_LIBRARY"); - ttl.append("SHARED_LIBRARY"); - ttl.append("MODULE_LIBRARY"); - ttl.append("OBJECT_LIBRARY"); - ttl.append("UTILITY"); - ttl.append("INTERFACE_LIBRARY"); - - if (!hasString(ttl, typeName) || target->IsImported()) { - return Json::Value(); - } - - Json::Value result = Json::objectValue; - result[kNAME_KEY] = target->GetName(); - result[kIS_GENERATOR_PROVIDED_KEY] = - target->Target->GetIsGeneratorProvided(); - result[kTYPE_KEY] = typeName; - result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory(); - result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory(); - result[kFULL_NAME_KEY] = target->GetFullName(config); - - if (target->Target->GetHaveInstallRule()) { - result[kHAS_INSTALL_RULE] = true; - - Json::Value installPaths = Json::arrayValue; - auto targetGenerators = target->Makefile->GetInstallGenerators(); - for (auto installGenerator : targetGenerators) { - auto installTargetGenerator = - dynamic_cast<cmInstallTargetGenerator*>(installGenerator); - if (installTargetGenerator != nullptr && - installTargetGenerator->GetTarget()->Target == target->Target) { - auto dest = installTargetGenerator->GetDestination(config); - - std::string installPath; - if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) { - installPath = dest; - } else { - std::string installPrefix = - target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); - installPath = installPrefix + '/' + dest; - } - - installPaths.append(installPath); - } - } - - result[kINSTALL_PATHS] = installPaths; - } - - if (target->HaveWellDefinedOutputFiles()) { - Json::Value artifacts = Json::arrayValue; - artifacts.append( - target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact)); - if (target->IsDLLPlatform()) { - artifacts.append( - target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact)); - const cmGeneratorTarget::OutputInfo* output = - target->GetOutputInfo(config); - if (output && !output->PdbDir.empty()) { - artifacts.append(output->PdbDir + '/' + target->GetPDBName(config)); - } - } - result[kARTIFACTS_KEY] = artifacts; - - result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config); - - std::string linkLibs; - std::string linkFlags; - std::string linkLanguageFlags; - std::string frameworkPath; - std::string linkPath; - cmLinkLineComputer linkLineComputer(lg, - lg->GetStateSnapshot().GetDirectory()); - lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags, - linkFlags, frameworkPath, linkPath, target); - - linkLibs = cmSystemTools::TrimWhitespace(linkLibs); - linkFlags = cmSystemTools::TrimWhitespace(linkFlags); - linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags); - frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath); - linkPath = cmSystemTools::TrimWhitespace(linkPath); - - if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) { - result[kLINK_LIBRARIES_KEY] = linkLibs; - } - if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) { - result[kLINK_FLAGS_KEY] = linkFlags; - } - if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) { - result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags; - } - if (!frameworkPath.empty()) { - result[kFRAMEWORK_PATH_KEY] = frameworkPath; - } - if (!linkPath.empty()) { - result[kLINK_PATH_KEY] = linkPath; - } - const std::string sysroot = - lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT"); - if (!sysroot.empty()) { - result[kSYSROOT_KEY] = sysroot; - } - } - - std::set<std::string> languages; - std::map<std::string, LanguageData> languageDataMap; - if (type == cmStateEnums::INTERFACE_LIBRARY) { - // INTERFACE_LIBRARY targets do not create all the data structures - // associated with regular targets. If properties are explicitly specified - // for files in INTERFACE_SOURCES then we can get them through the Makefile - // rather than the target. - for (auto file : target->Makefile->GetSourceFiles()) { - const std::string& language = file->GetLanguage(); - if (!language.empty()) { - languages.insert(language); - } - } - } else { - target->GetLanguages(languages, config); - } - - for (std::string const& lang : languages) { - LanguageData& ld = languageDataMap[lang]; - ld.Language = lang; - lg->GetTargetCompileFlags(target, config, lang, ld.Flags); - std::set<std::string> defines; - lg->GetTargetDefines(target, config, lang, defines); - ld.SetDefines(defines); - std::vector<std::string> includePathList; - lg->GetIncludeDirectories(includePathList, target, lang, config, true); - for (std::string const& i : includePathList) { - ld.IncludePathList.push_back( - std::make_pair(i, target->IsSystemIncludeDirectory(i, config, lang))); - } - } - - if (target->Target->GetProperty("INTERFACE_SOURCES") != nullptr) { - // Create an entry in the languageDataMap for interface sources. - CreateInterfaceSourcesEntry(lg, target, config, languageDataMap); - } - - Json::Value sourceGroupsValue = - DumpSourceFilesList(target, config, languageDataMap); - if (!sourceGroupsValue.empty()) { - result[kFILE_GROUPS_KEY] = sourceGroupsValue; - } - - return result; -} - -static Json::Value DumpTargetsList( - const std::vector<cmLocalGenerator*>& generators, const std::string& config) -{ - Json::Value result = Json::arrayValue; - - std::vector<cmGeneratorTarget*> targetList; - for (auto const& lgIt : generators) { - const auto& list = lgIt->GetGeneratorTargets(); - targetList.insert(targetList.end(), list.begin(), list.end()); - } - std::sort(targetList.begin(), targetList.end()); - - for (cmGeneratorTarget* target : targetList) { - Json::Value tmp = DumpTarget(target, config); - if (!tmp.isNull()) { - result.append(tmp); - } - } - - return result; -} - -static Json::Value DumpProjectList(const cmake* cm, std::string const& config) -{ - Json::Value result = Json::arrayValue; - - auto globalGen = cm->GetGlobalGenerator(); - - for (auto const& projectIt : globalGen->GetProjectMap()) { - Json::Value pObj = Json::objectValue; - pObj[kNAME_KEY] = projectIt.first; - - // All Projects must have at least one local generator - assert(!projectIt.second.empty()); - const cmLocalGenerator* lg = projectIt.second.at(0); - - // Project structure information: - const cmMakefile* mf = lg->GetMakefile(); - auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION"); - pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : ""; - pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory(); - pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory(); - pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config); - - // For a project-level install rule it might be defined in any of its - // associated generators. - bool hasInstallRule = false; - for (const auto generator : projectIt.second) { - hasInstallRule = - generator->GetMakefile()->GetInstallGenerators().empty() == false; - - if (hasInstallRule) { - break; - } - } - - pObj[kHAS_INSTALL_RULE] = hasInstallRule; - - result.append(pObj); - } - - return result; -} - -static Json::Value DumpConfiguration(const cmake* cm, - const std::string& config) -{ - Json::Value result = Json::objectValue; - result[kNAME_KEY] = config; - - result[kPROJECTS_KEY] = DumpProjectList(cm, config); - - return result; -} - -static Json::Value DumpConfigurationsList(const cmake* cm) -{ - Json::Value result = Json::arrayValue; - - for (std::string const& c : getConfigurations(cm)) { - result.append(DumpConfiguration(cm, c)); - } - - return result; -} - cmServerResponse cmServerProtocol1::ProcessCodeModel( const cmServerRequest& request) { @@ -1263,9 +483,7 @@ cmServerResponse cmServerProtocol1::ProcessCodeModel( return request.ReportError("No build system was generated yet."); } - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(this->CMakeInstance()); - return request.Reply(result); + return request.Reply(cmDumpCodeModel(this->CMakeInstance())); } cmServerResponse cmServerProtocol1::ProcessCompute( @@ -1382,7 +600,8 @@ cmServerResponse cmServerProtocol1::ProcessConfigure( } std::vector<std::string> toWatchList; - getCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, nullptr); + cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, + nullptr); FileMonitor()->MonitorPaths(toWatchList, [this](const std::string& p, int e, int s) { @@ -1488,10 +707,7 @@ cmServerResponse cmServerProtocol1::ProcessCTests( return request.ReportError("This instance was not yet computed."); } - Json::Value result = Json::objectValue; - result[kCONFIGURATIONS_KEY] = - DumpCTestConfigurationsList(this->CMakeInstance()); - return request.Reply(result); + return request.Reply(cmDumpCTestInfo(this->CMakeInstance())); } cmServerProtocol1::GeneratorInformation::GeneratorInformation( diff --git a/Source/cmState.cxx b/Source/cmState.cxx index c8b8653..c6667f6 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -659,6 +659,7 @@ cmStateSnapshot cmState::CreateBaseSnapshot() pos->IncludeDirectoryPosition = 0; pos->CompileDefinitionsPosition = 0; pos->CompileOptionsPosition = 0; + pos->LinkOptionsPosition = 0; pos->BuildSystemDirectory->DirectoryEnd = pos; pos->Policies = this->PolicyStack.Root(); pos->PolicyRoot = this->PolicyStack.Root(); @@ -810,6 +811,8 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot) prevPos->BuildSystemDirectory->CompileDefinitions.size(); prevPos->CompileOptionsPosition = prevPos->BuildSystemDirectory->CompileOptions.size(); + prevPos->LinkOptionsPosition = + prevPos->BuildSystemDirectory->LinkOptions.size(); prevPos->BuildSystemDirectory->DirectoryEnd = prevPos; if (!pos->Keep && this->SnapshotData.IsLast(pos)) { diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 79e5ccf..8339aac 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -6,6 +6,7 @@ #include "cmDuration.h" #include "cmProcessOutput.h" #include "cm_sys_stat.h" +#include "cm_uv.h" #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmArchiveWrite.h" @@ -55,8 +56,6 @@ # include <wincrypt.h> # include <fcntl.h> /* _O_TEXT */ - -# include "cm_uv.h" #else # include <sys/time.h> # include <unistd.h> @@ -2988,3 +2987,25 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value) *value = strtoul(str, &endp, 10); return (*endp == '\0') && (endp != str) && (errno == 0); } + +bool cmSystemTools::CreateSymlink(const std::string& origName, + const std::string& newName) +{ + uv_fs_t req; + int flags = 0; +#if defined(_WIN32) + if (cmsys::SystemTools::FileIsDirectory(origName)) { + flags |= UV_FS_SYMLINK_DIR; + } +#endif + int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(), + flags, nullptr); + if (err) { + std::string e = + "failed to create symbolic link '" + newName + "': " + uv_strerror(err); + cmSystemTools::Error(e.c_str()); + return false; + } + + return true; +} diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 5c383ee..98300eb 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -513,6 +513,11 @@ public: /** Perform one-time initialization of libuv. */ static void InitializeLibUV(); + /** Create a symbolic link if the platform supports it. Returns whether + creation succeeded. */ + static bool CreateSymlink(const std::string& origName, + const std::string& newName); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index cd40223..4e353c7 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -190,13 +190,11 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, // Check whether this is a DLL platform. this->DLLPlatform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); // Check whether we are targeting an Android platform. this->IsAndroid = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"), - "Android") == 0; + (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"); // Setup default property values. if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && diff --git a/Source/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx index f0f13fd..d6ed5ae 100644 --- a/Source/cmTargetLinkOptionsCommand.cxx +++ b/Source/cmTargetLinkOptionsCommand.cxx @@ -33,9 +33,9 @@ std::string cmTargetLinkOptionsCommand::Join( } bool cmTargetLinkOptionsCommand::HandleDirectContent( - cmTarget* tgt, const std::vector<std::string>& content, bool, bool) + cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool) { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - tgt->InsertLinkOption(this->Join(content), lfbt); + tgt->InsertLinkOption(this->Join(content), lfbt, prepend); return true; // Successfully handled. } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 53a2a59..c79b071 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1122,6 +1122,9 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { e1.Element("WindowsAppContainer", "true"); } + if (this->IPOEnabledConfigurations.count(config) > 0) { + e1.Element("WholeProgramOptimization", "true"); + } } void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( @@ -2370,9 +2373,11 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( Options& linkOptions = *(this->LinkOptions[configName]); const std::string cond = this->CalcCondition(configName); - const char* incremental = linkOptions.GetFlag("LinkIncremental"); - e1.WritePlatformConfigTag("LinkIncremental", cond, - (incremental ? incremental : "true")); + if (this->IPOEnabledConfigurations.count(configName) == 0) { + const char* incremental = linkOptions.GetFlag("LinkIncremental"); + e1.WritePlatformConfigTag("LinkIncremental", cond, + (incremental ? incremental : "true")); + } linkOptions.RemoveFlag("LinkIncremental"); const char* manifest = linkOptions.GetFlag("GenerateManifest"); @@ -2484,8 +2489,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.AddFlag("CompileAs", "CompileAsCpp"); } - // Check IPO related warning/error. - this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName); + // Put the IPO enabled configurations into a set. + if (this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName)) { + this->IPOEnabledConfigurations.insert(configName); + } // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); @@ -2699,11 +2706,9 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions( Options& rcOptions = *pOptions; std::string CONFIG = cmSystemTools::UpperCase(configName); - std::string rcConfigFlagsVar = std::string("CMAKE_RC_FLAGS_") + CONFIG; - std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(rcConfigFlagsVar)); + std::string rcConfigFlagsVar = "CMAKE_RC_FLAGS_" + CONFIG; + std::string flags = this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS") + + " " + this->Makefile->GetSafeDefinition(rcConfigFlagsVar); rcOptions.Parse(flags); @@ -2757,10 +2762,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // Get compile flags for CUDA in this directory. std::string CONFIG = cmSystemTools::UpperCase(configName); std::string configFlagsVar = std::string("CMAKE_CUDA_FLAGS_") + CONFIG; - std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + std::string flags = this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS") + + " " + this->Makefile->GetSafeDefinition(configFlagsVar); this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA", configName); @@ -2971,9 +2974,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( std::string CONFIG = cmSystemTools::UpperCase(configName); std::string configFlagsVar = std::string("CMAKE_ASM_MASM_FLAGS_") + CONFIG; std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS") + " " + + this->Makefile->GetSafeDefinition(configFlagsVar); masmOptions.Parse(flags); @@ -3024,14 +3026,11 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( Options& nasmOptions = *pOptions; std::string CONFIG = cmSystemTools::UpperCase(configName); - std::string configFlagsVar = std::string("CMAKE_ASM_NASM_FLAGS_") + CONFIG; + std::string configFlagsVar = "CMAKE_ASM_NASM_FLAGS_" + CONFIG; std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS")) + - std::string(" -f") + - std::string( - this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS") + " -f" + + this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT") + " " + + this->Makefile->GetSafeDefinition(configFlagsVar); nasmOptions.Parse(flags); // Get includes for this target diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 15e47b4..829d2bf 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -204,6 +204,7 @@ private: bool NsightTegra; unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; + std::set<std::string> IPOEnabledConfigurations; cmGlobalVisualStudio10Generator* const GlobalGenerator; cmLocalVisualStudio10Generator* const LocalGenerator; std::set<std::string> CSharpCustomCommandNames; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 783dbf2..c26a380 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -225,10 +225,8 @@ cmake::~cmake() } #if defined(CMAKE_BUILD_WITH_CMAKE) -Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const +Json::Value cmake::ReportVersionJson() const { - Json::Value obj = Json::objectValue; - // Version information: Json::Value version = Json::objectValue; version["string"] = CMake_VERSION; version["major"] = CMake_VERSION_MAJOR; @@ -236,8 +234,15 @@ Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const version["suffix"] = CMake_VERSION_SUFFIX; version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1); version["patch"] = CMake_VERSION_PATCH; + return version; +} + +Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const +{ + Json::Value obj = Json::objectValue; - obj["version"] = version; + // Version information: + obj["version"] = this->ReportVersionJson(); // Generators: std::vector<cmake::GeneratorInfo> generatorInfoList; @@ -612,19 +617,43 @@ void cmake::SetArgs(const std::vector<std::string>& args, bool havePlatform = false; for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; - if (arg.find("-H", 0) == 0) { + if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) { directoriesSet = true; std::string path = arg.substr(2); + if (path.empty()) { + ++i; + if (i >= args.size()) { + cmSystemTools::Error("No source directory specified for -S"); + return; + } + path = args[i]; + if (path[0] == '-') { + cmSystemTools::Error("No source directory specified for -S"); + return; + } + } + path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeDirectory(path); - } else if (arg.find("-S", 0) == 0) { - // There is no local generate anymore. Ignore -S option. } else if (arg.find("-O", 0) == 0) { // There is no local generate anymore. Ignore -O option. } else if (arg.find("-B", 0) == 0) { directoriesSet = true; std::string path = arg.substr(2); + if (path.empty()) { + ++i; + if (i >= args.size()) { + cmSystemTools::Error("No build directory specified for -B"); + return; + } + path = args[i]; + if (path[0] == '-') { + cmSystemTools::Error("No build directory specified for -B"); + return; + } + } + path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeOutputDirectory(path); @@ -836,20 +865,27 @@ void cmake::SetDirectoriesFromFile(const char* arg) this->SetHomeOutputDirectory(listPath); } else { // Source directory given on command line. Use current working - // directory as build tree. - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - this->SetHomeOutputDirectory(cwd); + // directory as build tree if -B hasn't been given already + if (this->GetHomeOutputDirectory().empty()) { + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } } return; } - // We didn't find a CMakeLists.txt or CMakeCache.txt file from the - // argument. Assume it is the path to the source tree, and use the - // current working directory as the build tree. - std::string full = cmSystemTools::CollapseFullPath(arg); - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - this->SetHomeDirectory(full); - this->SetHomeOutputDirectory(cwd); + if (this->GetHomeDirectory().empty()) { + // We didn't find a CMakeLists.txt and it wasn't specified + // with -S. Assume it is the path to the source tree + std::string full = cmSystemTools::CollapseFullPath(arg); + this->SetHomeDirectory(full); + } + if (this->GetHomeOutputDirectory().empty()) { + // We didn't find a CMakeCache.txt and it wasn't specified + // with -B. Assume the current working directory as the build tree. + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } } // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the diff --git a/Source/cmake.h b/Source/cmake.h index 4b4c67c..d3d0e80 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -128,6 +128,7 @@ public: ~cmake(); #if defined(CMAKE_BUILD_WITH_CMAKE) + Json::Value ReportVersionJson() const; Json::Value ReportCapabilitiesJson(bool haveServerMode) const; #endif std::string ReportCapabilities(bool haveServerMode) const; @@ -556,7 +557,9 @@ private: }; #define CMAKE_STANDARD_OPTIONS_TABLE \ - { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ + { "-S <path-to-source>", "Explicitly specify a source directory." }, \ + { "-B <path-to-build>", "Explicitly specify a build directory." }, \ + { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \ { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \ { "-G <generator-name>", "Specify a build system generator." }, \ diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index e3d94f6..75dabde 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -38,7 +38,8 @@ static const char* cmDocumentationName[][2] = { static const char* cmDocumentationUsage[][2] = { { nullptr, " cmake [options] <path-to-source>\n" - " cmake [options] <path-to-existing-build>" }, + " cmake [options] <path-to-existing-build>\n" + " cmake [options] -S <path-to-source> -B <path-to-build>" }, { nullptr, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 87da108..1d2f741 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -108,6 +108,7 @@ void CMakeCommandUsage(const char* program) << " time command [args...] - run command and display elapsed time\n" << " touch file - touch a file.\n" << " touch_nocreate file - touch a file but do not create it.\n" + << " create_symlink old new - create a symbolic link new -> old\n" #if defined(_WIN32) && !defined(__CYGWIN__) << "Available on Windows only:\n" << " delete_regv key - delete registry value\n" @@ -116,9 +117,6 @@ void CMakeCommandUsage(const char* program) << " env_vs9_wince sdkname - displays a batch file which sets the " "environment for the provided Windows CE SDK installed in VS2008\n" << " write_regv key value - write registry value\n" -#else - << "Available on UNIX only:\n" - << " create_symlink old new - create a symbolic link new -> old\n" #endif ; /* clang-format on */ @@ -868,9 +866,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 1; } if (!cmSystemTools::CreateSymlink(args[2], args[3])) { - std::string emsg = cmSystemTools::GetLastSystemError(); - std::cerr << "failed to create symbolic link '" << destinationFileName - << "': " << emsg << "\n"; return 1; } return 0; diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 9fa0cb1..2a2e737 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -973,8 +973,8 @@ void kwsysProcess_Execute(kwsysProcess* cp) wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); DWORD error; cp->PipeChildStd[0] = - CreateFileW(wstdin, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0); error = GetLastError(); /* Check now in case free changes this. */ free(wstdin); if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 476fe08..0a4ad7a 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3640,11 +3640,11 @@ bool SystemTools::Split(const std::string& str, while (lpos < data.length()) { std::string::size_type rpos = data.find_first_of(separator, lpos); if (rpos == std::string::npos) { - // Line ends at end of string without a newline. + // String ends at end of string without a separator. lines.push_back(data.substr(lpos)); return false; } else { - // Line ends in a "\n", remove the character. + // String ends in a separator, remove the character. lines.push_back(data.substr(lpos, rpos - lpos)); } lpos = rpos + 1; @@ -3658,7 +3658,7 @@ bool SystemTools::Split(const std::string& str, std::string data(str); std::string::size_type lpos = 0; while (lpos < data.length()) { - std::string::size_type rpos = data.find_first_of("\n", lpos); + std::string::size_type rpos = data.find_first_of('\n', lpos); if (rpos == std::string::npos) { // Line ends at end of string without a newline. lines.push_back(data.substr(lpos)); |