Example #1
0
void Tool::ToolResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    std::vector<Phase::File> const &inputs,
    std::string const &outputDirectory,
    std::string const &logMessage) const
{
    Tool::Environment toolEnvironment = Tool::Environment::Create(_tool, environment, toolContext->workingDirectory(), inputs);
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), nullptr);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);
    std::string const &resolvedLogMessage = (!logMessage.empty() ? logMessage : tokens.logMessage());

    std::vector<Tool::Invocation::DependencyInfo> dependencyInfo;
    if (_tool->deeplyStatInputDirectories()) {
        for (Phase::File const &input : inputs) {
            /* Create a dependency info file to track the input directory contents. */
            auto info = Tool::Invocation::DependencyInfo(dependency::DependencyInfoFormat::Directory, input.path());
            dependencyInfo.push_back(info);
        }
    }

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = tokens.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.logMessage() = resolvedLogMessage;
    toolContext->invocations().push_back(invocation);
}
void Tool::SwiftStandardLibraryResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &baseEnvironment,
    std::string const &executable,
    std::vector<std::string> const &directories) const
{
    pbxsetting::Level level = pbxsetting::Level({
        pbxsetting::Setting::Create("SWIFT_STDLIB_TOOL_FOLDERS_TO_SCAN", pbxsetting::Type::FormatList(directories)),
    });
    pbxsetting::Environment env = baseEnvironment;
    env.insertFront(level, false);

    std::string outputPath = env.resolve("TARGET_BUILD_DIR") + "/" + env.resolve("FULL_PRODUCT_NAME");

    Tool::Environment toolEnvironment = Tool::Environment::Create(_tool, env, toolContext->workingDirectory(), { executable }, { outputPath });
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), nullptr);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = tokens.arguments();
    invocation.environment() = options.environment();
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = toolEnvironment.inputs(toolContext->workingDirectory());
    invocation.outputs() = { }; // TODO(grp): Outputs are not known at build time.
    invocation.logMessage() = tokens.logMessage();
    toolContext->invocations().push_back(invocation);
}
Example #3
0
void Tool::ToolResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &environment,
    std::vector<std::string> const &inputs,
    std::vector<std::string> const &outputs,
    std::string const &logMessage) const
{
    Tool::Environment toolEnvironment = Tool::Environment::Create(_tool, environment, toolContext->workingDirectory(), inputs, outputs);
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), nullptr);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);
    std::string const &resolvedLogMessage = (!logMessage.empty() ? logMessage : tokens.logMessage());

    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = tokens.arguments();
    invocation.environment() = options.environment();
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = toolEnvironment.inputs(toolContext->workingDirectory());
    invocation.outputs() = toolEnvironment.outputs(toolContext->workingDirectory());
    invocation.logMessage() = resolvedLogMessage;
    toolContext->invocations().push_back(invocation);
}
Example #4
0
void Tool::AssetCatalogResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &baseEnvironment,
    std::vector<Tool::Input> const &inputs) const
{
    std::vector<std::string> absoluteInputPaths;
    std::vector<std::string> assetPaths;
    std::vector<std::string> stickerPackStrings;
    for (Tool::Input const &input : inputs) {
        if (input.fileType() != nullptr && input.fileType()->identifier() == "text.plist.strings") {
            std::string strings;
            strings += FSUtil::GetBaseNameWithoutExtension(input.path());
            strings += ":";
            strings += input.localization().value_or("");
            strings += ":";
            strings += input.path();
            stickerPackStrings.push_back(strings);
        } else {
            assetPaths.push_back(input.path());
        }

        std::string absoluteInputPath = FSUtil::ResolveRelativePath(input.path(), toolContext->workingDirectory());
        absoluteInputPaths.push_back(absoluteInputPath);
    }

    /*
     * Create the custom environment with the tool options.
     */
    pbxsetting::Level level = pbxsetting::Level({
        InterfaceBuilderCommon::TargetedDeviceSetting(baseEnvironment),
        pbxsetting::Setting::Create("ASSETCATALOG_COMPILER_INPUTS", pbxsetting::Type::FormatList(assetPaths)),
        pbxsetting::Setting::Create("ASSETCATALOG_COMPILER_STICKER_PACK_STRINGS", pbxsetting::Type::FormatList(stickerPackStrings)),
    });
    pbxsetting::Environment assetCatalogEnvironment = pbxsetting::Environment(baseEnvironment);
    assetCatalogEnvironment.insertFront(level, false);

    /*
     * Resolve the tool options.
     */
    Tool::Environment toolEnvironment = Tool::Environment::Create(_tool, assetCatalogEnvironment, toolContext->workingDirectory(), std::vector<Tool::Input>());
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), nullptr);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);

    pbxsetting::Environment const &environment = toolEnvironment.environment();

    /*
     * Create tool outputs.
     */
    std::vector<std::string> outputs = {
        /* Creates the asset catalog, always in the resources dir. */
        environment.expand(pbxsetting::Value::Parse("$(ProductResourcesDir)/Assets.car")),
    };

    /*
     * Add custom arguments to the end.
     */
    std::vector<std::string> arguments = tokens.arguments();
    arguments.push_back("--platform");
    arguments.push_back(environment.resolve("PLATFORM_NAME"));
    std::vector<std::string> deploymentTargetArguments = InterfaceBuilderCommon::DeploymentTargetArguments(environment);
    arguments.insert(arguments.end(), deploymentTargetArguments.begin(), deploymentTargetArguments.end());

    // TODO(grp): This is a hack to work around missing `Condition` support in options.
    arguments.erase(std::remove(arguments.begin(), arguments.end(), "--optimization"), arguments.end());
    arguments.erase(std::remove(arguments.begin(), arguments.end(), ""), arguments.end());

    // TODO(grp): This should be handled generically for all tools.
    if (_tool->generatedInfoPlistContentFilePath()) {
        std::string infoPlistContent = environment.expand(*_tool->generatedInfoPlistContentFilePath());
        toolContext->additionalInfoPlistContents().push_back(infoPlistContent);
        outputs.push_back(infoPlistContent);
    }

    // TODO(grp): This should be handled generically for all tools.
    std::vector<Tool::Invocation::DependencyInfo> dependencyInfo;
    if (_tool->dependencyInfoFile()) {
        dependencyInfo.push_back(Tool::Invocation::DependencyInfo(
            dependency::DependencyInfoFormat::Binary,
            environment.expand(*_tool->dependencyInfoFile())));
    }
    if (_tool->deeplyStatInputDirectories()) {
        for (Tool::Input const &input : inputs) {
            /* Create a dependency info file to track the input directory contents. */
            auto info = Tool::Invocation::DependencyInfo(dependency::DependencyInfoFormat::Directory, input.path());
            dependencyInfo.push_back(info);
        }
    }

    /*
     * Create the asset catalog invocation.
     */
    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable());
    invocation.arguments() = arguments;
    invocation.environment() = options.environment();
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = absoluteInputPaths;
    invocation.outputs() = outputs;
    invocation.dependencyInfo() = dependencyInfo;
    invocation.logMessage() = tokens.logMessage();
    invocation.priority() = toolContext->currentPhaseInvocationPriority();
    toolContext->invocations().push_back(invocation);
}
void Tool::InterfaceBuilderResolver::
resolve(
    Tool::Context *toolContext,
    pbxsetting::Environment const &baseEnvironment,
    std::vector<Phase::File> const &inputs) const
{
    /*
     * Filter arguments as either a real input or a localization-specific strings file.
     */
    std::vector<Phase::File> primaryInputs;
    std::vector<std::string> localizationStringsFiles;
    for (Phase::File const &input : inputs) {
        if (input.fileType()->identifier() == "text.plist.strings") {
            /* The format here is as expected by ibtool. */
            localizationStringsFiles.push_back(input.localization() + ":" + input.path());
        } else {
            primaryInputs.push_back(input);
        }
    }

    /*
     * Create the custom environment with the needed options.
     */
    pbxsetting::Level level = pbxsetting::Level({
        InterfaceBuilderCommon::TargetedDeviceSetting(baseEnvironment),
        pbxsetting::Setting::Create("IBC_REGIONS_AND_STRINGS_FILES", pbxsetting::Type::FormatList(localizationStringsFiles)),
    });
    pbxsetting::Environment interfaceBuilderEnvironment = baseEnvironment;
    interfaceBuilderEnvironment.insertFront(level, false);

    /*
     * Resolve the tool options.
     */
    Tool::Environment toolEnvironment = Tool::Environment::Create(_tool, interfaceBuilderEnvironment, toolContext->workingDirectory(), primaryInputs);
    Tool::OptionsResult options = Tool::OptionsResult::Create(toolEnvironment, toolContext->workingDirectory(), nullptr);
    Tool::Tokens::ToolExpansions tokens = Tool::Tokens::ExpandTool(toolEnvironment, options);

    pbxsetting::Environment const &environment = toolEnvironment.environment();

    /*
     * Add custom arguments to the end.
     */
    std::vector<std::string> arguments = tokens.arguments();
    std::vector<std::string> deploymentTargetArguments = InterfaceBuilderCommon::DeploymentTargetArguments(environment);
    arguments.insert(arguments.end(), deploymentTargetArguments.begin(), deploymentTargetArguments.end());

    // TODO(grp): Invocations must emit all their outputs for now, but ibtool can emit both general
    // and device-specific (e.g. ~iphone, ~ipad) variants. For now, assume all files are not variant.
    std::vector<std::string> outputs = toolEnvironment.outputs();
    if (_tool->mightNotEmitAllOutputs() && !outputs.empty()) {
        outputs = { outputs.front() };
    }

    // TODO(grp): These should be handled generically for all tools.
    std::unordered_map<std::string, std::string> environmentVariables = options.environment();
    if (_tool->environmentVariables()) {
        for (auto const &variable : *_tool->environmentVariables()) {
            environmentVariables.insert({ variable.first, environment.expand(variable.second) });
        }
    }

    // TODO(grp): This should be handled generically for all tools.
    if (_tool->generatedInfoPlistContentFilePath()) {
        std::string infoPlistContent = environment.expand(*_tool->generatedInfoPlistContentFilePath());
        toolContext->additionalInfoPlistContents().push_back(infoPlistContent);
        outputs.push_back(infoPlistContent);
    }

    /*
     * Create the invocation.
     */
    Tool::Invocation invocation;
    invocation.executable() = Tool::Invocation::Executable::Determine(tokens.executable(), toolContext->executablePaths());
    invocation.arguments() = arguments;
    invocation.environment() = environmentVariables;
    invocation.workingDirectory() = toolContext->workingDirectory();
    invocation.inputs() = toolEnvironment.inputs(toolContext->workingDirectory());
    invocation.outputs() = outputs;
    invocation.logMessage() = tokens.logMessage();
    toolContext->invocations().push_back(invocation);
}