ext::optional<Target::Environment> Target::Environment:: Create(Build::Environment const &buildEnvironment, Build::Context const &buildContext, pbxproj::PBX::Target::shared_ptr const &target) { xcsdk::SDK::Target::shared_ptr sdk; std::vector<std::string> specDomains; pbxproj::XC::BuildConfiguration::shared_ptr projectConfiguration; pbxproj::XC::BuildConfiguration::shared_ptr targetConfiguration; pbxsetting::XC::Config::shared_ptr projectConfigurationFile; pbxsetting::XC::Config::shared_ptr targetConfigurationFile; { // FIXME(grp): $(SRCROOT) must be set in order to find the xcconfig, but we need the xcconfig to know $(SDKROOT). So this can't // use the default level order, because $(SRCROOT) comes below $(SDKROOT). Hack around this for now with a synthetic environment. // It's also in the wrong order because project settings should be below the SDK, but are needed to *load* the xcconfig. pbxsetting::Environment determinationEnvironment = buildEnvironment.baseEnvironment(); determinationEnvironment.insertFront(buildContext.baseSettings(), false); projectConfiguration = ConfigurationNamed(target->project()->buildConfigurationList(), buildContext.configuration()); if (projectConfiguration == nullptr) { fprintf(stderr, "error: unable to find project configuration %s\n", buildContext.configuration().c_str()); return ext::nullopt; } determinationEnvironment.insertFront(target->project()->settings(), false); determinationEnvironment.insertFront(projectConfiguration->buildSettings(), false); pbxsetting::Environment projectActionEnvironment = determinationEnvironment; projectActionEnvironment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { projectActionEnvironment.insertFront(level, false); } projectConfigurationFile = LoadConfigurationFile(projectConfiguration, projectActionEnvironment); if (projectConfigurationFile != nullptr) { determinationEnvironment.insertFront(projectConfigurationFile->level(), false); } targetConfiguration = ConfigurationNamed(target->buildConfigurationList(), buildContext.configuration()); if (targetConfiguration == nullptr) { fprintf(stderr, "error: unable to find target configuration %s\n", buildContext.configuration().c_str()); return ext::nullopt; } determinationEnvironment.insertFront(target->settings(), false); determinationEnvironment.insertFront(targetConfiguration->buildSettings(), false); // FIXME(grp): Similar issue for the target xcconfig. These levels aren't complete (no platform) but are needed to *get* which SDK to use. pbxsetting::Environment targetActionEnvironment = determinationEnvironment; targetActionEnvironment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { targetActionEnvironment.insertFront(level, false); } targetConfigurationFile = LoadConfigurationFile(targetConfiguration, targetActionEnvironment); if (targetConfigurationFile != nullptr) { determinationEnvironment.insertFront(targetConfigurationFile->level(), false); } determinationEnvironment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { determinationEnvironment.insertFront(level, false); } std::string sdkroot = determinationEnvironment.resolve("SDKROOT"); sdk = buildEnvironment.sdkManager()->findTarget(sdkroot); if (sdk == nullptr) { fprintf(stderr, "error: unable to find sdkroot %s\n", sdkroot.c_str()); return ext::nullopt; } specDomains = SDKSpecificationDomains(sdk); } pbxspec::PBX::BuildSystem::shared_ptr buildSystem = TargetBuildSystem(buildEnvironment.specManager(), specDomains, target); if (buildSystem == nullptr) { fprintf(stderr, "error: unable to create build system\n"); return ext::nullopt; } pbxspec::PBX::ProductType::shared_ptr productType = nullptr; pbxspec::PBX::PackageType::shared_ptr packageType = nullptr; if (target->type() == pbxproj::PBX::Target::Type::Native) { pbxproj::PBX::NativeTarget::shared_ptr nativeTarget = std::static_pointer_cast<pbxproj::PBX::NativeTarget>(target); productType = buildEnvironment.specManager()->productType(nativeTarget->productType(), specDomains); if (productType == nullptr) { fprintf(stderr, "error: unable to find product type %s\n", nativeTarget->productType().c_str()); return ext::nullopt; } // FIXME(grp): Should this always use the first package type? if (productType->packageTypes() && !productType->packageTypes()->empty()) { packageType = buildEnvironment.specManager()->packageType(productType->packageTypes()->at(0), specDomains); if (packageType == nullptr) { fprintf(stderr, "error: unable to find package type %s\n", productType->packageTypes()->at(0).c_str()); return ext::nullopt; } } } // Now we have $(SDKROOT), and can make the real levels. pbxsetting::Environment environment = buildEnvironment.baseEnvironment(); environment.insertFront(buildSystem->defaultSettings(), true); environment.insertFront(buildContext.baseSettings(), false); environment.insertFront(pbxsetting::Level({ pbxsetting::Setting::Parse("GCC_VERSION", "$(DEFAULT_COMPILER)"), }), false); environment.insertFront(sdk->platform()->defaultProperties(), false); environment.insertFront(PlatformArchitecturesLevel(buildEnvironment.specManager(), specDomains), false); environment.insertFront(sdk->defaultProperties(), false); environment.insertFront(sdk->platform()->settings(), false); environment.insertFront(sdk->settings(), false); environment.insertFront(sdk->customProperties(), false); environment.insertFront(sdk->platform()->overrideProperties(), false); if (packageType != nullptr) { environment.insertFront(PackageTypeLevel(packageType), false); } if (productType != nullptr) { environment.insertFront(ProductTypeLevel(productType), false); } environment.insertFront(target->project()->settings(), false); if (projectConfigurationFile != nullptr) { environment.insertFront(projectConfigurationFile->level(), false); } environment.insertFront(projectConfiguration->buildSettings(), false); environment.insertFront(target->settings(), false); if (targetConfigurationFile != nullptr) { environment.insertFront(targetConfigurationFile->level(), false); } environment.insertFront(targetConfiguration->buildSettings(), false); environment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { environment.insertFront(level, false); } std::vector<std::string> architectures = ResolveArchitectures(environment); std::vector<std::string> variants = ResolveVariants(environment); environment.insertFront(ArchitecturesVariantsLevel(architectures, variants), false); /* At the target level and below, the SDKROOT changes to always be a SDK path. */ environment.insertFront(pbxsetting::Level({ pbxsetting::Setting::Create("SDKROOT", sdk->path()), }), false); /* Determine toolchains. Must be after the SDK levels are added, so they can be a fallback. */ xcsdk::SDK::Toolchain::vector toolchains; for (std::string const &toolchainName : pbxsetting::Type::ParseList(environment.resolve("TOOLCHAINS"))) { if (xcsdk::SDK::Toolchain::shared_ptr toolchain = buildEnvironment.sdkManager()->findToolchain(toolchainName)) { toolchains.push_back(toolchain); } } /* Tool search directories. Use the toolchains just discovered. */ std::vector<std::string> executablePaths = sdk->executablePaths(toolchains); auto buildRules = std::make_shared<Target::BuildRules>(Target::BuildRules::Create(buildEnvironment.specManager(), specDomains, target)); auto buildFileDisambiguation = BuildFileDisambiguation(target); /* Use the source root, which could have been modified by project options, rather than the raw project path. */ std::string workingDirectory = target->project()->sourceRoot(); Target::Environment te = Target::Environment(); te._sdk = sdk; te._toolchains = toolchains; te._executablePaths = executablePaths; te._buildRules = buildRules; te._environment = std::unique_ptr<pbxsetting::Environment>(new pbxsetting::Environment(environment)); te._variants = variants; te._architectures = architectures; te._buildSystem = buildSystem; te._packageType = packageType; te._productType = productType; te._specDomains = specDomains; te._projectConfigurationFile = projectConfigurationFile; te._targetConfigurationFile = targetConfigurationFile; te._workingDirectory = workingDirectory; te._buildFileDisambiguation = buildFileDisambiguation; return te; }
ext::optional<Target::Environment> Target::Environment:: Create(Build::Environment const &buildEnvironment, Build::Context const &buildContext, pbxproj::PBX::Target::shared_ptr const &target) { /* Use the source root, which could have been modified by project options, rather than the raw project path. */ std::string workingDirectory = target->project()->sourceRoot(); xcsdk::SDK::Target::shared_ptr sdk; std::vector<std::string> specDomains; pbxproj::XC::BuildConfiguration::shared_ptr projectConfiguration; pbxproj::XC::BuildConfiguration::shared_ptr targetConfiguration; ext::optional<pbxsetting::XC::Config> projectConfigurationFile; ext::optional<pbxsetting::XC::Config> targetConfigurationFile; { /* * Create a synthetic build setting environment to determine the SDK to use. The real build * setting environment will interleave in SDK build settings, but those aren't available until * the target SDK is itself determined. */ pbxsetting::Environment determinationEnvironment = pbxsetting::Environment(buildEnvironment.baseEnvironment()); /* * Add build base settings. */ determinationEnvironment.insertFront(buildContext.baseSettings(), false); /* * Add project build settings. */ determinationEnvironment.insertFront(target->project()->settings(), false); projectConfiguration = ConfigurationNamed(target->project()->buildConfigurationList(), buildContext.configuration()); if (projectConfiguration == nullptr) { fprintf(stderr, "error: unable to find project configuration %s\n", buildContext.configuration().c_str()); return ext::nullopt; } projectConfigurationFile = ConfigurationFile(buildContext.workspaceContext(), projectConfiguration); if (projectConfigurationFile) { determinationEnvironment.insertFront(projectConfigurationFile->level(), false); } determinationEnvironment.insertFront(projectConfiguration->buildSettings(), false); /* * Add target build settings. */ determinationEnvironment.insertFront(target->settings(), false); targetConfiguration = ConfigurationNamed(target->buildConfigurationList(), buildContext.configuration()); if (targetConfiguration == nullptr) { fprintf(stderr, "error: unable to find target configuration %s\n", buildContext.configuration().c_str()); return ext::nullopt; } targetConfigurationFile = ConfigurationFile(buildContext.workspaceContext(), targetConfiguration); if (targetConfigurationFile) { determinationEnvironment.insertFront(targetConfigurationFile->level(), false); } determinationEnvironment.insertFront(targetConfiguration->buildSettings(), false); /* * Add build override settings. */ determinationEnvironment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { determinationEnvironment.insertFront(level, false); } /* * All settings added; determine target SDK. */ std::string sdkroot = determinationEnvironment.resolve("SDKROOT"); sdk = buildEnvironment.sdkManager()->findTarget(nullptr, sdkroot); if (sdk == nullptr) { fprintf(stderr, "error: unable to find sdkroot %s\n", sdkroot.c_str()); return ext::nullopt; } specDomains = SDKSpecificationDomains(sdk); } pbxspec::PBX::BuildSystem::shared_ptr buildSystem = TargetBuildSystem(buildEnvironment.specManager(), specDomains, target); if (buildSystem == nullptr) { fprintf(stderr, "error: unable to create build system\n"); return ext::nullopt; } pbxspec::PBX::ProductType::shared_ptr productType = nullptr; pbxspec::PBX::PackageType::shared_ptr packageType = nullptr; if (target->type() == pbxproj::PBX::Target::Type::Native) { pbxproj::PBX::NativeTarget::shared_ptr nativeTarget = std::static_pointer_cast<pbxproj::PBX::NativeTarget>(target); productType = buildEnvironment.specManager()->productType(nativeTarget->productType(), specDomains); if (productType == nullptr) { fprintf(stderr, "error: unable to find product type %s\n", nativeTarget->productType().c_str()); return ext::nullopt; } // FIXME(grp): Should this always use the first package type? if (productType->packageTypes() && !productType->packageTypes()->empty()) { packageType = buildEnvironment.specManager()->packageType(productType->packageTypes()->at(0), specDomains); if (packageType == nullptr) { fprintf(stderr, "error: unable to find package type %s\n", productType->packageTypes()->at(0).c_str()); return ext::nullopt; } } } /* * Now we have $(SDKROOT), and can make the real levels. */ pbxsetting::Environment environment = pbxsetting::Environment(buildEnvironment.baseEnvironment()); environment.insertFront(buildSystem->defaultSettings(), true); environment.insertFront(buildContext.baseSettings(), false); environment.insertFront(pbxsetting::Level({ pbxsetting::Setting::Parse("GCC_VERSION", "$(DEFAULT_COMPILER)"), }), false); if (sdk->platform()->defaultProperties()) { environment.insertFront(*sdk->platform()->defaultProperties(), false); } environment.insertFront(PlatformArchitecturesLevel(buildEnvironment.specManager(), specDomains), false); if (sdk->defaultProperties()) { environment.insertFront(*sdk->defaultProperties(), false); } environment.insertFront(sdk->platform()->settings(), false); environment.insertFront(sdk->settings(), false); if (sdk->customProperties()) { environment.insertFront(*sdk->customProperties(), false); } if (sdk->platform()->overrideProperties()) { environment.insertFront(*sdk->platform()->overrideProperties(), false); } if (packageType != nullptr) { environment.insertFront(PackageTypeLevel(packageType), false); } if (productType != nullptr) { environment.insertFront(ProductTypeLevel(productType), false); } /* * Add project build settings. */ environment.insertFront(target->project()->settings(), false); if (projectConfigurationFile) { environment.insertFront(projectConfigurationFile->level(), false); } environment.insertFront(projectConfiguration->buildSettings(), false); /* * Add target build settings. */ environment.insertFront(target->settings(), false); if (targetConfigurationFile) { environment.insertFront(targetConfigurationFile->level(), false); } environment.insertFront(targetConfiguration->buildSettings(), false); environment.insertFront(buildContext.actionSettings(), false); for (pbxsetting::Level const &level : buildContext.overrideLevels()) { environment.insertFront(level, false); } std::vector<std::string> architectures = ResolveArchitectures(environment); std::vector<std::string> variants = ResolveVariants(environment); environment.insertFront(ArchitecturesVariantsLevel(architectures, variants), false); /* Determine toolchains. Must be after the SDK levels are added, so they can be a fallback. */ std::vector<xcsdk::SDK::Toolchain::shared_ptr> toolchains; std::vector<std::string> effectiveToolchainPaths; for (std::string const &toolchainName : pbxsetting::Type::ParseList(environment.resolve("TOOLCHAINS"))) { if (xcsdk::SDK::Toolchain::shared_ptr toolchain = buildEnvironment.sdkManager()->findToolchain(nullptr, toolchainName)) { // TODO: Apply toolchain override build settings. toolchains.push_back(toolchain); effectiveToolchainPaths.push_back(toolchain->path()); } } environment.insertFront(pbxsetting::Level({ /* At the target level and below, the SDKROOT changes to always be a SDK path. */ pbxsetting::Setting::Create("SDKROOT", sdk->path()), pbxsetting::Setting::Create("EFFECTIVE_TOOLCHAINS_DIRS", pbxsetting::Type::FormatList(effectiveToolchainPaths)), }), false); /* Tool search directories. Use the toolchains just discovered. */ std::shared_ptr<xcsdk::SDK::Manager> const &sdkManager = buildEnvironment.sdkManager(); std::vector<std::string> executablePaths = sdkManager->executablePaths(sdk->platform(), sdk, toolchains); executablePaths.insert(executablePaths.end(), buildEnvironment.baseExecutablePaths().begin(), buildEnvironment.baseExecutablePaths().end()); environment.insertFront(ExecutablePathsLevel(executablePaths), false); auto buildRules = Target::BuildRules::Create(buildEnvironment.specManager(), specDomains, target); auto buildFileDisambiguation = BuildFileDisambiguation(target); return Environment( sdk, toolchains, executablePaths, buildRules, specDomains, buildSystem, productType, packageType, environment, variants, architectures, workingDirectory, buildFileDisambiguation); }
void Tool::HeadermapResolver:: resolve( Tool::Context *toolContext, pbxsetting::Environment const &environment, pbxproj::PBX::Target::shared_ptr const &target ) const { /* Add the compiler default environment, which contains the headermap setting defaults. */ pbxsetting::Environment compilerEnvironment = pbxsetting::Environment(environment); compilerEnvironment.insertFront(_compiler->defaultSettings(), true); if (!pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("USE_HEADERMAP"))) { return; } if (pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("HEADERMAP_USES_VFS"))) { // TODO(grp): Support VFS-based header maps. } HeaderMap targetName; HeaderMap ownTargetHeaders; HeaderMap projectHeaders; HeaderMap allTargetHeaders; HeaderMap allNonFrameworkTargetHeaders; bool includeFlatEntriesForTargetBeingBuilt = pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT")); bool includeFrameworkEntriesForAllProductTypes = pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES")); bool includeProjectHeaders = pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("HEADERMAP_INCLUDES_PROJECT_HEADERS")); // TODO(grp): Populate generated headers. HeaderMap generatedFiles; pbxproj::PBX::Project::shared_ptr project = target->project(); std::vector<std::string> headermapSearchPaths = HeadermapSearchPaths(_specManager, compilerEnvironment, target, toolContext->searchPaths(), toolContext->workingDirectory()); for (std::string const &path : headermapSearchPaths) { Filesystem::GetDefaultUNSAFE()->readDirectory(path, false, [&](std::string const &fileName) -> bool { // TODO(grp): Use FileTypeResolver when reliable. std::string extension = FSUtil::GetFileExtension(fileName); if (extension != "h" && extension != "hpp") { return true; } targetName.add(fileName, path + "/", fileName); return true; }); } for (pbxproj::PBX::FileReference::shared_ptr const &fileReference : project->fileReferences()) { std::string filePath = compilerEnvironment.expand(fileReference->resolve()); pbxspec::PBX::FileType::shared_ptr fileType = FileTypeResolver::Resolve(Filesystem::GetDefaultUNSAFE(), _specManager, { pbxspec::Manager::AnyDomain() }, fileReference, filePath); if (fileType == nullptr || (fileType->identifier() != "sourcecode.c.h" && fileType->identifier() != "sourcecode.cpp.h")) { continue; } std::string fileName = FSUtil::GetBaseName(filePath); std::string fileDirectory = FSUtil::GetDirectoryName(filePath) + "/"; projectHeaders.add(fileName, fileDirectory, fileName); if (includeProjectHeaders) { targetName.add(fileName, fileDirectory, fileName); } } for (pbxproj::PBX::Target::shared_ptr const &projectTarget : project->targets()) { for (pbxproj::PBX::BuildPhase::shared_ptr const &buildPhase : projectTarget->buildPhases()) { if (buildPhase->type() != pbxproj::PBX::BuildPhase::Type::Headers) { continue; } for (pbxproj::PBX::BuildFile::shared_ptr const &buildFile : buildPhase->files()) { if (buildFile->fileRef() == nullptr || buildFile->fileRef()->type() != pbxproj::PBX::GroupItem::Type::FileReference) { continue; } pbxproj::PBX::FileReference::shared_ptr const &fileReference = std::static_pointer_cast <pbxproj::PBX::FileReference> (buildFile->fileRef()); std::string filePath = compilerEnvironment.expand(fileReference->resolve()); pbxspec::PBX::FileType::shared_ptr fileType = FileTypeResolver::Resolve(Filesystem::GetDefaultUNSAFE(), _specManager, { pbxspec::Manager::AnyDomain() }, fileReference, filePath); if (fileType == nullptr || (fileType->identifier() != "sourcecode.c.h" && fileType->identifier() != "sourcecode.cpp.h")) { continue; } std::string fileName = FSUtil::GetBaseName(filePath); std::string fileDirectory = FSUtil::GetDirectoryName(filePath) + "/"; std::string frameworkName = projectTarget->productName() + "/" + fileName; std::vector<std::string> const &attributes = buildFile->attributes(); bool isPublic = std::find(attributes.begin(), attributes.end(), "Public") != attributes.end(); bool isPrivate = std::find(attributes.begin(), attributes.end(), "Private") != attributes.end(); if (projectTarget == target) { ownTargetHeaders.add(fileName, fileDirectory, fileName); if (!isPublic && !isPrivate) { ownTargetHeaders.add(frameworkName, fileDirectory, fileName); if (includeFlatEntriesForTargetBeingBuilt) { targetName.add(frameworkName, fileDirectory, fileName); } } } if (isPublic || isPrivate) { allTargetHeaders.add(frameworkName, fileDirectory, fileName); if (includeFrameworkEntriesForAllProductTypes) { targetName.add(frameworkName, fileDirectory, fileName); } // TODO(grp): This is a little messy. Maybe check the product type specification, or the product reference's file type? if (projectTarget->type() == pbxproj::PBX::Target::Type::Native && std::static_pointer_cast<pbxproj::PBX::NativeTarget>(projectTarget)->productType().find("framework") == std::string::npos) { allNonFrameworkTargetHeaders.add(frameworkName, fileDirectory, fileName); if (!includeFrameworkEntriesForAllProductTypes) { targetName.add(frameworkName, fileDirectory, fileName); } } } } } } std::string headermapFile = compilerEnvironment.resolve("CPP_HEADERMAP_FILE"); std::string headermapFileForOwnTargetHeaders = compilerEnvironment.resolve("CPP_HEADERMAP_FILE_FOR_OWN_TARGET_HEADERS"); std::string headermapFileForAllTargetHeaders = compilerEnvironment.resolve("CPP_HEADERMAP_FILE_FOR_ALL_TARGET_HEADERS"); std::string headermapFileForAllNonFrameworkTargetHeaders = compilerEnvironment.resolve("CPP_HEADERMAP_FILE_FOR_ALL_NON_FRAMEWORK_TARGET_HEADERS"); std::string headermapFileForGeneratedFiles = compilerEnvironment.resolve("CPP_HEADERMAP_FILE_FOR_GENERATED_FILES"); std::string headermapFileForProjectFiles = compilerEnvironment.resolve("CPP_HEADERMAP_FILE_FOR_PROJECT_FILES"); std::vector<Tool::AuxiliaryFile> auxiliaryFiles = { Tool::AuxiliaryFile::Data(headermapFile, targetName.write()), Tool::AuxiliaryFile::Data(headermapFileForOwnTargetHeaders, ownTargetHeaders.write()), Tool::AuxiliaryFile::Data(headermapFileForAllTargetHeaders, allTargetHeaders.write()), Tool::AuxiliaryFile::Data(headermapFileForAllNonFrameworkTargetHeaders, allNonFrameworkTargetHeaders.write()), Tool::AuxiliaryFile::Data(headermapFileForGeneratedFiles, generatedFiles.write()), Tool::AuxiliaryFile::Data(headermapFileForProjectFiles, projectHeaders.write()), }; toolContext->auxiliaryFiles().insert(toolContext->auxiliaryFiles().end(), auxiliaryFiles.begin(), auxiliaryFiles.end()); std::vector<std::string> systemHeadermapFiles; std::vector<std::string> userHeadermapFiles; if (pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("ALWAYS_SEARCH_USER_PATHS")) && !pbxsetting::Type::ParseBoolean(compilerEnvironment.resolve("ALWAYS_USE_SEPARATE_HEADERMAPS"))) { systemHeadermapFiles.push_back(headermapFile); } else { if (includeFlatEntriesForTargetBeingBuilt) { systemHeadermapFiles.push_back(headermapFileForOwnTargetHeaders); } if (includeFrameworkEntriesForAllProductTypes) { systemHeadermapFiles.push_back(headermapFileForAllTargetHeaders); } else { systemHeadermapFiles.push_back(headermapFileForAllNonFrameworkTargetHeaders); } userHeadermapFiles.push_back(headermapFileForGeneratedFiles); if (includeProjectHeaders) { userHeadermapFiles.push_back(headermapFileForProjectFiles); } } Tool::HeadermapInfo *headermapInfo = &toolContext->headermapInfo(); headermapInfo->systemHeadermapFiles().insert(headermapInfo->systemHeadermapFiles().end(), systemHeadermapFiles.begin(), systemHeadermapFiles.end()); headermapInfo->userHeadermapFiles().insert(headermapInfo->userHeadermapFiles().end(), userHeadermapFiles.begin(), userHeadermapFiles.end()); }