| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmRulePlaceholderExpander.h" | |
| #include <utility> | |
| #include "cmOutputConverter.h" | |
| #include "cmStringAlgorithms.h" | |
| #include "cmSystemTools.h" | |
| cmRulePlaceholderExpander::cmRulePlaceholderExpander( | |
| cmBuildStep buildStep, std::map<std::string, std::string> compilers, | |
| std::map<std::string, std::string> variableMappings, | |
| std::string compilerSysroot, std::string linkerSysroot, | |
| UseShortPaths useShortPaths) | |
| : BuildStep(buildStep) | |
| , Compilers(std::move(compilers)) | |
| , VariableMappings(std::move(variableMappings)) | |
| , CompilerSysroot(std::move(compilerSysroot)) | |
| , LinkerSysroot(std::move(linkerSysroot)) | |
| { | |
| if (useShortPaths == UseShortPaths::Yes) { | |
| this->ConvertToOutputForExisting = | |
| [this](cm::string_view path) -> std::string { | |
| return this->OutputConverter->ConvertToOutputForExisting(path); | |
| }; | |
| } else { | |
| this->ConvertToOutputForExisting = | |
| [this](cm::string_view path) -> std::string { | |
| return this->OutputConverter->ConvertToOutputFormat( | |
| path, cmOutputConverter::SHELL); | |
| }; | |
| } | |
| } | |
| std::string cmRulePlaceholderExpander::ExpandVariable( | |
| std::string const& variable) | |
| { | |
| if (this->ReplaceValues->LinkFlags) { | |
| if (variable == "LINK_FLAGS") { | |
| return this->ReplaceValues->LinkFlags; | |
| } | |
| } | |
| if (this->ReplaceValues->Linker) { | |
| if (variable == "CMAKE_LINKER") { | |
| auto result = | |
| this->ConvertToOutputForExisting(this->ReplaceValues->Linker); | |
| if (this->ReplaceValues->Launcher) { | |
| // Add launcher as part of expansion so that it always appears | |
| // immediately before the command itself, regardless of whether the | |
| // overall rule template contains other content at the front. | |
| result = | |
| cmStrCat(this->ReplaceValues->Launcher, ' ', std::move(result)); | |
| } | |
| return result; | |
| } | |
| } | |
| if (this->ReplaceValues->Language && this->ReplaceValues->Launcher && | |
| variable == | |
| cmStrCat("CMAKE_", this->ReplaceValues->Language, | |
| "_HOST_LINK_LAUNCHER")) { | |
| auto mapIt = this->VariableMappings.find(variable); | |
| std::string result = mapIt != this->VariableMappings.end() | |
| ? this->ConvertToOutputForExisting(mapIt->second) | |
| : variable; | |
| // Add launcher as part of expansion so that it always appears | |
| // immediately before the command itself, regardless of whether the | |
| // overall rule template contains other content at the front. | |
| return cmStrCat(this->ReplaceValues->Launcher, ' ', result); | |
| } | |
| if (this->ReplaceValues->Manifests) { | |
| if (variable == "MANIFESTS") { | |
| return this->ReplaceValues->Manifests; | |
| } | |
| } | |
| if (this->ReplaceValues->Flags) { | |
| if (variable == "FLAGS") { | |
| return this->ReplaceValues->Flags; | |
| } | |
| } | |
| if (this->ReplaceValues->Source) { | |
| if (variable == "SOURCE") { | |
| return this->ReplaceValues->Source; | |
| } | |
| } | |
| if (this->ReplaceValues->DynDepFile) { | |
| if (variable == "DYNDEP_FILE") { | |
| return this->ReplaceValues->DynDepFile; | |
| } | |
| } | |
| if (this->ReplaceValues->PreprocessedSource) { | |
| if (variable == "PREPROCESSED_SOURCE") { | |
| return this->ReplaceValues->PreprocessedSource; | |
| } | |
| } | |
| if (this->ReplaceValues->AssemblySource) { | |
| if (variable == "ASSEMBLY_SOURCE") { | |
| return this->ReplaceValues->AssemblySource; | |
| } | |
| } | |
| if (this->ReplaceValues->Object) { | |
| if (variable == "OBJECT") { | |
| return this->ReplaceValues->Object; | |
| } | |
| } | |
| if (this->ReplaceValues->TargetSupportDir) { | |
| if (variable == "TARGET_SUPPORT_DIR") { | |
| return this->ReplaceValues->TargetSupportDir; | |
| } | |
| } | |
| if (this->ReplaceValues->ObjectDir) { | |
| if (variable == "OBJECT_DIR") { | |
| return this->ReplaceValues->ObjectDir; | |
| } | |
| } | |
| if (this->ReplaceValues->ObjectFileDir) { | |
| if (variable == "OBJECT_FILE_DIR") { | |
| return this->ReplaceValues->ObjectFileDir; | |
| } | |
| } | |
| if (this->ReplaceValues->Objects) { | |
| if (variable == "OBJECTS") { | |
| return this->ReplaceValues->Objects; | |
| } | |
| } | |
| if (this->ReplaceValues->ObjectsQuoted) { | |
| if (variable == "OBJECTS_QUOTED") { | |
| return this->ReplaceValues->ObjectsQuoted; | |
| } | |
| } | |
| if (this->ReplaceValues->CudaCompileMode) { | |
| if (variable == "CUDA_COMPILE_MODE") { | |
| return this->ReplaceValues->CudaCompileMode; | |
| } | |
| } | |
| if (this->ReplaceValues->AIXExports) { | |
| if (variable == "AIX_EXPORTS") { | |
| return this->ReplaceValues->AIXExports; | |
| } | |
| } | |
| if (this->ReplaceValues->ISPCHeader) { | |
| if (variable == "ISPC_HEADER") { | |
| return this->ReplaceValues->ISPCHeader; | |
| } | |
| } | |
| if (this->ReplaceValues->Defines && variable == "DEFINES") { | |
| return this->ReplaceValues->Defines; | |
| } | |
| if (this->ReplaceValues->Includes && variable == "INCLUDES") { | |
| return this->ReplaceValues->Includes; | |
| } | |
| if (this->ReplaceValues->SwiftLibraryName) { | |
| if (variable == "SWIFT_LIBRARY_NAME") { | |
| return this->ReplaceValues->SwiftLibraryName; | |
| } | |
| } | |
| if (this->ReplaceValues->SwiftModule) { | |
| if (variable == "SWIFT_MODULE") { | |
| return this->ReplaceValues->SwiftModule; | |
| } | |
| } | |
| if (this->ReplaceValues->SwiftModuleName) { | |
| if (variable == "SWIFT_MODULE_NAME") { | |
| return this->ReplaceValues->SwiftModuleName; | |
| } | |
| } | |
| if (this->ReplaceValues->SwiftSources) { | |
| if (variable == "SWIFT_SOURCES") { | |
| return this->ReplaceValues->SwiftSources; | |
| } | |
| } | |
| if (this->ReplaceValues->RustEmit) { | |
| if (variable == "RUST_EMIT") { | |
| return this->ReplaceValues->RustEmit; | |
| } | |
| } | |
| if (this->ReplaceValues->RustMainCrateRoot) { | |
| if (variable == "RUST_MAIN_CRATE_ROOT") { | |
| return this->ReplaceValues->RustMainCrateRoot; | |
| } | |
| } | |
| if (this->ReplaceValues->RustLinkCrates) { | |
| if (variable == "RUST_LINK_CRATES") { | |
| return this->ReplaceValues->RustLinkCrates; | |
| } | |
| } | |
| if (this->ReplaceValues->RustNativeObjects) { | |
| if (variable == "RUST_NATIVE_OBJECTS") { | |
| return this->ReplaceValues->RustNativeObjects; | |
| } | |
| } | |
| if (this->ReplaceValues->TargetPDB) { | |
| if (variable == "TARGET_PDB") { | |
| return this->ReplaceValues->TargetPDB; | |
| } | |
| } | |
| if (this->ReplaceValues->TargetCompilePDB) { | |
| if (variable == "TARGET_COMPILE_PDB") { | |
| return this->ReplaceValues->TargetCompilePDB; | |
| } | |
| } | |
| if (this->ReplaceValues->DependencyFile) { | |
| if (variable == "DEP_FILE") { | |
| return this->ReplaceValues->DependencyFile; | |
| } | |
| } | |
| if (this->ReplaceValues->DependencyTarget) { | |
| if (variable == "DEP_TARGET") { | |
| return this->ReplaceValues->DependencyTarget; | |
| } | |
| } | |
| if (this->ReplaceValues->Fatbinary) { | |
| if (variable == "FATBINARY") { | |
| return this->ReplaceValues->Fatbinary; | |
| } | |
| } | |
| if (this->ReplaceValues->RegisterFile) { | |
| if (variable == "REGISTER_FILE") { | |
| return this->ReplaceValues->RegisterFile; | |
| } | |
| } | |
| if (this->ReplaceValues->Target) { | |
| if (variable == "TARGET_QUOTED") { | |
| std::string targetQuoted = this->ReplaceValues->Target; | |
| if (!targetQuoted.empty() && targetQuoted.front() != '\"') { | |
| targetQuoted = cmStrCat('"', this->ReplaceValues->Target, '"'); | |
| } | |
| return targetQuoted; | |
| } | |
| if (variable == "TARGET_UNQUOTED") { | |
| std::string unquoted = this->ReplaceValues->Target; | |
| std::string::size_type sz = unquoted.size(); | |
| if (sz > 2 && unquoted.front() == '\"' && unquoted.back() == '\"') { | |
| unquoted = unquoted.substr(1, sz - 2); | |
| } | |
| return unquoted; | |
| } | |
| if (this->ReplaceValues->LanguageCompileFlags) { | |
| if (variable == "LANGUAGE_COMPILE_FLAGS") { | |
| return this->ReplaceValues->LanguageCompileFlags; | |
| } | |
| } | |
| if (this->ReplaceValues->Target) { | |
| if (variable == "TARGET") { | |
| return this->ReplaceValues->Target; | |
| } | |
| } | |
| if (variable == "TARGET_IMPLIB") { | |
| return this->TargetImpLib; | |
| } | |
| if (variable == "TARGET_VERSION_MAJOR") { | |
| if (this->ReplaceValues->TargetVersionMajor) { | |
| return this->ReplaceValues->TargetVersionMajor; | |
| } | |
| return "0"; | |
| } | |
| if (variable == "TARGET_VERSION_MINOR") { | |
| if (this->ReplaceValues->TargetVersionMinor) { | |
| return this->ReplaceValues->TargetVersionMinor; | |
| } | |
| return "0"; | |
| } | |
| if (this->ReplaceValues->Target) { | |
| if (variable == "TARGET_BASE") { | |
| // Strip the last extension off the target name. | |
| std::string targetBase = this->ReplaceValues->Target; | |
| std::string::size_type pos = targetBase.rfind('.'); | |
| if (pos != std::string::npos) { | |
| return targetBase.substr(0, pos); | |
| } | |
| return targetBase; | |
| } | |
| } | |
| } | |
| if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" || | |
| variable == "TARGET_INSTALLNAME_DIR") { | |
| // All these variables depend on TargetSOName | |
| if (this->ReplaceValues->TargetSOName) { | |
| if (variable == "TARGET_SONAME") { | |
| return this->ReplaceValues->TargetSOName; | |
| } | |
| if (variable == "SONAME_FLAG" && this->ReplaceValues->SONameFlag) { | |
| return this->ReplaceValues->SONameFlag; | |
| } | |
| if (this->ReplaceValues->TargetInstallNameDir && | |
| variable == "TARGET_INSTALLNAME_DIR") { | |
| return this->ReplaceValues->TargetInstallNameDir; | |
| } | |
| } | |
| return ""; | |
| } | |
| if (this->ReplaceValues->LinkLibraries) { | |
| if (variable == "LINK_LIBRARIES") { | |
| return this->ReplaceValues->LinkLibraries; | |
| } | |
| } | |
| if (this->ReplaceValues->Language) { | |
| if (variable == "LANGUAGE") { | |
| return this->ReplaceValues->Language; | |
| } | |
| } | |
| if (this->ReplaceValues->CMTargetName) { | |
| if (variable == "TARGET_NAME") { | |
| return this->ReplaceValues->CMTargetName; | |
| } | |
| } | |
| if (this->ReplaceValues->CMTargetType) { | |
| if (variable == "TARGET_TYPE") { | |
| return this->ReplaceValues->CMTargetType; | |
| } | |
| } | |
| if (this->ReplaceValues->Output) { | |
| if (variable == "OUTPUT") { | |
| return this->ReplaceValues->Output; | |
| } | |
| } | |
| if (this->ReplaceValues->FilePathWithOutput) { | |
| if (variable == "OUTPUT_STORE_TO_FILE") { | |
| return this->ReplaceValues->FilePathWithOutput; | |
| } | |
| } | |
| if (variable == "CMAKE_COMMAND") { | |
| return this->OutputConverter->ConvertToOutputFormat( | |
| cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); | |
| } | |
| if (variable == "ROLE") { | |
| if (this->ReplaceValues->Role) { | |
| return this->ReplaceValues->Role; | |
| } | |
| return ""; | |
| } | |
| if (variable == "CONFIG") { | |
| if (this->ReplaceValues->Config) { | |
| return this->ReplaceValues->Config; | |
| } | |
| return ""; | |
| } | |
| auto compIt = this->Compilers.find(variable); | |
| if (compIt != this->Compilers.end()) { | |
| std::string const& compilerPath = | |
| this->VariableMappings[cmStrCat("CMAKE_", compIt->second, "_COMPILER")]; | |
| std::string ret = this->ConvertToOutputForExisting(compilerPath); | |
| std::string const& compilerArg1 = this->VariableMappings[cmStrCat( | |
| "CMAKE_", compIt->second, "_COMPILER_ARG1")]; | |
| std::string const& compilerTarget = this->VariableMappings[cmStrCat( | |
| "CMAKE_", compIt->second, "_COMPILER_TARGET")]; | |
| std::string const& compilerOptionTarget = this->VariableMappings[cmStrCat( | |
| "CMAKE_", compIt->second, "_COMPILE_OPTIONS_TARGET")]; | |
| std::string const& compilerExternalToolchain = | |
| this->VariableMappings[cmStrCat("CMAKE_", compIt->second, | |
| "_COMPILER_EXTERNAL_TOOLCHAIN")]; | |
| std::string const& compilerOptionExternalToolchain = | |
| this->VariableMappings[cmStrCat("CMAKE_", compIt->second, | |
| "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN")]; | |
| std::string const& compilerOptionSysroot = this->VariableMappings[cmStrCat( | |
| "CMAKE_", compIt->second, "_COMPILE_OPTIONS_SYSROOT")]; | |
| if (compIt->second == this->ReplaceValues->Language && | |
| this->ReplaceValues->Launcher) { | |
| // Add launcher as part of expansion so that it always appears | |
| // immediately before the command itself, regardless of whether the | |
| // overall rule template contains other content at the front. | |
| ret = cmStrCat(this->ReplaceValues->Launcher, ' ', std::move(ret)); | |
| } | |
| // if there are required arguments to the compiler add it | |
| // to the compiler string | |
| if (!compilerArg1.empty()) { | |
| ret = cmStrCat(std::move(ret), ' ', compilerArg1); | |
| } | |
| if (!compilerTarget.empty() && !compilerOptionTarget.empty()) { | |
| ret = | |
| cmStrCat(std::move(ret), ' ', compilerOptionTarget, compilerTarget); | |
| } | |
| if (!compilerExternalToolchain.empty() && | |
| !compilerOptionExternalToolchain.empty()) { | |
| ret = cmStrCat(std::move(ret), ' ', compilerOptionExternalToolchain, | |
| this->OutputConverter->EscapeForShell( | |
| compilerExternalToolchain, true)); | |
| } | |
| std::string sysroot; | |
| // Some platforms may use separate sysroots for compiling and linking. | |
| // When the build step is link, pass the link sysroot instead. | |
| if (this->BuildStep == cmBuildStep::Link) { | |
| sysroot = this->LinkerSysroot; | |
| } else { | |
| sysroot = this->CompilerSysroot; | |
| } | |
| if (!sysroot.empty() && !compilerOptionSysroot.empty()) { | |
| ret = cmStrCat(std::move(ret), ' ', compilerOptionSysroot, | |
| this->OutputConverter->EscapeForShell(sysroot, true)); | |
| } | |
| return ret; | |
| } | |
| auto mapIt = this->VariableMappings.find(variable); | |
| if (mapIt != this->VariableMappings.end()) { | |
| if (variable.find("_FLAG") == std::string::npos) { | |
| return this->ConvertToOutputForExisting(mapIt->second); | |
| } | |
| return mapIt->second; | |
| } | |
| return variable; | |
| } | |
| void cmRulePlaceholderExpander::ExpandRuleVariables( | |
| cmOutputConverter* outputConverter, std::string& s, | |
| RuleVariables const& replaceValues) | |
| { | |
| this->OutputConverter = outputConverter; | |
| this->ReplaceValues = &replaceValues; | |
| this->ExpandVariables(s); | |
| } |