/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmRulePlaceholderExpander.h" #include #include "cmOutputConverter.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" cmRulePlaceholderExpander::cmRulePlaceholderExpander( std::map compilers, std::map variableMappings, std::string compilerSysroot, std::string linkerSysroot) : Compilers(std::move(compilers)) , VariableMappings(std::move(variableMappings)) , CompilerSysroot(std::move(compilerSysroot)) , LinkerSysroot(std::move(linkerSysroot)) { } std::string cmRulePlaceholderExpander::ExpandVariable( std::string const& variable) { if (this->ReplaceValues->LinkFlags) { if (variable == "LINK_FLAGS") { return this->ReplaceValues->LinkFlags; } } 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->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->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 = '\"'; targetQuoted += this->ReplaceValues->Target; targetQuoted += '\"'; } 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 (variable == "CMAKE_COMMAND") { return this->OutputConverter->ConvertToOutputFormat( cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL); } auto compIt = this->Compilers.find(variable); if (compIt != this->Compilers.end()) { std::string ret = this->OutputConverter->ConvertToOutputForExisting( this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER"]); std::string const& compilerArg1 = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_ARG1"]; std::string const& compilerTarget = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_TARGET"]; std::string const& compilerOptionTarget = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILE_OPTIONS_TARGET"]; std::string const& compilerExternalToolchain = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILER_EXTERNAL_TOOLCHAIN"]; std::string const& compilerOptionExternalToolchain = this->VariableMappings["CMAKE_" + compIt->second + "_COMPILE_OPTIONS_EXTERNAL_TOOLCHAIN"]; std::string const& compilerOptionSysroot = this->VariableMappings["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, " ", ret); } // if there are required arguments to the compiler add it // to the compiler string if (!compilerArg1.empty()) { ret += " "; ret += compilerArg1; } if (!compilerTarget.empty() && !compilerOptionTarget.empty()) { ret += " "; ret += compilerOptionTarget; ret += compilerTarget; } if (!compilerExternalToolchain.empty() && !compilerOptionExternalToolchain.empty()) { ret += " "; ret += compilerOptionExternalToolchain; ret += this->OutputConverter->EscapeForShell(compilerExternalToolchain, true); } std::string sysroot; // Some platforms may use separate sysroots for compiling and linking. // If we detect link flags, then we pass the link sysroot instead. // FIXME: Use a more robust way to detect link line expansion. if (this->ReplaceValues->LinkFlags) { sysroot = this->LinkerSysroot; } else { sysroot = this->CompilerSysroot; } if (!sysroot.empty() && !compilerOptionSysroot.empty()) { ret += " "; ret += compilerOptionSysroot; ret += 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) { std::string ret = this->OutputConverter->ConvertToOutputForExisting(mapIt->second); if (this->ReplaceValues->Launcher && variable == "CMAKE_LINKER") { // 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, " ", ret); } return ret; } return mapIt->second; } return variable; } void cmRulePlaceholderExpander::ExpandRuleVariables( cmOutputConverter* outputConverter, std::string& s, const RuleVariables& replaceValues) { this->OutputConverter = outputConverter; this->ReplaceValues = &replaceValues; this->ExpandVariables(s); }