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; }
void SBResourcesBuildPhase::writeVCProjectFiles(VCProject& proj) const { TargetProductType productType = m_parentTarget.getProductType(); if (productType != TargetApplication && productType != TargetBundle) { return; } // Process build files const BuildSettings& projBS = m_parentTarget.getProject().getBuildSettings(); const BuildFileList& buildFiles = m_phase->getBuildFileList(); sbAssert(buildFiles.size() == m_buildFileTargets.size()); for (size_t i = 0; i < buildFiles.size(); i++) { // Construct a path for Bundle build products, relative to the SolutionDir, // instead of using the Xcode path String pathOverride; if (m_buildFileTargets[i]) { String productFileName = sb_basename(buildFiles[i]->getFile()->getFullPath()); String productFileType = buildFiles[i]->getFile()->getFileType(); if (productFileType == "wrapper.cfbundle") { pathOverride = "$(SolutionDir)$(Configuration)\\" + productFileName; } else { SBLog::warning() << "Unexpected build product in ResourceBuildPhase: " << productFileName << std::endl; } } VCItemHint itemHint = { "SBResourceCopy" , pathOverride }; addBuildFileToVS(buildFiles[i], proj, projBS, &itemHint); } // Process all Info.plist files std::map<std::string, VCProjectItem*> infoPlistMap; for (auto bs : m_parentTarget.getBuildSettings()) { VCProjectConfiguration* config = proj.addConfiguration(bs.first); // Exclude all plist from building, by default config->setItemDefinition("SBInfoPlistCopy", "ExcludedFromBuild", "true"); // Get absolute path to plist String plistPath = bs.second->getValue("INFOPLIST_FILE"); plistPath = m_parentTarget.makeAbsolutePath(plistPath); // Add plist file to project (only once) if (infoPlistMap.find(plistPath) == infoPlistMap.end()) { infoPlistMap[plistPath] = addRelativeFilePathToVS("SBInfoPlistCopy", plistPath, "", proj, *bs.second); } // Un-exclude building plist for configuration String condition = "'$(Configuration)'=='" + bs.first + "'"; infoPlistMap[plistPath]->setDefinition("ExcludedFromBuild", "false", condition); // Specify which variables files to use String varsFile = m_parentTarget.getName() + "-" + bs.first + "-xcvars.txt"; infoPlistMap[plistPath]->setDefinition("VariableFile", varsFile, condition); } }
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; }
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"); } } }