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); }
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); }
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); }