void Tool::ScriptResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    pbxproj::PBX::LegacyTarget::shared_ptr const &legacyTarget) const
{
    std::string logMessage = "ExternalBuildToolExecution " + legacyTarget->name();

    std::string script = environment.expand(legacyTarget->buildArgumentsString());

    std::unordered_map<std::string, std::string> environmentVariables;
    if (legacyTarget->passBuildSettingsInEnvironment()) {
        environmentVariables = environment.computeValues(pbxsetting::Condition::Empty());
    }

    std::string fullWorkingDirectory = FSUtil::ResolveRelativePath(legacyTarget->buildWorkingDirectory(), toolContext->workingDirectory());

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(legacyTarget->buildToolPath(), toolContext->executablePaths());
    invocation.arguments() = pbxsetting::Type::ParseList(script);
    invocation.environment() = environmentVariables;
    invocation.workingDirectory() = fullWorkingDirectory;
    invocation.logMessage() = logMessage;
    toolContext->invocations().push_back(invocation);
}
std::vector<std::string> Tool::InterfaceBuilderCommon::
DeploymentTargetArguments(pbxsetting::Environment const &environment)
{
    return {
        "--minimum-deployment-target",
        environment.resolve(environment.resolve("DEPLOYMENT_TARGET_SETTING_NAME")),
    };
}
Exemple #3
0
static void
AppendNotUsedInPrecompsFlags(std::vector<std::string> *args, pbxsetting::Environment const &environment)
{
    std::vector<std::string> preprocessorDefinitions = pbxsetting::Type::ParseList(environment.resolve("GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS"));
    Tool::CompilerCommon::AppendCompoundFlags(args, "-D", true, preprocessorDefinitions);

    std::vector<std::string> otherFlags = pbxsetting::Type::ParseList(environment.resolve("GCC_OTHER_CFLAGS_NOT_USED_IN_PRECOMPS"));
    args->insert(args->end(), otherFlags.begin(), otherFlags.end());
}
Exemple #4
0
static std::vector<std::string>
ResolveArchitectures(pbxsetting::Environment const &environment)
{
    std::vector<std::string> archsVector = pbxsetting::Type::ParseList(environment.resolve("ARCHS"));
    std::set<std::string> archs = std::set<std::string>(archsVector.begin(), archsVector.end());
    std::vector<std::string> validArchsVector = pbxsetting::Type::ParseList(environment.resolve("VALID_ARCHS"));
    std::set<std::string> validArchs = std::set<std::string>(validArchsVector.begin(), validArchsVector.end());

    std::vector<std::string> architectures;
    std::set_intersection(archs.begin(), archs.end(), validArchs.begin(), validArchs.end(), std::back_inserter(architectures));
    return architectures;
}
pbxsetting::Setting Tool::InterfaceBuilderCommon::
TargetedDeviceSetting(pbxsetting::Environment const &environment)
{
    /*
     * Determine the target devices from the environment.
     */
    std::vector<std::string> targetDeviceNames = InterfaceBuilderCommon::TargetedDeviceNames(
        environment.resolve("PLATFORM_NAME"),
        environment.resolve("TARGETED_DEVICE_FAMILY"));

    return pbxsetting::Setting::Create("RESOURCES_TARGETED_DEVICE_FAMILY", pbxsetting::Type::FormatList(targetDeviceNames));
}
void Tool::ScriptResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    pbxproj::PBX::ShellScriptBuildPhase::shared_ptr const &buildPhase) const
{
    pbxsetting::Level level = pbxsetting::Level({
        pbxsetting::Setting::Create("BuildPhaseName", (!buildPhase->name().empty() ? buildPhase->name() : "Run Script")),
        pbxsetting::Setting::Create("BuildPhaseIdentifier", buildPhase->blueprintIdentifier()),
    });

    pbxsetting::Environment phaseEnvironment = environment;
    phaseEnvironment.insertFront(level, false);

    pbxsetting::Value scriptPath = pbxsetting::Value::Parse("$(TEMP_FILES_DIR)/Script-$(BuildPhaseIdentifier).sh");
    pbxsetting::Value logMessage = pbxsetting::Value::Parse("PhaseScriptExecution $(BuildPhaseName:quote) ") + scriptPath;

    std::vector<std::string> inputFiles;
    std::transform(buildPhase->inputPaths().begin(), buildPhase->inputPaths().end(), std::back_inserter(inputFiles), [&](pbxsetting::Value const &input) -> std::string {
        std::string path = environment.expand(input);
        return FSUtil::ResolveRelativePath(path, toolContext->workingDirectory());
    });

    std::vector<std::string> outputFiles;
    std::transform(buildPhase->outputPaths().begin(), buildPhase->outputPaths().end(), std::back_inserter(outputFiles), [&](pbxsetting::Value const &output) -> std::string {
        std::string path = environment.expand(output);
        return FSUtil::ResolveRelativePath(path, toolContext->workingDirectory());
    });

    std::string scriptFilePath = phaseEnvironment.expand(scriptPath);
    std::string contents = (!buildPhase->shellPath().empty() ? "#!" + buildPhase->shellPath() + "\n" : "") + buildPhase->shellScript();
    Tool::Invocation::AuxiliaryFile scriptFile = Tool::Invocation::AuxiliaryFile(scriptFilePath, contents, true);

    pbxsetting::Environment scriptEnvironment = environment;
    scriptEnvironment.insertFront(ScriptInputOutputLevel(inputFiles, outputFiles, true), false);
    std::unordered_map<std::string, std::string> environmentVariables = scriptEnvironment.computeValues(pbxsetting::Condition::Empty());

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/sh");
    invocation.arguments() = { "-c", Escape::Shell(scriptFilePath) };
    invocation.environment() = environmentVariables;
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.phonyInputs() = inputFiles; /* User-specified, may not exist. */
    invocation.outputs() = outputFiles;
    invocation.auxiliaryFiles() = { scriptFile };
    invocation.logMessage() = phaseEnvironment.expand(logMessage);
    invocation.showEnvironmentInLog() = buildPhase->showEnvVarsInLog();
    toolContext->invocations().push_back(invocation);
}
Exemple #7
0
static bool
EvaluateCondition(std::string const &condition, pbxsetting::Environment const &environment)
{
#define WARN_UNHANDLED_CONDITION 0

    // TODO(grp): Evaluate condition expression language correctly.
    std::string expression = environment.expand(pbxsetting::Value::Parse(condition));

    std::string::size_type eq = expression.find(" == ");
    if (eq != std::string::npos) {
        std::string lhs = expression.substr(0, eq);
        std::string rhs = expression.substr(eq + 4);
#if WARN_UNHANDLED_CONDITION
        fprintf(stderr, "warning: unhandled condition evaluation '%s' == '%s'\n", lhs.c_str(), rhs.c_str());
#endif
        return (lhs == rhs);
    }

    std::string::size_type noteq = expression.find(" != ");
    if (noteq != std::string::npos) {
        std::string lhs = expression.substr(0, noteq);
        std::string rhs = expression.substr(noteq + 4);
#if WARN_UNHANDLED_CONDITION
        fprintf(stderr, "warning: unhandled condition evaluation '%s' != '%s'\n", lhs.c_str(), rhs.c_str());
#endif
        return (lhs != rhs);
    }

#if WARN_UNHANDLED_CONDITION
    fprintf(stderr, "warning: unhandled condition evaluation '%s'\n", expression.c_str());
#endif
    return expression != "NO";
}
Exemple #8
0
static void
AppendFrameworkPathFlags(std::vector<std::string> *args, pbxsetting::Environment const &environment, Tool::SearchPaths const &searchPaths)
{
    std::vector<std::string> specialFrameworkPaths = {
        environment.resolve("BUILT_PRODUCTS_DIR"),
    };
    Tool::CompilerCommon::AppendCompoundFlags(args, "-F", true, specialFrameworkPaths);
    Tool::CompilerCommon::AppendCompoundFlags(args, "-F", true, searchPaths.frameworkSearchPaths());
}
Exemple #9
0
static void
AddOptionArgumentValues(std::vector<std::string> *arguments, pbxsetting::Environment const &environment, std::string const &workingDirectory, std::vector<pbxsetting::Value> const &args, pbxspec::PBX::PropertyOption::shared_ptr const &option)
{
    if ((option->type() == "StringList" || option->type() == "stringlist") ||
        (option->type() == "PathList" || option->type() == "pathlist")) {
        std::vector<std::string> values = pbxsetting::Type::ParseList(environment.resolve(option->name()));
        if (option->flattenRecursiveSearchPathsInValue()) {
            values = Tool::SearchPaths::ExpandRecursive(values, environment, workingDirectory);
        }

        for (std::string const &value : values) {
            AddOptionArgumentValue(arguments, environment, args, value);
        }
    } else {
        std::string value = environment.resolve(option->name());
        AddOptionArgumentValue(arguments, environment, args, value);
    }
}
Exemple #10
0
static void
AppendDependencyInfoFlags(std::vector<std::string> *args, pbxspec::PBX::Compiler::shared_ptr const &compiler, pbxsetting::Environment const &environment)
{
    if (compiler->dependencyInfoArgs()) {
        for (pbxsetting::Value const &arg : *compiler->dependencyInfoArgs()) {
            args->push_back(environment.expand(arg));
        }
    }
}
Exemple #11
0
static void
AppendCustomFlags(std::vector<std::string> *args, pbxsetting::Environment const &environment, ext::optional<std::string> const &dialect)
{
    std::vector<std::string> flagSettings;
    flagSettings.push_back("WARNING_CFLAGS");
    flagSettings.push_back("OPTIMIZATION_CFLAGS");
    if (DialectIsCPlusPlus(dialect)) {
        flagSettings.push_back("OTHER_CPLUSPLUSFLAGS");
    } else {
        flagSettings.push_back("OTHER_CFLAGS");
    }
    flagSettings.push_back("OTHER_CFLAGS_" + environment.resolve("CURRENT_VARIANT"));
    flagSettings.push_back("PER_ARCH_CFLAGS_" + environment.resolve("CURRENT_ARCH"));

    for (std::string const &flagSetting : flagSettings) {
        std::vector<std::string> flags = pbxsetting::Type::ParseList(environment.resolve(flagSetting));
        args->insert(args->end(), flags.begin(), flags.end());
    }
}
Exemple #12
0
static pbxsetting::XC::Config::shared_ptr
LoadConfigurationFile(pbxproj::XC::BuildConfiguration::shared_ptr const &buildConfiguration, pbxsetting::Environment const &environment)
{
    if (buildConfiguration->baseConfigurationReference() == nullptr) {
        return nullptr;
    }

    pbxsetting::Value configurationValue = buildConfiguration->baseConfigurationReference()->resolve();
    std::string configurationPath = environment.expand(configurationValue);
    return pbxsetting::XC::Config::Open(configurationPath, environment);
}
Exemple #13
0
static std::string
CompileLogMessage(
    pbxspec::PBX::Compiler::shared_ptr const &compiler,
    std::string const &logTitle,
    std::string const &input,
    pbxspec::PBX::FileType::shared_ptr const &fileType,
    std::string const &output,
    pbxsetting::Environment const &environment,
    std::string const &workingDirectory
)
{
    std::string logMessage;
    logMessage += logTitle + " ";
    logMessage += output + " ";
    logMessage += FSUtil::GetRelativePath(input, workingDirectory) + " ";
    logMessage += environment.resolve("variant") + " ";
    logMessage += environment.resolve("arch") + " ";
    if (fileType->GCCDialectName()) {
        logMessage += *fileType->GCCDialectName() + " ";
    }
    logMessage += compiler->identifier();
    return logMessage;
}
Exemple #14
0
void Tool::ClangResolver::
resolvePrecompiledHeader(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    Tool::PrecompiledHeaderInfo const &precompiledHeaderInfo
) const
{
    std::string const &input = precompiledHeaderInfo.prefixHeader();
    pbxspec::PBX::FileType::shared_ptr const &fileType = precompiledHeaderInfo.fileType();
    std::string output = environment.expand(precompiledHeaderInfo.compileOutputPath());

    pbxspec::PBX::Tool::shared_ptr tool = std::static_pointer_cast <pbxspec::PBX::Tool> (_compiler);
    Tool::Environment toolEnvironment = Tool::Environment::Create(tool, environment, toolContext->workingDirectory(), { input }, { output });
    pbxsetting::Environment const &env = toolEnvironment.environment();
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), fileType);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);

    std::vector<std::string> arguments = precompiledHeaderInfo.arguments();
    AppendDependencyInfoFlags(&arguments, _compiler, env);
    AppendInputOutputFlags(&arguments, _compiler, input, output);

    ext::optional<std::string> const &dialect = fileType->GCCDialectName();
    std::string logTitle = DialectIsCPlusPlus(dialect) ? "ProcessPCH++" : "ProcessPCH";
    std::string logMessage = CompileLogMessage(_compiler, logTitle, input, fileType, output, env, toolContext->workingDirectory());

    auto serializedFile = Tool::Invocation::AuxiliaryFile(
        env.expand(precompiledHeaderInfo.serializedOutputPath()),
        precompiledHeaderInfo.serialize(),
        false);

    std::vector<Tool::Invocation::DependencyInfo> dependencyInfo;
    if (_compiler->dependencyInfoFile()) {
        dependencyInfo.push_back(Tool::Invocation::DependencyInfo(
            dependency::DependencyInfoFormat::Makefile,
            env.expand(*_compiler->dependencyInfoFile())));
    }

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = arguments;
    invocation.environment() = options.environment();
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = toolEnvironment.inputs(toolContext->workingDirectory());
    invocation.outputs() = toolEnvironment.outputs(toolContext->workingDirectory());
    invocation.dependencyInfo() = dependencyInfo;
    invocation.auxiliaryFiles().push_back(serializedFile);
    invocation.logMessage() = logMessage;
    toolContext->invocations().push_back(invocation);
}
Exemple #15
0
static void
ExpandBuildSettings(plist::Object *value, pbxsetting::Environment const &environment)
{
    /*
     * Recursively expand any strings in the plist. Dictionary keys are not expanded.
     */
    if (auto dictionary = plist::CastTo<plist::Dictionary>(value)) {
        for (size_t n = 0; n < dictionary->count(); n++) {
            ExpandBuildSettings(dictionary->value(n), environment);
        }
    } else if (auto array = plist::CastTo<plist::Array>(value)) {
        for (size_t n = 0; n < array->count(); n++) {
            ExpandBuildSettings(array->value(n), environment);
        }
    } else if (auto string = plist::CastTo<plist::String>(value)) {
        pbxsetting::Value parsed = pbxsetting::Value::Parse(string->value());
        string->setValue(environment.expand(parsed));
    }
}
Exemple #16
0
static void
AppendPaths(std::vector<std::string> *args, pbxsetting::Environment const &environment, std::string const &workingDirectory, std::vector<std::string> const &paths)
{
    Filesystem const *filesystem = Filesystem::GetDefaultUNSAFE();

    for (std::string path : paths) {
        // TODO(grp): Is this the right place to insert the SDKROOT? Should all path lists have this, or just *_SEARCH_PATHS?
        std::string const system = "/System";
        std::string const usr    = "******";
        if ((path.size() >= system.size() && path.compare(0, system.size(), system) == 0) ||
            (path.size() >=    usr.size() && path.compare(0,    usr.size(),    usr) == 0)) {
            std::string sdkPath = FSUtil::NormalizePath(environment.resolve("SDKROOT") + path);

            // TODO(grp): Testing if the directory exists seems fragile.
            if (filesystem->type(sdkPath) == Filesystem::Type::Directory) {
                path = sdkPath;
            }
        }

        std::string recursive = "**";
        if (path.size() >= recursive.size() && path.substr(path.size() - recursive.size()) == recursive) {
            std::string root = path.substr(0, path.size() - recursive.size());
            args->push_back(root);

            std::string absoluteRoot = FSUtil::ResolveRelativePath(root, workingDirectory);
            filesystem->readDirectory(absoluteRoot, true, [&](std::string const &relative) -> bool {
                // TODO(grp): Use build settings for included and excluded recursive paths.
                // Included: INCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES
                // Excluded: EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES
                // Follow: RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS

                std::string absolute = absoluteRoot + "/" + relative;
                if (filesystem->type(absolute) == Filesystem::Type::Directory) {
                    args->push_back(root + "/" + relative);
                }
                return true;
            });
        } else {
            args->push_back(path);
        }
    }
}
Exemple #17
0
static std::vector<std::string>
HeadermapSearchPaths(pbxspec::Manager::shared_ptr const &specManager, pbxsetting::Environment const &environment, pbxproj::PBX::Target::shared_ptr const &target, Tool::SearchPaths const &searchPaths, std::string const &workingDirectory)
{
    std::unordered_set<std::string> allHeaderSearchPaths;
    std::vector<std::string> orderedHeaderSearchPaths;

    for (pbxproj::PBX::BuildPhase::shared_ptr const &buildPhase : target->buildPhases()) {
        if (buildPhase->type() != pbxproj::PBX::BuildPhase::Type::Sources) {
            continue;
        }

        for (pbxproj::PBX::BuildFile::shared_ptr const &buildFile : buildPhase->files()) {
            if (buildFile->fileRef() == nullptr) {
                continue;
            }

            std::string filePath = environment.expand(buildFile->fileRef()->resolve());
            std::string fullPath = FSUtil::GetDirectoryName(filePath);
            if (allHeaderSearchPaths.insert(fullPath).second) {
                orderedHeaderSearchPaths.push_back(fullPath);
            }
        }
    }

    for (std::string const &path : searchPaths.userHeaderSearchPaths()) {
        std::string fullPath = FSUtil::ResolveRelativePath(path, workingDirectory);
        if (allHeaderSearchPaths.insert(fullPath).second) {
            orderedHeaderSearchPaths.push_back(fullPath);
        }
    }
    for (std::string const &path : searchPaths.headerSearchPaths()) {
        std::string fullPath = FSUtil::ResolveRelativePath(path, workingDirectory);
        if (allHeaderSearchPaths.insert(fullPath).second) {
            orderedHeaderSearchPaths.push_back(fullPath);
        }
    }

    return orderedHeaderSearchPaths;
}
Exemple #18
0
Tool::SearchPaths Tool::SearchPaths::
Create(pbxsetting::Environment const &environment, std::string const &workingDirectory)
{
    std::vector<std::string> headerSearchPaths;
    AppendPaths(&headerSearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("PRODUCT_TYPE_HEADER_SEARCH_PATHS")));
    AppendPaths(&headerSearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("HEADER_SEARCH_PATHS")));

    std::vector<std::string> userHeaderSearchPaths;
    AppendPaths(&userHeaderSearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("USER_HEADER_SEARCH_PATHS")));

    std::vector<std::string> frameworkSearchPaths;
    AppendPaths(&frameworkSearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("FRAMEWORK_SEARCH_PATHS")));
    AppendPaths(&frameworkSearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("PRODUCT_TYPE_FRAMEWORK_SEARCH_PATHS")));

    std::vector<std::string> librarySearchPaths;
    AppendPaths(&librarySearchPaths, environment, workingDirectory, pbxsetting::Type::ParseList(environment.resolve("LIBRARY_SEARCH_PATHS")));

    return Tool::SearchPaths(headerSearchPaths, userHeaderSearchPaths, frameworkSearchPaths, librarySearchPaths);
}
Exemple #19
0
void Tool::ClangResolver::
resolveSource(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    Phase::File const &input,
    std::string const &outputDirectory) const
{
    Tool::HeadermapInfo const &headermapInfo = toolContext->headermapInfo();

    std::string resolvedOutputDirectory;
    if (_compiler->outputDir()) {
        resolvedOutputDirectory = environment.expand(*_compiler->outputDir());
    } else {
        resolvedOutputDirectory = outputDirectory;
    }

    std::string outputExtension = _compiler->outputFileExtension().value_or("o");

    std::string outputBaseName = FSUtil::GetBaseNameWithoutExtension(input.path());
    if (!input.fileNameDisambiguator().empty()) {
        outputBaseName = input.fileNameDisambiguator();
    }
    std::string output = resolvedOutputDirectory + "/" + outputBaseName + "." + outputExtension;

    pbxspec::PBX::FileType::shared_ptr const &fileType = input.fileType();
    std::vector<std::string> const &inputArguments = input.buildFile()->compilerFlags();

    pbxspec::PBX::Tool::shared_ptr tool = std::static_pointer_cast <pbxspec::PBX::Tool> (_compiler);
    Tool::Environment toolEnvironment = Tool::Environment::Create(tool, environment, toolContext->workingDirectory(), { input }, { output });
    pbxsetting::Environment const &env = toolEnvironment.environment();

    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), fileType);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);

    std::vector<std::string> inputDependencies;
    inputDependencies.insert(inputDependencies.end(), headermapInfo.systemHeadermapFiles().begin(), headermapInfo.systemHeadermapFiles().end());
    inputDependencies.insert(inputDependencies.end(), headermapInfo.userHeadermapFiles().begin(), headermapInfo.userHeadermapFiles().end());

    std::vector<std::string> arguments;
    AppendDialectFlags(&arguments, fileType->GCCDialectName());
    size_t dialectOffset = arguments.size();

    arguments.insert(arguments.end(), tokens.arguments().begin(), tokens.arguments().end());
    Tool::CompilerCommon::AppendIncludePathFlags(&arguments, env, toolContext->searchPaths(), headermapInfo);
    AppendFrameworkPathFlags(&arguments, env, toolContext->searchPaths());
    AppendCustomFlags(&arguments, env, fileType->GCCDialectName());

    bool precompilePrefixHeader = pbxsetting::Type::ParseBoolean(env.resolve("GCC_PRECOMPILE_PREFIX_HEADER"));
    std::string prefixHeader = env.resolve("GCC_PREFIX_HEADER");
    std::shared_ptr<Tool::PrecompiledHeaderInfo> precompiledHeaderInfo = nullptr;

    if (!prefixHeader.empty()) {
        std::string prefixHeaderFile = FSUtil::ResolveRelativePath(prefixHeader, toolContext->workingDirectory());

        if (precompilePrefixHeader) {
            std::vector<std::string> precompiledHeaderArguments;
            AppendDialectFlags(&precompiledHeaderArguments, fileType->GCCDialectName(), "-header");
            precompiledHeaderArguments.insert(precompiledHeaderArguments.end(), arguments.begin() + dialectOffset, arguments.end());
            // Added below, but need to have here in case it affects the precompiled header (as it often does).
            precompiledHeaderArguments.insert(precompiledHeaderArguments.end(), inputArguments.begin(), inputArguments.end());

            precompiledHeaderInfo = std::make_shared<Tool::PrecompiledHeaderInfo>(PrecompiledHeaderInfo::Create(_compiler, prefixHeaderFile, fileType, precompiledHeaderArguments));
            AppendPrefixHeaderFlags(&arguments, env.expand(precompiledHeaderInfo->logicalOutputPath()));
            inputDependencies.push_back(env.expand(precompiledHeaderInfo->compileOutputPath()));
        } else {
            AppendPrefixHeaderFlags(&arguments, prefixHeaderFile);
            inputDependencies.push_back(prefixHeaderFile);
        }
    }

    AppendNotUsedInPrecompsFlags(&arguments, env);
    // After all of the configurable settings, so they can override.
    arguments.insert(arguments.end(), inputArguments.begin(), inputArguments.end());
    AppendDependencyInfoFlags(&arguments, _compiler, env);
    AppendInputOutputFlags(&arguments, _compiler, input.path(), output);

    std::string logMessage = CompileLogMessage(_compiler, "CompileC", input.path(), fileType, output, env, toolContext->workingDirectory());

    std::vector<Tool::Invocation::DependencyInfo> dependencyInfo;
    if (_compiler->dependencyInfoFile()) {
        dependencyInfo.push_back(Tool::Invocation::DependencyInfo(
            dependency::DependencyInfoFormat::Makefile,
            env.expand(*_compiler->dependencyInfoFile())));
    }

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = arguments;
    invocation.environment() = options.environment();
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = toolEnvironment.inputs(toolContext->workingDirectory());
    invocation.outputs() = toolEnvironment.outputs(toolContext->workingDirectory());
    invocation.inputDependencies() = inputDependencies;
    invocation.dependencyInfo() = dependencyInfo;
    invocation.logMessage() = logMessage;

    /* Add the compilation invocation to the context. */
    toolContext->invocations().push_back(invocation);
    auto variantArchitectureKey = std::make_pair(environment.resolve("variant"), environment.resolve("arch"));
    toolContext->variantArchitectureInvocations()[variantArchitectureKey].push_back(invocation);

    Tool::CompilationInfo *compilationInfo = &toolContext->compilationInfo();

    /* If we have precompiled header info, create an invocation for the precompiled header. */
    if (precompiledHeaderInfo != nullptr) {
        std::string hash = precompiledHeaderInfo->hash();

        auto precompiledHeaderInfoMap = &compilationInfo->precompiledHeaderInfo();
        if (precompiledHeaderInfoMap->find(hash) == precompiledHeaderInfoMap->end()) {
            /* This precompiled header wasn't already created, create it now. */
            precompiledHeaderInfoMap->insert({ hash, *precompiledHeaderInfo });

            resolvePrecompiledHeader(
                toolContext,
                environment,
                *precompiledHeaderInfo
            );
        }
    }

    if (DialectIsCPlusPlus(fileType->GCCDialectName()) && _compiler->execCPlusPlusLinkerPath()) {
        /* If a single C++ file is seen, use the C++ linker driver. */
        compilationInfo->linkerDriver() = *_compiler->execCPlusPlusLinkerPath();
    } else if (compilationInfo->linkerDriver().empty() && _compiler->execPath()) {
        /* If a C file is seen after a C++ file, don't reset back to the C driver. */
        compilationInfo->linkerDriver() = _compiler->execPath()->raw();
    }

    for (std::string const &linkerArg : options.linkerArgs()) {
        std::vector<std::string> *linkerArguments = &compilationInfo->linkerArguments();

        /* Avoid duplicating arguments for multiple compiler invocations. */
        if (std::find(linkerArguments->begin(), linkerArguments->end(), linkerArg) == linkerArguments->end()) {
            linkerArguments->push_back(linkerArg);
        }
    }
}
Exemple #20
0
static void
AddBuildEnvironment(plist::Dictionary *root, pbxsetting::Environment const &environment)
{
    root->set("DTCompiler", plist::String::New(environment.resolve("DEFAULT_COMPILER")));
    root->set("DTXcode", plist::String::New(environment.resolve("XCODE_VERSION_ACTUAL")));
    root->set("DTXcodeBuild", plist::String::New(environment.resolve("XCODE_PRODUCT_BUILD_VERSION")));
    root->set("BuildMachineOSBuild", plist::String::New(environment.resolve("MAC_OS_X_PRODUCT_BUILD_VERSION")));

    root->set("DTPlatformName", plist::String::New(environment.resolve("PLATFORM_NAME")));
    root->set("DTPlatformBuild", plist::String::New(environment.resolve("PLATFORM_PRODUCT_BUILD_VERSION")));
    root->set("DTPlatformVersion", plist::String::New("")); // TODO(grp): Not available through build settings.

    root->set("DTSDKName", plist::String::New(environment.resolve("SDK_NAME")));
    root->set("DTSDKBuild", plist::String::New(environment.resolve("SDK_PRODUCT_BUILD_VERSION")));

    root->set("MinimumOSVersion", plist::String::New(environment.resolve(environment.resolve("DEPLOYMENT_TARGET_SETTING_NAME"))));

    std::string targetedDeviceFamily = environment.resolve("TARGETED_DEVICE_FAMILY");
    if (!targetedDeviceFamily.empty()) {
        std::unique_ptr<plist::Array> deviceFamily = plist::Array::New();

        std::string::size_type off = 0;
        do {
            std::string::size_type noff = targetedDeviceFamily.find(',', off);
            std::string entry = (noff == std::string::npos ? targetedDeviceFamily.substr(off) : targetedDeviceFamily.substr(off, noff));

            if (!entry.empty()) {
                int value = pbxsetting::Type::ParseInteger(entry);
                deviceFamily->append(plist::Integer::New(value));
            }

            off = noff;
        } while ((off != std::string::npos) && (off++ < targetedDeviceFamily.size()));

        std::unique_ptr<plist::Object> deviceFamilyObject = std::unique_ptr<plist::Object>(deviceFamily.release());
        root->set("UIDeviceFamily", std::move(deviceFamilyObject));
    }
}
Exemple #21
0
static std::vector<std::string>
ResolveVariants(pbxsetting::Environment const &environment)
{
    return pbxsetting::Type::ParseList(environment.resolve("BUILD_VARIANTS"));
}
Exemple #22
0
Tool::OptionsResult Tool::OptionsResult::
Create(
    pbxsetting::Environment const &environment,
    std::string const &workingDirectory,
    std::vector<pbxspec::PBX::PropertyOption::shared_ptr> const &options,
    pbxspec::PBX::FileType::shared_ptr const &fileType,
    std::unordered_set<std::string> const &deletedSettings)
{
    std::vector<std::string> arguments;
    std::unordered_map<std::string, std::string> environmentVariables;
    std::vector<std::string> linkerArgs;

    std::string architecture = environment.resolve("arch");

    for (pbxspec::PBX::PropertyOption::shared_ptr const &option : options) {
        if (deletedSettings.find(option->name()) != deletedSettings.end()) {
            continue;
        }

        if (option->condition() && !EvaluateCondition(*option->condition(), environment)) {
            continue;
        }
        if (option->commandLineCondition() && !EvaluateCondition(*option->commandLineCondition(), environment)) {
            continue;
        }

        if (option->architectures() && std::find(option->architectures()->begin(), option->architectures()->end(), architecture) == option->architectures()->end()) {
            continue;
        }

        if (option->fileTypes() && fileType != nullptr && std::find(option->fileTypes()->begin(), option->fileTypes()->end(), fileType->identifier()) == option->fileTypes()->end()) {
            continue;
        }

        // TODO(grp): Use PropertyOption::conditionFlavors().
        std::string value = environment.resolve(option->name());

        if (option->type() == "Boolean" || option->type() == "bool") {
            bool booleanValue = pbxsetting::Type::ParseBoolean(value);
            ext::optional<pbxsetting::Value> const &flag = (booleanValue ? option->commandLineFlag() : option->commandLineFlagIfFalse());

            if (flag) {
                /* Boolean flags don't get the flag value after, since that would be just YES or NO. */
                arguments.push_back(environment.expand(*flag));
            }
        } else {
            if (!value.empty()) {
                if (option->commandLineFlag()) {
                    pbxsetting::Value const &flag = *option->commandLineFlag();

                    /* Pass both the command line flag and the option value itself. */
                    std::vector<pbxsetting::Value> values = { flag, pbxsetting::Value::Variable("value") };
                    AddOptionArgumentValues(&arguments, environment, workingDirectory, values, option);
                }
            }
        }

        AddOptionValuesArguments(&arguments, environment, workingDirectory, plist::CastTo<plist::Array>(option->values()), value, option);
        AddOptionValuesArguments(&arguments, environment, workingDirectory, plist::CastTo<plist::Array>(option->allowedValues()), value, option);

        if (!value.empty()) {
            /* Pass the prefix then the option value in the same argument. */
            if (option->commandLinePrefixFlag()) {
                pbxsetting::Value const &prefix = *option->commandLinePrefixFlag();
                pbxsetting::Value prefixValue = prefix + pbxsetting::Value::Variable("value");
                AddOptionArgumentValues(&arguments, environment, workingDirectory, { prefixValue }, option);
            }
        }

        AddOptionArgsArguments(&arguments, environment, workingDirectory, option->commandLineArgs(), value, option);
        AddOptionArgsArguments(&linkerArgs, environment, workingDirectory, option->additionalLinkerArgs(), value, option);

        if (option->setValueInEnvironmentVariable()) {
            std::string const &variable = environment.expand(*option->setValueInEnvironmentVariable());
            environmentVariables.insert({ variable, value });
        }

        // TODO(grp): Use PropertyOption::conditionFlavors().
        // TODO(grp): Use PropertyOption::isCommand{Input,Output}().
        // TODO(grp): Use PropertyOption::isInputDependency(), PropertyOption::outputDependencies().
        // TODO(grp): Use PropertyOption::outputsAreSourceFiles().
    }

    return Tool::OptionsResult(arguments, environmentVariables, linkerArgs);
}