
Swift is used as the linker for non-swift files because it needs to pull files like swiftrt.o in when swift symbols are present to ensure that the swift runtime is linked. The swift driver uses clang as the underlying linker, which pulls in crtbegin.o and friends when appropriate, so using Swift as a linker for C/C++ libraries is fine. The output-file-map was getting passed to all Swift invocations, regardless of whether or not we generated one. This patch changes it so that we only include the output-file-map in the Swift compiler invocation if we have actually generated the file.
354 lines
11 KiB
C++
354 lines
11 KiB
C++
/* 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 <utility>
|
|
|
|
#include "cmOutputConverter.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
cmRulePlaceholderExpander::cmRulePlaceholderExpander(
|
|
std::map<std::string, std::string> compilers,
|
|
std::map<std::string, std::string> 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);
|
|
}
|