std::vector<std::string> Tool::InterfaceBuilderCommon:: DeploymentTargetArguments(pbxsetting::Environment const &environment) { return { "--minimum-deployment-target", environment.resolve(environment.resolve("DEPLOYMENT_TARGET_SETTING_NAME")), }; }
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()); }
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)); }
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); } }
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()); }
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()); } }
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; }
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); } } }
static std::vector<std::string> ResolveVariants(pbxsetting::Environment const &environment) { return pbxsetting::Type::ParseList(environment.resolve("BUILD_VARIANTS")); }
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); }
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); }
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); } } }
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)); } }