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
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #8
0
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);
}
Exemple #9
0
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);
  }
}
Exemple #10
0
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);
}
Exemple #13
0
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;
}
Exemple #14
0
static const char* getVsImporterTemplatesDir() {
    static String templatesDir = joinPaths(sb_dirname(getBinaryLocation()), "../msvc/vsimporter-templates");
    return templatesDir.c_str();
}
Exemple #15
0
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();
}
Exemple #16
0
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");
    }
  }
}
Exemple #18
0
static void recordFilterPath(const std::string& filterPath, StringSet& filterSet)
{
  if (!filterPath.empty() && filterPath != "." && filterSet.insert(filterPath).second)
    recordFilterPath(sb_dirname(filterPath), filterSet);
}