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; }
SBWorkspace* SBWorkspace::createFromWorkspace(const String& workspaceDir) { sbAssertWithTelemetry(!s_workspace, "Workspace already exists"); // Create the workspace s_workspace = new SBWorkspace(); s_workspace->m_workspace = XCWorkspace::createFromFile(workspaceDir); sbValidateWithTelemetry(s_workspace->m_workspace, "Failed to open main workspace"); // Record location of the workspace VariableCollectionManager& settingsManager = VariableCollectionManager::get(); settingsManager.setGlobalVar("WORKSPACE_FILE_PATH", workspaceDir); // Open all projects referenced by the workspace const StringVec& projPaths = s_workspace->m_workspace->getProjectPaths(); for (unsigned i = 0; i < projPaths.size(); i++) { s_workspace->openProject(projPaths[i]); } s_workspace->findSchemes(workspaceDir); // A workspace MUST contain at least one scheme sbValidateWithTelemetry(!s_workspace->m_schemes.empty(), "The workspace does not contain any schemes."); // A workspace MUST also contain at least one open project sbValidateWithTelemetry(!s_workspace->m_openProjects.empty(), "The workspace does not contain any valid projects."); return s_workspace; }
void SBWorkspace::selectTargets(PotentialTargetsVec& ret) { String queryMessage; if (m_workspace) { queryMessage = "The \"" + getName() + "\" workspace contains multiple targets."; } else { queryMessage = "The project contains multiple targets."; } // Get all possible targets in the solution PotentialTargetsVec allTargets; getAllTargets(allTargets); // Construct vector of target names for the query, maintaining order StringVec targetNames; std::transform(allTargets.begin(), allTargets.end(), back_inserter(targetNames), [](auto kv) { return kv.first->getNameWithType(); }); sbAssertWithTelemetry(!targetNames.empty(), "The workspace contains no targets"); // Query the user for which targets should be queued std::vector<size_t> selection; queryListSelection(targetNames, queryMessage, "target", selection); // Return selection of targets ret.clear(); std::transform(selection.begin(), selection.end(), back_inserter(ret), [&allTargets](size_t i) { return allTargets[i]; }); }
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; }
SBWorkspace* SBWorkspace::createFromProject(const String& projectDir) { sbAssertWithTelemetry(!s_workspace, "Workspace already exists"); // Create the workspace s_workspace = new SBWorkspace(); // Open project SBProject* proj = s_workspace->openProject(projectDir); // Failing to open a project here is fatal sbValidateWithTelemetry(proj, "Failed to open main project"); // Save a ptr to the project, so later we can access the "main" project s_workspace->m_mainProject = proj; return s_workspace; }
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; } } // Take into account path override bool useRelativePath = true; if (itemHint && !itemHint->pathOverride.empty()) { sbAssertWithTelemetry(!isVariant, "Unexpected path override for variant file: " + realPath); realPath = itemHint->pathOverride; useRelativePath = false; } // Take into account filter override string filterPath = sb_dirname(virtualPath); if (itemHint && !itemHint->filterOverride.empty()) { filterPath = itemHint->filterOverride; } // Add the item to the project VCProjectItem* item = NULL; if (useRelativePath) { item = addRelativeFilePathToVS(vsType, realPath, filterPath, proj, bs); } else { item = proj.addItem(vsType, realPath, filterPath); } // Handle Variant files if (isVariant) { String variantDir = sb_basename(sb_dirname(realPath)); item->setDefinition("VariantDir", variantDir); } return item; }
VSSolution::VSSolution(const std::string& absPath, unsigned version) : m_absFilePath(platformPath(sanitizePath(absPath))), m_version(version) { sbAssertWithTelemetry(isAbsolutePath(absPath), "Path to VS solution is not absolute"); }
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; }