1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-06-22 12:31:22 +08:00
CMake/Source/cmRulePlaceholderExpander.cxx
Saleem Abdulrasool 001446126e Ninja: add final placeholders to merge Swift partials
This adds the placeholders that are needed to merge the swift partial
modules.  It permits generating the rules necessary to actually merge
the partial modules emitted for a partial compilation.
2019-02-20 09:25:34 -08:00

359 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 <ctype.h>
#include <string.h>
#include <utility>
#include "cmOutputConverter.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))
{
}
cmRulePlaceholderExpander::RuleVariables::RuleVariables()
{
memset(this, 0, sizeof(*this));
}
std::string cmRulePlaceholderExpander::ExpandRuleVariable(
cmOutputConverter* outputConverter, std::string const& variable,
const RuleVariables& replaceValues)
{
if (replaceValues.LinkFlags) {
if (variable == "LINK_FLAGS") {
return replaceValues.LinkFlags;
}
}
if (replaceValues.Manifests) {
if (variable == "MANIFESTS") {
return replaceValues.Manifests;
}
}
if (replaceValues.Flags) {
if (variable == "FLAGS") {
return replaceValues.Flags;
}
}
if (replaceValues.Source) {
if (variable == "SOURCE") {
return replaceValues.Source;
}
}
if (replaceValues.PreprocessedSource) {
if (variable == "PREPROCESSED_SOURCE") {
return replaceValues.PreprocessedSource;
}
}
if (replaceValues.AssemblySource) {
if (variable == "ASSEMBLY_SOURCE") {
return replaceValues.AssemblySource;
}
}
if (replaceValues.Object) {
if (variable == "OBJECT") {
return replaceValues.Object;
}
}
if (replaceValues.ObjectDir) {
if (variable == "OBJECT_DIR") {
return replaceValues.ObjectDir;
}
}
if (replaceValues.ObjectFileDir) {
if (variable == "OBJECT_FILE_DIR") {
return replaceValues.ObjectFileDir;
}
}
if (replaceValues.Objects) {
if (variable == "OBJECTS") {
return replaceValues.Objects;
}
}
if (replaceValues.ObjectsQuoted) {
if (variable == "OBJECTS_QUOTED") {
return replaceValues.ObjectsQuoted;
}
}
if (replaceValues.Defines && variable == "DEFINES") {
return replaceValues.Defines;
}
if (replaceValues.Includes && variable == "INCLUDES") {
return replaceValues.Includes;
}
if (replaceValues.TargetPDB) {
if (variable == "TARGET_PDB") {
return replaceValues.TargetPDB;
}
}
if (replaceValues.TargetCompilePDB) {
if (variable == "TARGET_COMPILE_PDB") {
return replaceValues.TargetCompilePDB;
}
}
if (replaceValues.DependencyFile) {
if (variable == "DEP_FILE") {
return replaceValues.DependencyFile;
}
}
if (replaceValues.Target) {
if (variable == "TARGET_QUOTED") {
std::string targetQuoted = replaceValues.Target;
if (!targetQuoted.empty() && targetQuoted.front() != '\"') {
targetQuoted = '\"';
targetQuoted += replaceValues.Target;
targetQuoted += '\"';
}
return targetQuoted;
}
if (variable == "TARGET_UNQUOTED") {
std::string unquoted = 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 (replaceValues.LanguageCompileFlags) {
if (variable == "LANGUAGE_COMPILE_FLAGS") {
return replaceValues.LanguageCompileFlags;
}
}
if (replaceValues.Target) {
if (variable == "TARGET") {
return replaceValues.Target;
}
}
if (variable == "TARGET_IMPLIB") {
return this->TargetImpLib;
}
if (variable == "TARGET_VERSION_MAJOR") {
if (replaceValues.TargetVersionMajor) {
return replaceValues.TargetVersionMajor;
}
return "0";
}
if (variable == "TARGET_VERSION_MINOR") {
if (replaceValues.TargetVersionMinor) {
return replaceValues.TargetVersionMinor;
}
return "0";
}
if (replaceValues.Target) {
if (variable == "TARGET_BASE") {
// Strip the last extension off the target name.
std::string targetBase = replaceValues.Target;
std::string::size_type pos = targetBase.rfind('.');
if (pos != std::string::npos) {
return targetBase.substr(0, pos);
}
return targetBase;
}
}
}
if (replaceValues.SwiftAuxiliarySources) {
if (variable == "SWIFT_AUXILIARY_SOURCES") {
return replaceValues.SwiftAuxiliarySources;
}
}
if (replaceValues.SwiftModuleName) {
if (variable == "SWIFT_MODULE_NAME") {
return replaceValues.SwiftModuleName;
}
}
if (replaceValues.SwiftLibraryName) {
if (variable == "SWIFT_LIBRARY_NAME") {
return replaceValues.SwiftLibraryName;
}
}
if (replaceValues.SwiftPartialDoc) {
if (variable == "SWIFT_PARTIAL_DOC") {
return replaceValues.SwiftPartialDoc;
}
}
if (replaceValues.SwiftPartialModule) {
if (variable == "SWIFT_PARTIAL_MODULE") {
return replaceValues.SwiftPartialModule;
}
}
if (replaceValues.SwiftPartialModules) {
if (variable == "SWIFT_PARTIAL_MODULES") {
return replaceValues.SwiftPartialModules;
}
}
if (replaceValues.TargetSwiftDoc) {
if (variable == "TARGET_SWIFT_DOC") {
return replaceValues.TargetSwiftDoc;
}
}
if (replaceValues.TargetSwiftModule) {
if (variable == "TARGET_SWIFT_MODULE") {
return replaceValues.TargetSwiftModule;
}
}
if (variable == "TARGET_SONAME" || variable == "SONAME_FLAG" ||
variable == "TARGET_INSTALLNAME_DIR") {
// All these variables depend on TargetSOName
if (replaceValues.TargetSOName) {
if (variable == "TARGET_SONAME") {
return replaceValues.TargetSOName;
}
if (variable == "SONAME_FLAG" && replaceValues.SONameFlag) {
return replaceValues.SONameFlag;
}
if (replaceValues.TargetInstallNameDir &&
variable == "TARGET_INSTALLNAME_DIR") {
return replaceValues.TargetInstallNameDir;
}
}
return "";
}
if (replaceValues.LinkLibraries) {
if (variable == "LINK_LIBRARIES") {
return replaceValues.LinkLibraries;
}
}
if (replaceValues.Language) {
if (variable == "LANGUAGE") {
return replaceValues.Language;
}
}
if (replaceValues.CMTargetName) {
if (variable == "TARGET_NAME") {
return replaceValues.CMTargetName;
}
}
if (replaceValues.CMTargetType) {
if (variable == "TARGET_TYPE") {
return replaceValues.CMTargetType;
}
}
if (replaceValues.Output) {
if (variable == "OUTPUT") {
return replaceValues.Output;
}
}
if (variable == "CMAKE_COMMAND") {
return outputConverter->ConvertToOutputFormat(
cmSystemTools::CollapseFullPath(cmSystemTools::GetCMakeCommand()),
cmOutputConverter::SHELL);
}
std::map<std::string, std::string>::iterator compIt =
this->Compilers.find(variable);
if (compIt != this->Compilers.end()) {
std::string ret = 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 there is a required first argument 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 += 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 (replaceValues.LinkFlags) {
sysroot = this->LinkerSysroot;
} else {
sysroot = this->CompilerSysroot;
}
if (!sysroot.empty() && !compilerOptionSysroot.empty()) {
ret += " ";
ret += compilerOptionSysroot;
ret += outputConverter->EscapeForShell(sysroot, true);
}
return ret;
}
std::map<std::string, std::string>::iterator mapIt =
this->VariableMappings.find(variable);
if (mapIt != this->VariableMappings.end()) {
if (variable.find("_FLAG") == std::string::npos) {
return outputConverter->ConvertToOutputForExisting(mapIt->second);
}
return mapIt->second;
}
return variable;
}
void cmRulePlaceholderExpander::ExpandRuleVariables(
cmOutputConverter* outputConverter, std::string& s,
const RuleVariables& replaceValues)
{
std::string::size_type start = s.find('<');
// no variables to expand
if (start == std::string::npos) {
return;
}
std::string::size_type pos = 0;
std::string expandedInput;
while (start != std::string::npos && start < s.size() - 2) {
std::string::size_type end = s.find('>', start);
// if we find a < with no > we are done
if (end == std::string::npos) {
return;
}
char c = s[start + 1];
// if the next char after the < is not A-Za-z then
// skip it and try to find the next < in the string
if (!isalpha(c)) {
start = s.find('<', start + 1);
} else {
// extract the var
std::string var = s.substr(start + 1, end - start - 1);
std::string replace =
this->ExpandRuleVariable(outputConverter, var, replaceValues);
expandedInput += s.substr(pos, start - pos);
expandedInput += replace;
// move to next one
start = s.find('<', start + var.size() + 2);
pos = end + 1;
}
}
// add the rest of the input
expandedInput += s.substr(pos, s.size() - pos);
s = expandedInput;
}