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
}
Example #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;
}
Example #3
0
String PBXFile::getFileType(const String& fileName)
{
  // Get the lowercase extension
  std::string ext = sb_fextension(sb_basename(fileName));
  for (int i = 0; i < ext.length(); i++)
    ext[i] = tolower(ext[i]);

  if (ext == "c")
    return "sourcecode.c.c";
  else if (ext == "cpp" || ext == "cc" || ext == "cxx")
    return "sourcecode.cpp.cpp";
  else if (ext == "m")
    return "sourcecode.c.objc";
  else if (ext == "mm" || ext == "mxx")
    return "sourcecode.cpp.objcpp";
  else if (ext == "s")
    return "sourcecode.asm";
  else if (ext == "h" || ext == "pch")
    return "sourcecode.c.h";
  else if (ext == "hpp" || ext == "hh")
    return "sourcecode.cpp.h";
  else if (ext == "d")
    return "sourcecode.dtrace";
  else if (ext == "png")
    return "image.png";
  else if (ext == "tiff")
    return "image.tiff";
  else if (ext == "jpg" || ext == "jpeg")
    return "image.jpeg";
  else if (ext == "mp3")
    return "audio.mp3";
  else if (ext == "xib")
    return "file.xib";
  else if (ext == "nib" || ext == "nib~")
    return "file.xib";
  else if (ext == "plist" || ext == "dict")
    return "text.plist.xml";
  else if (ext == "strings")
    return "text.plist.strings";
  else if (ext == "storyboard")
    return "file.storyboard";
  else if (ext == "storyboardc")
    return "wrapper.storyboardc";
  else if (ext == "xcdatamodel")
    return "wrapper.xcdatamodel";
  else if (ext == "xcdatamodeld")
    return "wrapper.xcdatamodeld";
  else if (ext == "o" || ext == "obj")
    return "compiled.mach-o.objfile";
  else if (ext == "bundle")
    return "wrapper.plug-in";
  else if (ext == "xcassets")
    return "folder.assetcatalog";
  else if (ext == ".app")
    return "wrapper.application";
  else if (ext == ".a")
    return "archive.ar";
  else
    return "text";
}
Example #4
0
void printUsage(const char *execName, bool full, int exitCode)
{
  std::cout << "Usage: ";
  std::cout << "\t" << sb_basename(execName) << " ";
  std::cout << "[-project projectname] [-target targetname ...] [-configuration configurationname] ";
  std::cout << "[-interactive] [setting=value ...]";
  std::cout << std::endl;
  std::cout << "\t" << sb_basename(execName) << " ";
  std::cout << "[-project projectname] -scheme schemename [-configuration configurationname] ";
  std::cout << "[-interactive] [setting=value ...]";
  std::cout << std::endl;
  std::cout << "\t" << sb_basename(execName) << " ";
  std::cout << "-workspace workspacename -scheme schemename [-configuration configurationname] ";
  std::cout << "[-interactive] [setting=value ...]";
  std::cout << std::endl;
  std::cout << "\t" << sb_basename(execName) << " ";
  std::cout << "-list [-project projectname | -workspace workspacename]" << std::endl;

  // Don't print option descriptions if brief usage was requested
  if (!full)
    goto done;

  std::cout << std::endl;
  std::cout << "Program Options" << std::endl;
  std::cout << "    -usage" << "\t\t    print brief usage message" << std::endl;
  std::cout << "    -help" << "\t\t    print full usage message" << std::endl;
  std::cout << "    -interactive" << "\t    enable interactive mode" << std::endl;
  std::cout << "    -loglevel LEVEL" << "\t    debug | info | warning | error" << std::endl;
  std::cout << "    -list" << "\t\t    list the targets and configurations in the project" << std::endl;
  std::cout << "    -sdk SDKROOT" << "\t    specify path to WinObjC SDK root (by default calculated from binary's location)" << std::endl;
  std::cout << "    -relativepath" << "\t    write a relative WinObjC SDK path to project files" << std::endl;
  std::cout << "    -project PATH" << "\t    specify project to process" << std::endl;
  std::cout << "    -workspace PATH" << "\t    specify workspace to process" << std::endl;
  std::cout << "    -target NAME" << "\t    specify target to process" << std::endl;
  std::cout << "    -alltargets" << "\t\t    process all targets" << std::endl;
  std::cout << "    -scheme NAME" << "\t    specify scheme to process" << std::endl;
  std::cout << "    -allschemes" << "\t\t    process all schemes" << std::endl;
  std::cout << "    -configuration NAME" << "\t    specify configuration to use" << std::endl;
  std::cout << "    -xcconfig FILE" << "\t    apply build settings defined in FILE as overrides" << std::endl;
  std::cout << "    -version" << "\t\t    print the tool version" << std::endl;

done:
  exit(exitCode);
}
Example #5
0
// TODO: use function pointers
const PBXTarget* PBXProject::getTargetWithProductName(const String& productName) const
{
  for (unsigned i = 0; i < m_targetPtrs.size(); i++) {
    String productFile = sb_basename(m_targetPtrs[i]->getProductFileName());
    if (productFile == productName)
      return m_targetPtrs[i];
  }
  
  return NULL;
}
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);
  }
}
Example #7
0
void SBTarget::validateSDK()
{
  // Check if this is an iphoneos target
  // Could take the form of "iphone" or a full path to the SDK
  for (auto bs : m_buildSettings) {
    const VariableCollectionHierarchy& vch = bs.second->getHierarchy();
    String sdkRoot = vch.getValue("SDKROOT", vch.size() - 2);
    sdkRoot = strToLower(sb_basename(sdkRoot));
    if (!strBeginsWith(sdkRoot, "iphoneos")) {
      SBLog::warning() << "The \"" << bs.first << "\" configuration of the \"" << getName() << "\" target does not target an iOS SDK." << std::endl;
    }
  }
}
Example #8
0
void PBXFile::initFromPlist(const String& id, const Plist::dictionary_type& plist, const PBXDocument* pbxDoc)
{
  // Call super init
  PBXObject::initFromPlist(id, plist, pbxDoc);
  
  // Get path
  getStringForKey(plist, "path", m_path, VALUE_OPTIONAL, m_parseER);

  // Get name
  getStringForKey(plist, "name", m_name, VALUE_OPTIONAL, m_parseER);
  if (m_name.empty())
    m_name = sb_basename(m_path);
  
  // Get sourceTree
  getStringForKey(plist, "sourceTree", m_sourceTree, VALUE_REQUIRED, m_parseER);
}
void PBXNativeTarget::getBuildSettings(VariableCollection& settings) const
{
  PBXTarget::getBuildSettings(settings);

  String productFileType = getProductFileType();
  String productPath = getProductFileName();
  String productNameFull = sb_basename(productPath);
  String productName = sb_fname(productNameFull);

  if (m_productType == "com.apple.product-type.library.static") {
    if (productFileType != "archive.ar")
      SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" static lib target." << std::endl;

    settings.insert("EXECUTABLE_NAME", productNameFull);
    settings.insert("EXECUTABLE_PATH", productNameFull);
  }  else if (m_productType == "com.apple.product-type.framework") {
    if (productFileType != "wrapper.framework") {
      SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" framework target." << std::endl;
    }

    settings.insert("EXECUTABLE_NAME", productName);
    settings.insert("EXECUTABLE_PATH", joinPaths(productNameFull, productName));
  } else if (m_productType == "com.apple.product-type.application") {
    // Fix up product name, when necessary
    if (productFileType == "compiled.mach-o.executable")
      productNameFull = productName + ".app";
    else if (productFileType != "wrapper.application")
      SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" app target." << std::endl;

    settings.insert("EXECUTABLE_NAME", productName);
    settings.insert("EXECUTABLE_FOLDER_PATH", productNameFull);
  } else if (m_productType == "com.apple.product-type.bundle") {
    if (productFileType != "wrapper.cfbundle") {
      SBLog::warning() << "Unexpected product file type \"" << productFileType << "\" for \"" << getName() << "\" bundle target." << std::endl;
    }

    settings.insert("EXECUTABLE_NAME", productName);
    settings.insert("EXECUTABLE_FOLDER_PATH", productNameFull);
  }

  settings.insert("PRODUCT_NAME", productName);
  settings.insert("FULL_PRODUCT_NAME", productNameFull);
  settings.insert("PRODUCT_TYPE", m_productType);
}
Example #10
0
bool VSTemplateProject::initFromXML(const pugi::xml_node& pNode)
{
  // Create a ProjectItem from the project description
  ProjectItem* projectDesc = new ProjectItem;
  projectDesc->inFile = pNode.attribute("File").value();
  projectDesc->outFile = pNode.attribute("TargetFileName").value();
  projectDesc->replaceParams = pNode.attribute("ReplaceParameters").as_bool();
  m_items.push_back(projectDesc);
  
  tokenize(pNode.attribute("Platforms").value(), m_platforms, ";");
  m_shared = pNode.attribute("Shared").as_bool();
  m_deployable = pNode.attribute("Deployable").as_bool();
  m_outputDir = pNode.attribute("OutputDirectory").value();
  if (m_outputDir.empty()) {
    m_outputDir = "$projectname$";
  }

  // Extract project items
  for (pugi::xml_node child = pNode.first_child(); child; child = child.next_sibling()) {
    if (child.name() == std::string("ProjectItem")) {
      bool replaceParams = child.attribute("ReplaceParameters").as_bool();
      std::string inFile = child.child_value();
      std::string outFile = child.attribute("TargetFileName").value();
      if (outFile.empty()) {
        outFile = sb_basename(inFile);
      }

      ProjectItem* item = new ProjectItem(inFile, outFile, replaceParams);
      m_items.push_back(item);
    }
  }

  // Validate
  if (m_platforms.empty() && !m_shared) {
    SBLog::warning() << "Ignoring " << projectDesc->inFile << " project because it specifies no platforms." << std::endl;
    return false;
  }
  return true;
}
void SBFrameworksBuildPhase::writeVCProjectFiles(VCProject& proj) const
{
  // We don't support linking with frameworks when building bundles
  TargetProductType productType = m_parentTarget.getProductType();
  if (productType == TargetBundle) {
    if (!m_phase->getBuildFileList().empty()) {
      SBLog::warning() << "Ignoring all frameworkss in \"" << m_parentTarget.getName() << "\" bundle target." << std::endl;
    }
    return;
  }

  String linkTarget;
  if (productType == TargetApplication)
    linkTarget = "Link";
  else if (productType == TargetStaticLib)
    linkTarget = "Lib";

  // Get paths to all the build files (frameworks)
  StringVec buildFilePaths;
  if (m_phase) {
    const BuildFileList& buildFiles = m_phase->getBuildFileList();
    sbAssert(buildFiles.size() == m_buildFileTargets.size());
    for (size_t i = 0; i < buildFiles.size(); i++) {
      const PBXFile* file = buildFiles[i]->getFile();
      // Ignore any frameworks build from source (they will be added as project references)
      if (file && !m_buildFileTargets[i])
        buildFilePaths.push_back(file->getFullPath());
    }
  }

  for (auto bs : m_parentTarget.getBuildSettings()) {
    VCProjectConfiguration* config = proj.addConfiguration(bs.first);

    // Extrace libs/frameworks from OTHER_LDFLAGS
    StringVec buildFilePaths(buildFilePaths);
    processLDFlags(bs.second->getValue("OTHER_LDFLAGS"), buildFilePaths);

    // Construct a list of libraries to link against
    StringSet linkedLibs;
    linkedLibs.insert("%(AdditionalDependencies)");
    for (auto filePath : buildFilePaths) {
      if (productType == TargetStaticLib && !strEndsWith(filePath, ".a"))
        continue;

      String winLibName = sb_fname(sb_basename(filePath)) + ".lib";

      // If the library is blocked then add the replacement library to our additional dependencies 
      auto it = s_blockedLibraries.find(winLibName);
      while (it != s_blockedLibraries.end())
      {
          // get the replacement library.
          winLibName = it->second;

          // follow any transitive replacement.
          it = s_blockedLibraries.find(winLibName);
      }

      if (!winLibName.empty())
      {
          linkedLibs.insert(winLibName);
      }
    }

    // AdditionalDependencies
    String additionalDeps = joinStrings(linkedLibs, ";");
    if (!additionalDeps.empty()) {
      config->setItemDefinition(linkTarget, "AdditionalDependencies", additionalDeps);
    }
  }
}
Example #12
0
SBTarget* SBTarget::getPossibleTarget(const PBXBuildFile* buildFile)
{
  static const char* const _productWildcards[] = {"lib*.a", "*.app", "*.framework"};
  static StringVec productWildcards(_productWildcards, _productWildcards + sizeof(_productWildcards) / sizeof(char*));

  sbAssert(buildFile);
  const PBXFile* file = buildFile->getFile();
  
  String filePath, fileName;
  if (file) {
    filePath = file->getFullPath();
    fileName = sb_basename(filePath);
  }

  SBTarget* depTarget = NULL;
  const PBXReferenceProxy* proxyFile = NULL;

  // We are interested in any potential Xcode build products
  if (!matchWildcardList(fileName, productWildcards)) {
    // Do nothing
  } else if ((proxyFile = dynamic_cast<const PBXReferenceProxy*>(file))) {
    // Construct base error string, to hopefully never be used
    String errStr = "Failed to process PBXBuildFile (" + buildFile->getId() + ") for " + getName() + " target. ";

    // Get remote proxy container
    const PBXContainerItemProxy* container = proxyFile->getContainer();

    // Ignore build file, if necessary
    if (!container) {
      SBLog::warning() << errStr << "Unable to get the PBXContainerItemProxy.";
      return NULL;
    }

    // Get remote project and target identifier from the proxy
    const String& remoteId = container->getRemoteId();
    String projectPath = container->getPortalPath();

    // Expand the project path
    const BuildSettings& projBS = m_parentProject.getBuildSettings();
    String absProjectPath = projBS.expand(projectPath, PathValue);
      
    // Try to open the remote project
    SBProject* remoteProject = SBWorkspace::get()->openProject(absProjectPath);

    // Try to queue up the target with the given product reference
    if (remoteProject) {
      depTarget = remoteProject->queueTargetWithProductReference(remoteId);
      if (!depTarget)
        SBLog::warning() << errStr << "Unable to create proxy target " << remoteId << " from the \"" << remoteProject->getName() << "\" project." << std::endl;
    } else {
      SBLog::warning() << errStr << "Unable to open referenced project path: " << projectPath << std::endl;
    }
  } else {
    // Look for target in current project first
    depTarget = m_parentProject.queueTargetWithProductName(fileName);

    // Look for target in workspace, if it hasn't been found already
    if (!depTarget)
      depTarget = SBWorkspace::get()->queueTargetWithProductName(fileName);
  }

  // Add the target to the dependency set
  addDependency(depTarget);

  // Indicate whether this was a dependency or not
  return depTarget;
}
Example #13
0
void printVersion(const char *execName)
{
static String binaryVersion = "1.0";
  std::cout << sb_basename(execName) << " " << binaryVersion << std::endl;
  exit(EXIT_SUCCESS);
}