XCScheme::XCScheme(const String& absSchemePath, const PBXProject* owner) : m_absPath(absSchemePath), m_parentProject(owner) { // Record the scheme name m_name = sb_fname(sb_basename(m_absPath)); #if defined(_MSC_VER) // Disambiguate scheme names from different users String userDir = sb_basename(sb_dirname(sb_dirname(m_absPath))); if (strEndsWith(userDir, ".xcuserdatad")) m_name = m_name + " (" + sb_fname(userDir) + ")"; #endif }
static VCProjectItem* addFileToVSInternal(const PBXFile* file, VCProject& proj, const BuildSettings& bs, bool isVariant, const VCItemHint* itemHint) { // Add all children of any PBXVariantGroup const PBXVariantGroup* variantGroup = dynamic_cast<const PBXVariantGroup*>(file); if (variantGroup) { const ConstFileList& children = variantGroup->getChildren(); for (auto child : children) { addFileToVSInternal(child, proj, bs, true, itemHint); } return NULL; } // Get the real and virtual paths for the file in Xcode String realPath = file->getFullPath(); String virtualPath = file->getVirtualPath(); // Fix up virtual path for variant files // Resources/MainStoryboard.storyboard/en => Resources/en/MainStoryboard.storyboard if (isVariant) { String variantLang = sb_basename(virtualPath); String filePath = sb_dirname(virtualPath); String fixedDir = joinPaths(sb_dirname(filePath), variantLang); virtualPath = joinPaths(fixedDir, sb_basename(filePath)); } // Compute the VS ItemType for the file String fileType = file->getFileType(); String vsType = getVSItemType(fileType); if (vsType == "Unknown") { if (itemHint && !itemHint->defaultType.empty()) { vsType = itemHint->defaultType; } } // Add the item to the project, taking into account path overrides VCProjectItem* item = NULL; if (itemHint && !itemHint->pathOverride.empty()) { sbAssert(!isVariant, "Unexpected path override for variant file: " + realPath); item = proj.addItem(vsType, itemHint->pathOverride, sb_dirname(virtualPath)); } else { item = addRelativeFilePathToVS(vsType, realPath, sb_dirname(virtualPath), proj, bs); } // Handle Variant files if (isVariant) { String variantDir = sb_basename(sb_dirname(realPath)); item->setDefinition("VariantDir", variantDir); } return item; }
VCProject* SBWorkspace::generateGlueProject() const { // Get a set of all configurations appearing in all projects StringSet slnConfigs; for (auto project : m_openProjects) { const StringSet& configs = project.second->getSelectedConfigurations(); slnConfigs.insert(configs.begin(), configs.end()); } // Get the template VSTemplate* vstemplate = VSTemplate::getTemplate("WinRT"); sbAssertWithTelemetry(vstemplate, "Failed to get WinRT VS template"); // Set up basis template parameters string projectName = getName() + "WinRT"; VSTemplateParameters templateParams; templateParams.setProjectName(projectName); // Expand the template and get the template project vstemplate->expand(sb_dirname(getPath()), templateParams); const VSTemplateProjectVec& projTemplates = vstemplate->getProjects(); sbAssertWithTelemetry(projTemplates.size() == 1, "Unexpected WinRT template size"); // Create the glue project and add it to the solution VCProject* glueProject = new VCProject(projTemplates.front()); // Get path to WinObjC SDK BuildSettings globalBS(NULL); String useRelativeSdkPath = globalBS.getValue("VSIMPORTER_RELATIVE_SDK_PATH"); String sdkDir = globalBS.getValue("WINOBJC_SDK_ROOT"); // Try to create a relative path to the SDK, if requested if (strToUpper(useRelativeSdkPath) == "YES") { String projectDir = sb_dirname(projTemplates.front()->getPath()); sdkDir = getRelativePath(projectDir, sdkDir); } glueProject->addGlobalProperty("WINOBJC_SDK_ROOT", platformPath(sdkDir), "'$(WINOBJC_SDK_ROOT)' == ''"); // Set configuration properties for (auto configName : slnConfigs) { VCProjectConfiguration *projConfig = glueProject->addConfiguration(configName); projConfig->setProperty("TargetName", getName()); } // Set RootNamespace glueProject->addGlobalProperty("RootNamespace", getName()); return glueProject; }
VCProject* SBTarget::constructVCProject(VSTemplateProject* projTemplate) { // Create the project VCProject* proj = new VCProject(projTemplate); // Get path to WinObjC SDK const BuildSettings& projBS = m_parentProject.getBuildSettings(); String useRelativeSdkPath = projBS.getValue("VSIMPORTER_RELATIVE_SDK_PATH"); String sdkDir = projBS.getValue("WINOBJC_SDK_ROOT"); // Try to create a relative path to the SDK, if requested if (strToUpper(useRelativeSdkPath) == "YES") { String projectDir = sb_dirname(projTemplate->getPath()); sdkDir = getRelativePath(projectDir, sdkDir); } proj->addGlobalProperty("WINOBJC_SDK_ROOT", platformPath(sdkDir), "'$(WINOBJC_SDK_ROOT)' == ''"); // Set configuration properties for (auto configBS : m_buildSettings) { VCProjectConfiguration *projConfig = proj->addConfiguration(configBS.first); String productName = configBS.second->getValue("PRODUCT_NAME"); if (!productName.empty()) { projConfig->setProperty("TargetName", productName); } } // Write files associated with each build phase SBBuildPhaseList::const_iterator phaseIt = m_buildPhases.begin(); for (; phaseIt != m_buildPhases.end(); ++phaseIt) (*phaseIt)->writeVCProjectFiles(*proj); return proj; }
void addBuildFileToVS(const PBXBuildFile* buildFile, VCProject& proj, const BuildSettings& bs, const VCItemHint* itemHint) { const String& compilerFlags = buildFile->getCompilerFlags(); int attribs = buildFile->getAttributes(); const PBXFile* file = buildFile->getFile(); if (!file) return; VCProjectItem* item = addFileToVSInternal(file, proj, bs, false, itemHint); // If the filetype doesn't match the file extension, specify the actual type String filePath = file->getFullPath(); String fileType = file->getFileType(); String inferredType = PBXFile::getFileType(filePath); String compileAs = getVSCompileAsType(fileType); if (item && !compileAs.empty() && (fileType != inferredType || fileType == "sourcecode.c.c" || fileType == "sourcecode.cpp.cpp")) { item->setDefinition("CompileAs", compileAs); } // Record file compiler flags if (item && !compilerFlags.empty()) { String fixedFlags = "$(AdditionalOptions) " + compilerFlags; String xcProjectDir = bs.getValue("PROJECT_DIR"); String vsProjectDir = sb_dirname(proj.getPath()); processClangFlags(fixedFlags, xcProjectDir, vsProjectDir); item->setDefinition("AdditionalOptions", fixedFlags); } // Mark public headers if ((attribs & ATTR_PUBLIC) && (fileType == "sourcecode.c.h" || fileType == "sourcecode.cpp.h")) { item->setDefinition("PublicHeader", "true"); } }
VCProject* SBNativeTarget::constructVCProject(VSTemplateProject* projTemplate) { VCProject* proj = SBTarget::constructVCProject(projTemplate); String vsProjDir = sb_dirname(proj->getPath()); // Write variables file for App targets for (auto bs : m_buildSettings) { if (getProductType() == TargetApplication || getProductType() == TargetBundle) { String configName = bs.first; BuildSettings* configBS = bs.second; // Figure out where the file should go String varsFilePath = joinPaths(vsProjDir, getName() + "-" + configName + "-xcvars.txt"); // Open a file stream to write to OFStream varsOut; openOutputFileStream(varsOut, varsFilePath); // Write the build settings out XCConfigPrinter varsPrinter(varsOut); configBS->print(varsPrinter); // Add the variables file to the project VCProjectItem* xcvarsFile = addRelativeFilePathToVS("Text", varsFilePath, "Xcode Variable Files", *proj, *configBS); // Mark the file as non-deployable xcvarsFile->setDefinition("DeploymentContent", "false"); } } return proj; }
std::string VSBuildableSolutionProject::getPath() const { // Return a path relative to the solution directory std::string solutionDir = sb_dirname(m_parent.getPath()); std::string relativePath = getRelativePath(solutionDir, m_project->getPath()); relativePath = winPath(relativePath); return relativePath; }
VCProjectItem* addRelativeFilePathToVS(const String& itemName, const String& filePath, const String& filterPath, VCProject& proj, const BuildSettings& bs) { // Get relative path to file String xcProjectDir = bs.getValue("PROJECT_DIR"); String vsProjectDir = sb_dirname(proj.getPath()); String absFilePath = joinPaths(xcProjectDir, bs.expand(filePath)); String relPath = getRelativePath(vsProjectDir, absFilePath); relPath = winPath(relPath); return proj.addItem(itemName, relPath, filterPath); }
void VCProject::writeProjectReferences(pugi::xml_node& node) const { std::string projectPath = getPath(); std::string projectDir = sb_dirname(projectPath); for (auto dep : m_projectRefs) { std::string depGUID = formatVSGUID(dep->getId()); std::string depRelativePath = getRelativePath(projectDir, dep->getPath()); pugi::xml_node projRef = node.append_child("ProjectReference"); projRef.append_attribute("Include") = depRelativePath.c_str(); appendNodeWithText(projRef, "Project", depGUID); } }
void VCProject::writeSharedProjects(pugi::xml_node& node) const { std::string projectPath = getPath(); std::string projectDir = sb_dirname(projectPath); pugi::xml_node tempNode = node.parent().append_child("Temp"); for (auto sproj : m_sharedProjects) { std::string sprojRelativePath = getRelativePath(projectDir, sproj->getPath()); pugi::xml_node importProj = tempNode.append_child("Import"); importProj.append_attribute("Project") = sprojRelativePath.c_str(); importProj.append_attribute("Label") = "Shared"; } mergeNodes(node, tempNode); }
void openOutputFileStream(OFStream& ofs, const String& outFilePath, OFStream::openmode mode) { // Create directories std::string outputDir = sb_dirname(outFilePath); if (mkpath(outputDir)) { SBLog::warning() << "Failed to create " << outputDir << " output directory path." << std::endl; return; } // Open output file ofs.open(outFilePath.c_str(), mode); if (!ofs.is_open()) { SBLog::warning() << "Failed to open " << outFilePath << " for writing." << std::endl; return; } }
int mkpath(const String& dirPath, mode_t mode) { String parentPath = sb_dirname(dirPath); if (parentPath == "." || parentPath == dirPath) return 0; int rv = 0; if ((mkpath(parentPath, mode) == -1) && (errno != EEXIST)) rv = -1; #if defined(_MSC_VER) if ((rv == 0) && (mkdir(dirPath.c_str()) == -1) && (errno != EEXIST)) #else if ((rv == 0) && (mkdir(dirPath.c_str(), mode) == -1) && (errno != EEXIST)) #endif rv = -1; return (rv); }
VCProject* SBWorkspace::generateGlueProject(bool packageable) const { // Get a set of all configurations appearing in all projects StringSet slnConfigs; for (auto project : m_openProjects) { const StringSet& configs = project.second->getSelectedConfigurations(); slnConfigs.insert(configs.begin(), configs.end()); } // Get the template VSTemplate* vstemplate = VSTemplate::getTemplate("WinRT"); sbAssertWithTelemetry(vstemplate, "Failed to get WinRT VS template"); // Set up basis template parameters string projectName = getName() + "WinRT"; VSTemplateParameters templateParams; templateParams.setProjectName(projectName); templateParams.setIsPackageable(packageable); // Expand the template and get the template project vstemplate->expand(sb_dirname(getPath()), templateParams); const VSTemplateProjectVec& projTemplates = vstemplate->getProjects(); sbAssertWithTelemetry(projTemplates.size() == 1, "Unexpected WinRT template size"); // Create the glue project and add it to the solution VCProject* glueProject = new VCProject(projTemplates.front()); // Set configuration properties for (auto configName : slnConfigs) { VCProjectConfiguration* projConfig = glueProject->addConfiguration(configName); projConfig->setProperty("TargetName", getName()); } // Set RootNamespace glueProject->addGlobalProperty("RootNamespace", getName()); return glueProject; }
static const char* getVsImporterTemplatesDir() { static String templatesDir = joinPaths(sb_dirname(getBinaryLocation()), "../msvc/vsimporter-templates"); return templatesDir.c_str(); }
void SBWorkspace::generateFiles(bool genProjectionsProj, bool genPackagingProj) { // Detect and warn about about any collisions detectProjectCollisions(); // Don't generate packaging project if the solution only contains an app bool solutionContainsPackagebleProject = false; for (auto project : m_openProjects) { solutionContainsPackagebleProject = solutionContainsPackagebleProject || project.second->containsPackagebleProject(); } genPackagingProj = genPackagingProj && solutionContainsPackagebleProject; // Get a set of all configurations appearing in all projects StringSet slnConfigs; for (auto project : m_openProjects) { const StringSet& configs = project.second->getSelectedConfigurations(); slnConfigs.insert(configs.begin(), configs.end()); } // Create a solution BuildSettings globalBS(NULL); String outputFormat = globalBS.getValue("VSIMPORTER_OUTPUT_FORMAT"); String solutionPath = sb_fname(getPath()) + "-" + outputFormat + ".sln"; VSSolution* sln = new VSSolution(solutionPath); // Register all configurations with the solution for (auto configName : slnConfigs) { sln->addConfiguration(configName); } // Construct VS Projects std::multimap<SBTarget*, VCProject*> vcProjects; for (auto project : m_openProjects) { project.second->constructVCProjects(*sln, slnConfigs, vcProjects, genPackagingProj); } VCProject* glueProject = nullptr; if (genProjectionsProj) { // Construct a WinRT projections project glueProject = generateGlueProject(genPackagingProj); sln->addProject(glueProject); } VCProject* packageProject = nullptr; if (genPackagingProj) { // Construct a packaging project packageProject = generatePackageProject(); packageProject->addProjectReference(glueProject); sln->addProject(packageProject); sln->addPlatform("AnyCPU"); // Copy nuget.config into the solution directory String templatesDir = globalBS.getValue("VSIMPORTER_TEMPLATES_DIR"); String nugetConfigSource = joinPaths(templatesDir, "nuget.config"); String nugetConfigDest = joinPaths(sb_dirname(getPath()), "nuget.config"); CopyFile(nugetConfigSource.c_str(), nugetConfigDest.c_str(), false); } // Resolve dependencies for (auto proj : vcProjects) { proj.first->resolveVCProjectDependecies(proj.second, vcProjects); TargetProductType productType = proj.first->getProductType(); // Add a dependency on all static/framework target projects if (glueProject && productType == TargetStaticLib) { glueProject->addProjectReference(proj.second); } // Make the packaging project dependent on all framework components if (packageProject && productType != TargetProductUnknown && productType != TargetApplication) { packageProject->addProjectReference(proj.second); } } // Write solution/projects to disk sbValidateWithTelemetry(!vcProjects.empty(), "No valid targets to import."); sln->write(); }
int main(int argc, char* argv[]) { StringSet targets, configurations, schemes; String sdkRoot, projectPath, xcconfigPath, workspacePath; String logVerbosity("warning"); int projectSet = 0; int workspaceSet = 0; int interactiveFlag = 0; int relativeSdkFlag = 0; int genProjectionsFlag = 0; int allTargets = 0; int allSchemes = 0; int mode = GenerateMode; static struct option long_options[] = { {"version", no_argument, 0, 0}, {"usage", no_argument, 0, 0}, {"help", no_argument, 0, 0}, {"interactive", no_argument, &interactiveFlag, 1}, {"loglevel", required_argument, 0, 0}, {"sdk", required_argument, 0, 0}, {"list", no_argument, &mode, ListMode}, {"project", required_argument, &projectSet, 1}, {"target", required_argument, 0, 0}, {"alltargets", no_argument, &allTargets, 1}, {"configuration", required_argument, 0, 0}, {"xcconfig", required_argument, 0, 0}, {"workspace", required_argument, &workspaceSet, 1}, {"scheme", required_argument, 0, 0}, {"allschemes", required_argument, &allSchemes, 1}, {"relativepath", no_argument, &relativeSdkFlag, 1}, { "genprojections", no_argument, &genProjectionsFlag, 1 }, {0, 0, 0, 0} }; int numOptions = sizeof(long_options) / sizeof(struct option) - 1; while (1) { int option_index = 0; int c = getopt_long_only(argc, argv, "", long_options, &option_index); if (c == -1) { break; } else if (c || option_index < 0 || option_index >= numOptions) { printUsage(argv[0], false); exit(EXIT_FAILURE); } // Process options switch (option_index) { case 0: printVersion(argv[0]); exit(EXIT_SUCCESS); break; case 1: printUsage(argv[0], false); exit(EXIT_SUCCESS); break; case 2: printUsage(argv[0], true); exit(EXIT_SUCCESS); break; case 4: logVerbosity = strToLower(optarg); break; case 5: sdkRoot = optarg; break; case 7: projectPath = optarg; break; case 8: targets.insert(optarg); break; case 10: configurations.insert(optarg); break; case 11: xcconfigPath = optarg; break; case 12: workspacePath = optarg; break; case 13: schemes.insert(optarg); break; default: // Do nothing break; } } // Set AI Telemetry_Init TELEMETRY_INIT(L"AIF-23c336e0-1e7e-43ba-a5ce-eb9dc8a06d34"); if (checkTelemetryOptIn()) { TELEMETRY_ENABLE(); } else { TELEMETRY_DISABLE(); } TELEMETRY_SET_INTERNAL(isMSFTInternalMachine()); String machineID = getMachineID(); if (!machineID.empty()) { TELEMETRY_SET_MACHINEID(machineID.c_str()); } TELEMETRY_EVENT_DATA(L"VSImporterStart", getProductVersion().c_str()); // Process non-option ARGV-elements VariableCollectionManager& settingsManager = VariableCollectionManager::get(); while (optind < argc) { String arg = argv[optind]; if (arg == "/?") { // Due to issue 6715724, flush before exiting TELEMETRY_EVENT_DATA(L"VSImporterIncomplete", "printUsage"); TELEMETRY_FLUSH(); printUsage(argv[0], true); exit(EXIT_SUCCESS); } else if (arg.find_first_of('=') != String::npos) { settingsManager.processGlobalAssignment(arg); } else { sbValidateWithTelemetry(0, "Unsupported argument: " + arg); } optind++; } // Set output format settingsManager.setGlobalVar("VSIMPORTER_OUTPUT_FORMAT", "WinStore10"); // Set logging level SBLogLevel logLevel; if (logVerbosity == "debug") logLevel = SB_DEBUG; else if (logVerbosity == "info") logLevel = SB_INFO; else if (logVerbosity == "warning") logLevel = SB_WARN; else if (logVerbosity == "error") logLevel = SB_ERROR; else if (!logVerbosity.empty()) { sbValidateWithTelemetry(0, "Unrecognized logging verbosity: " + logVerbosity); } SBLog::setVerbosity(logLevel); // Look for a project file in current directory, if one hasn't been explicitly specified if (!projectSet && !workspaceSet) { StringList projects; findFiles(".", "*.xcodeproj", DT_DIR, false, projects); StringList workspaces; findFiles(".", "*.xcworkspace", DT_DIR, false, workspaces); if (!workspaces.empty()) { sbValidateWithTelemetry(workspaces.size() == 1, "Multiple workspaces found. Select the workspace to use with the -workspace option."); workspacePath = workspaces.front(); workspaceSet = 1; } else if (!projects.empty()) { sbValidateWithTelemetry(projects.size() == 1, "Multiple projects found. Select the project to use with the -project option."); projectPath = projects.front(); projectSet = 1; } else { sbValidateWithTelemetry(0, "The current directory does not contain a project or workspace."); } } // Set the architecture String arch = "msvc"; settingsManager.setGlobalVar("ARCHS", arch); settingsManager.setGlobalVar("CURRENT_ARCH", arch); // Make sure workspace arguments are valid if (workspaceSet) { sbValidateWithTelemetry(!projectSet, "Cannot specify both a project and a workspace."); } // Disallow specifying schemes and targets together sbValidateWithTelemetry((schemes.empty() && !allSchemes) || (targets.empty() && !allTargets), "Cannot specify schemes and targets together."); // Process allTargets and allSchemes flags if (allSchemes) schemes.clear(); if (allTargets) targets.clear(); // Initialize global settings String binaryDir = sb_dirname(getBinaryLocation()); sbValidateWithTelemetry(!binaryDir.empty(), "Failed to resolve binary directory."); settingsManager.setGlobalVar("VSIMPORTER_BINARY_DIR", binaryDir); settingsManager.setGlobalVar("VSIMPORTER_INTERACTIVE", interactiveFlag ? "YES" : "NO"); settingsManager.setGlobalVar("VSIMPORTER_RELATIVE_SDK_PATH", relativeSdkFlag ? "YES" : "NO"); if (!sdkRoot.empty()) { sdkRoot = joinPaths(getcwd(), sdkRoot); } else { sdkRoot = joinPaths(binaryDir, ".."); } settingsManager.setGlobalVar("WINOBJC_SDK_ROOT", sdkRoot); // Add useful environment variables to global settings String username; sbValidateWithTelemetry(sb_getenv("USERNAME", username), "Failed to get current username."); settingsManager.setGlobalVar("USER", username); // Read xcconfig file specified from the command line if (!xcconfigPath.empty()) settingsManager.processGlobalConfigFile(xcconfigPath); // Read xcconfig file specified by the XCODE_XCCONFIG_FILE environment variable String xcconfigFile; if (sb_getenv("XCODE_XCCONFIG_FILE", xcconfigFile)) settingsManager.processGlobalConfigFile(xcconfigFile); // Validate WinObjC SDK directory checkWinObjCSDK(); // Create a workspace SBWorkspace *mainWorkspace; if (workspaceSet) { mainWorkspace = SBWorkspace::createFromWorkspace(workspacePath); } else if (projectSet) { mainWorkspace = SBWorkspace::createFromProject(projectPath); } else { sbAssertWithTelemetry(0); // non-reachable } if (mode == ListMode) { mainWorkspace->printSummary(); } else if (mode == GenerateMode) { if (!schemes.empty() || allSchemes) { mainWorkspace->queueSchemes(schemes, configurations); } else { mainWorkspace->queueTargets(targets, configurations); } mainWorkspace->generateFiles(genProjectionsFlag); } else { sbAssertWithTelemetry(0); // non-reachable } TELEMETRY_EVENT_DATA(L"VSImporterComplete", getProductVersion().c_str()); TELEMETRY_FLUSH(); return EXIT_SUCCESS; }
void SBSourcesBuildPhase::writeVCProjectFiles(VCProject& proj) const { // We don't support source compilation when building bundles TargetProductType productType = m_parentTarget.getProductType(); if (productType == TargetBundle) { if (!m_phase->getBuildFileList().empty()) { SBLog::warning() << "Ignoring all source files in \"" << m_parentTarget.getName() << "\" bundle target." << std::endl; } return; } SBBuildPhase::writeVSFileDescriptions(proj, "Text"); String xcProjectDir = m_parentTarget.getProject().getProjectDir(); String vsProjectDir = sb_dirname(proj.getPath()); StringSet prefixHeaders; for (auto bs : m_parentTarget.getBuildSettings()) { VCProjectConfiguration* config = proj.addConfiguration(bs.first); // Prefix header (recalculate relative path) String prefixHeader = bs.second->getValue("GCC_PREFIX_HEADER"); if (!prefixHeader.empty()) { String absHeaderPath = m_parentTarget.makeAbsolutePath(prefixHeader); String relHeaderPath = m_parentTarget.makeRelativePath(prefixHeader, vsProjectDir);; relHeaderPath = winPath(relHeaderPath); config->setItemDefinition("ClangCompile", "PrefixHeader", relHeaderPath); // Add plist file to project (only once) if (prefixHeaders.find(absHeaderPath) == prefixHeaders.end()) { addRelativeFilePathToVS("ClInclude", absHeaderPath, "", proj, *bs.second); prefixHeaders.insert(absHeaderPath); } } // Preprocessor definitions StringVec preprocessorTokens; bs.second->getValue("GCC_PREPROCESSOR_DEFINITIONS", preprocessorTokens); String preprocessorDefs = joinStrings(preprocessorTokens, ";"); if (!preprocessorDefs.empty()) { config->setItemDefinition("ClangCompile", "PreprocessorDefinitions", preprocessorDefs); } // Optimization level String optimizationLevel = bs.second->getValue("GCC_OPTIMIZATION_LEVEL"); if (!optimizationLevel.empty()) { String vsOptimizationLevel; if (optimizationLevel == "s") { vsOptimizationLevel = "MinSpace"; } else if (optimizationLevel == "0") { vsOptimizationLevel = "Disabled"; } else { vsOptimizationLevel = "MaxSpeed"; } config->setItemDefinition("ClangCompile", "OptimizationLevel", vsOptimizationLevel); } // ARC String enableARC = bs.second->getValue("CLANG_ENABLE_OBJC_ARC"); if (enableARC == "YES") { config->setItemDefinition("ClangCompile", "ObjectiveCARC", "true"); } // Modules String enableModules = bs.second->getValue("CLANG_ENABLE_MODULES"); if (enableModules == "YES") { config->setItemDefinition("ClangCompile", "ObjectiveCModules", "true"); } // Header search paths (make them relative) StringVec includePaths; bs.second->getValue("HEADER_SEARCH_PATHS", includePaths); for (auto &cur : includePaths) { cur = m_parentTarget.makeRelativePath(cur, vsProjectDir); cur = winPath(cur); } includePaths.insert(includePaths.begin(), "$(SolutionPublicHeadersDir)"); config->setItemDefinition("ClangCompile", "IncludePaths", joinStrings(includePaths, ";")); // User header search paths (make them relative) StringVec userIncludePaths; bs.second->getValue("USER_HEADER_SEARCH_PATHS", userIncludePaths); for (auto &cur : userIncludePaths) { cur = m_parentTarget.makeRelativePath(cur, vsProjectDir); cur = winPath(cur); } if (!userIncludePaths.empty()) { config->setItemDefinition("ClangCompile", "UserIncludePaths", joinStrings(userIncludePaths, ";")); } // Exclude search path subdirectories StringVec excludeSubDirectories; bs.second->getValue("EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES", excludeSubDirectories); if (!excludeSubDirectories.empty()) { config->setItemDefinition("ClangCompile", "ExcludedSearchPathSubdirectories", joinStrings(excludeSubDirectories, ";")); } // Header map if (bs.second->getValue("USE_HEADERMAP") == "YES") { if (bs.second->getValue("ALWAYS_SEARCH_USER_PATHS") == "YES") { config->setItemDefinition("ClangCompile", "HeaderMap", "Combined"); } else if (bs.second->getValue("HEADERMAP_INCLUDES_PROJECT_HEADERS") == "YES") { config->setItemDefinition("ClangCompile", "HeaderMap", "Project"); } } // Other C flags String otherCFlags = bs.second->getValue("OTHER_CFLAGS"); processClangFlags(otherCFlags, xcProjectDir, vsProjectDir); if (!otherCFlags.empty()) { config->setItemDefinition("ClangCompile", "OtherCFlags", otherCFlags); } // Other C++ flags String otherCPlusPlusFlags = bs.second->getValue("OTHER_CPLUSPLUSFLAGS"); processClangFlags(otherCPlusPlusFlags, xcProjectDir, vsProjectDir); if (!otherCPlusPlusFlags.empty()) { config->setItemDefinition("ClangCompile", "OtherCPlusPlusFlags", otherCPlusPlusFlags); } // CRT String configNameUpper = strToUpper(bs.first); if (configNameUpper.find("DEBUG") != String::npos) { config->setItemDefinition("ClangCompile", "RuntimeLibrary", "MultiThreadedDebugDLL"); } } }
static void recordFilterPath(const std::string& filterPath, StringSet& filterSet) { if (!filterPath.empty() && filterPath != "." && filterSet.insert(filterPath).second) recordFilterPath(sb_dirname(filterPath), filterSet); }