diff options
author | Brad King <brad.king@kitware.com> | 2020-07-15 10:50:14 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2020-07-15 10:50:22 (GMT) |
commit | 67d809006f6ae05b52ec67672eb549720c33b855 (patch) | |
tree | 0106d4c631690ec8ae952ac0bdd08e3db1975289 | |
parent | e169ec9c23b5fda1d0036e8e3dadec635111ff90 (diff) | |
parent | 3603ca8e86c5bc41af7f2559ecd072e2df2caf83 (diff) | |
download | CMake-67d809006f6ae05b52ec67672eb549720c33b855.zip CMake-67d809006f6ae05b52ec67672eb549720c33b855.tar.gz CMake-67d809006f6ae05b52ec67672eb549720c33b855.tar.bz2 |
Merge topic 'xcode-lib-refs'
3603ca8e86 Xcode: Special treatment for directly linked framework binaries
e637744c51 Xcode: Use "Link Binary With Libraries" to link any library
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4975
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 209 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.h | 10 |
2 files changed, 161 insertions, 58 deletions
diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 656a346..2d47d2c 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -172,6 +172,7 @@ cmGlobalXCodeGenerator::cmGlobalXCodeGenerator( this->RootObject = nullptr; this->MainGroupChildren = nullptr; + this->FrameworkGroup = nullptr; this->CurrentMakefile = nullptr; this->CurrentLocalGenerator = nullptr; this->XcodeBuildCommandInitialized = false; @@ -668,6 +669,7 @@ void cmGlobalXCodeGenerator::ClearXCodeObjects() this->GroupNameMap.clear(); this->TargetGroup.clear(); this->FileRefs.clear(); + this->ExternalLibRefs.clear(); } void cmGlobalXCodeGenerator::addObject(std::unique_ptr<cmXCodeObject> obj) @@ -736,7 +738,7 @@ std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, return key; } -cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFileFromPath( +cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeBuildFileFromPath( const std::string& fullpath, cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf) { @@ -872,7 +874,7 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeSourceFile( lg->AppendFlags(flags, lg->GetIncludeFlags(includes, gtgt, lang, true)); cmXCodeObject* buildFile = - this->CreateXCodeSourceFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf); + this->CreateXCodeBuildFileFromPath(sf->ResolveFullPath(), gtgt, lang, sf); cmXCodeObject* settings = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); settings->AddAttributeIfNotEmpty("COMPILER_FLAGS", @@ -925,6 +927,31 @@ void cmGlobalXCodeGenerator::AddXCodeProjBuildRule( } } +bool IsLibraryExtension(const std::string& fileExt) +{ + return (fileExt == ".framework" || fileExt == ".a" || fileExt == ".o" || + fileExt == ".dylib" || fileExt == ".tbd"); +} +bool IsLibraryType(const std::string& fileType) +{ + return (fileType == "wrapper.framework" || fileType == "archive.ar" || + fileType == "compiled.mach-o.objfile" || + fileType == "compiled.mach-o.dylib" || + fileType == "sourcecode.text-based-dylib-definition"); +} + +std::string GetDirectoryValueFromFileExtension(const std::string& dirExt) +{ + std::string ext = cmSystemTools::LowerCase(dirExt); + if (ext == "framework") { + return "wrapper.framework"; + } + if (ext == "xcassets") { + return "folder.assetcatalog"; + } + return "folder"; +} + std::string GetSourcecodeValueFromFileExtension( const std::string& _ext, const std::string& lang, bool& keepLastKnownFileType, const std::vector<std::string>& enabled_langs) @@ -933,6 +960,7 @@ std::string GetSourcecodeValueFromFileExtension( std::string sourcecode = "sourcecode"; if (ext == "o") { + keepLastKnownFileType = true; sourcecode = "compiled.mach-o.objfile"; } else if (ext == "xctest") { sourcecode = "wrapper.cfbundle"; @@ -976,6 +1004,14 @@ std::string GetSourcecodeValueFromFileExtension( sourcecode += ".metal"; } else if (ext == "mig") { sourcecode += ".mig"; + } else if (ext == "tbd") { + sourcecode += ".text-based-dylib-definition"; + } else if (ext == "a") { + keepLastKnownFileType = true; + sourcecode = "archive.ar"; + } else if (ext == "dylib") { + keepLastKnownFileType = true; + sourcecode = "compiled.mach-o.dylib"; } // else // { @@ -992,20 +1028,6 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( const std::string& fullpath, cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf) { - std::string key = GetGroupMapKeyFromPath(target, fullpath); - cmXCodeObject* fileRef = this->FileRefs[key]; - if (!fileRef) { - fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); - fileRef->SetComment(fullpath); - this->FileRefs[key] = fileRef; - } - cmXCodeObject* group = this->GroupMap[key]; - cmXCodeObject* children = group->GetObject("children"); - if (!children->HasObject(fileRef)) { - children->AddObject(fileRef); - } - fileRef->AddAttribute("fileEncoding", this->CreateString("4")); - bool useLastKnownFileType = false; std::string fileType; if (sf) { @@ -1016,19 +1038,32 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( fileType = *l; } } + // Make a copy so that we can override it later + std::string path = fullpath; + // Compute the extension without leading '.'. + std::string ext = cmSystemTools::GetFilenameLastExtension(path); + if (!ext.empty()) { + ext = ext.substr(1); + } if (fileType.empty()) { - // Compute the extension without leading '.'. - std::string ext = cmSystemTools::GetFilenameLastExtension(fullpath); - if (!ext.empty()) { - ext = ext.substr(1); + // If file has no extension it's either a raw executable or might + // be a direct reference to binary within a framework (bad practice!) + // so this is where we change the path to the point to framework + // directory. + if (ext.empty()) { + auto parentDir = cmSystemTools::GetParentDirectory(path); + auto parentExt = cmSystemTools::GetFilenameLastExtension(parentDir); + if (parentExt == ".framework") { + path = parentDir; + ext = parentExt.substr(1); + } } - // If fullpath references a directory, then we need to specify // lastKnownFileType as folder in order for Xcode to be able to // open the contents of the folder. // (Xcode 4.6 does not like explicitFileType=folder). - if (cmSystemTools::FileIsDirectory(fullpath)) { - fileType = (ext == "xcassets" ? "folder.assetcatalog" : "folder"); + if (cmSystemTools::FileIsDirectory(path)) { + fileType = GetDirectoryValueFromFileExtension(ext); useLastKnownFileType = true; } else { fileType = GetSourcecodeValueFromFileExtension( @@ -1036,18 +1071,37 @@ cmXCodeObject* cmGlobalXCodeGenerator::CreateXCodeFileReferenceFromPath( } } + std::string key = GetGroupMapKeyFromPath(target, path); + cmXCodeObject* fileRef = this->FileRefs[key]; + if (!fileRef) { + fileRef = this->CreateObject(cmXCodeObject::PBXFileReference); + fileRef->SetComment(path); + this->FileRefs[key] = fileRef; + } + fileRef->AddAttribute("fileEncoding", this->CreateString("4")); fileRef->AddAttribute(useLastKnownFileType ? "lastKnownFileType" : "explicitFileType", this->CreateString(fileType)); - // Store the file path relative to the top of the source tree. - std::string path = this->RelativeToSource(fullpath); + if (!IsLibraryType(fileType)) { + path = this->RelativeToSource(path); + } std::string name = cmSystemTools::GetFilenameName(path); const char* sourceTree = cmSystemTools::FileIsFullPath(path) ? "<absolute>" : "SOURCE_ROOT"; fileRef->AddAttribute("name", this->CreateString(name)); fileRef->AddAttribute("path", this->CreateString(path)); fileRef->AddAttribute("sourceTree", this->CreateString(sourceTree)); + + cmXCodeObject* group = this->GroupMap[key]; + if (!group && IsLibraryType(fileType)) { + group = this->FrameworkGroup; + this->GroupMap[key] = group; + } + cmXCodeObject* children = group->GetObject("children"); + if (!children->HasObject(fileRef)) { + children->AddObject(fileRef); + } return fileRef; } @@ -1182,11 +1236,14 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( this->CurrentLocalGenerator, sourceFile, gtgt); cmXCodeObject* fr = xsf->GetObject("fileRef"); cmXCodeObject* filetype = fr->GetObject()->GetObject("explicitFileType"); + if (!filetype) { + filetype = fr->GetObject()->GetObject("lastKnownFileType"); + } cmGeneratorTarget::SourceFileFlags tsFlags = gtgt->GetTargetSourceFileFlags(sourceFile); - if (filetype && filetype->GetString() == "compiled.mach-o.objfile") { + if (filetype && IsLibraryType(filetype->GetString())) { if (sourceFile->GetObjectLibrary().empty()) { externalObjFiles.push_back(xsf); } @@ -2800,21 +2857,30 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) continue; } for (auto const& libItem : cli->GetItems()) { - // TODO: Drop this check once we have option to add outside libraries to - // Xcode project - auto* libTarget = FindXCodeTarget(libItem.Target); if (gt->IsBundleOnApple() && (gt->GetType() == cmStateEnums::EXECUTABLE || gt->GetType() == cmStateEnums::SHARED_LIBRARY || gt->GetType() == cmStateEnums::MODULE_LIBRARY || gt->GetType() == cmStateEnums::UNKNOWN_LIBRARY) && - (libTarget && libItem.Target && - (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY || - libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY || - libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY))) { + ((libItem.Target && + (libItem.Target->GetType() == cmStateEnums::STATIC_LIBRARY || + libItem.Target->GetType() == cmStateEnums::SHARED_LIBRARY || + libItem.Target->GetType() == cmStateEnums::MODULE_LIBRARY)) || + (!libItem.Target && libItem.IsPath))) { // Add unique configuration name to target-config map for later // checks - std::string libName = libItem.Target->GetName(); + std::string libName; + if (libItem.Target) { + libName = libItem.Target->GetName(); + } else { + libName = cmSystemTools::GetFilenameName(libItem.Value.Value); + const auto libExt = cmSystemTools::GetFilenameExtension(libName); + if (!IsLibraryExtension(libExt)) { + // Add this library item to a regular linker flag list + addToLinkerArguments(configName, &libItem); + continue; + } + } auto& configVector = targetConfigMap[libName]; if (std::find(configVector.begin(), configVector.end(), configName) == configVector.end()) { @@ -2865,38 +2931,63 @@ void cmGlobalXCodeGenerator::AddDependAndLinkInformation(cmXCodeObject* target) std::vector<std::string> linkSearchPaths; for (auto const& libItem : linkPhaseTargetVector) { // Add target output directory as a library search path - std::string linkDir = cmSystemTools::GetParentDirectory( - libItem->Target->GetLocationForBuild()); + std::string linkDir; + if (libItem->Target) { + linkDir = cmSystemTools::GetParentDirectory( + libItem->Target->GetLocationForBuild()); + } else { + linkDir = cmSystemTools::GetParentDirectory(libItem->Value.Value); + } if (std::find(linkSearchPaths.begin(), linkSearchPaths.end(), linkDir) == linkSearchPaths.end()) { linkSearchPaths.push_back(linkDir); } // Add target dependency - auto const& libName = *libItem; - if (!libName.Target->IsImported()) { + if (libItem->Target && !libItem->Target->IsImported()) { for (auto const& configName : this->CurrentConfigurationTypes) { - target->AddDependTarget(configName, libName.Target->GetName()); + target->AddDependTarget(configName, libItem->Target->GetName()); } } // Get the library target auto* libTarget = FindXCodeTarget(libItem->Target); - if (!libTarget) { - continue; - } - // Add the target output file as a build reference for other targets - // to link against - auto* fileRefObject = libTarget->GetObject("productReference"); - if (!fileRefObject) { - continue; - } cmXCodeObject* buildFile; - auto it = FileRefToBuildFileMap.find(fileRefObject); - if (it == FileRefToBuildFileMap.end()) { - buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); - buildFile->AddAttribute("fileRef", fileRefObject); - FileRefToBuildFileMap[fileRefObject] = buildFile; + if (!libTarget) { + if (libItem->IsPath) { + // Get or create a direct file ref in the root project + auto it = this->ExternalLibRefs.find(libItem->Value.Value); + if (it == this->ExternalLibRefs.end()) { + buildFile = CreateXCodeBuildFileFromPath(libItem->Value.Value, gt, + "", nullptr); + this->ExternalLibRefs.emplace(libItem->Value.Value, buildFile); + } else { + buildFile = it->second; + } + } else { + // Add this library item back to a regular linker flag list + for (const auto& conf : configItemMap) { + addToLinkerArguments(conf.first, libItem); + } + continue; + } } else { - buildFile = it->second; + // Add the target output file as a build reference for other targets + // to link against + auto* fileRefObject = libTarget->GetObject("productReference"); + if (!fileRefObject) { + // Add this library item back to a regular linker flag list + for (const auto& conf : configItemMap) { + addToLinkerArguments(conf.first, libItem); + } + continue; + } + auto it = FileRefToBuildFileMap.find(fileRefObject); + if (it == FileRefToBuildFileMap.end()) { + buildFile = this->CreateObject(cmXCodeObject::PBXBuildFile); + buildFile->AddAttribute("fileRef", fileRefObject); + FileRefToBuildFileMap[fileRefObject] = buildFile; + } else { + buildFile = it->second; + } } // Add this reference to current target auto* buildPhases = target->GetObject("buildPhases"); @@ -3164,6 +3255,7 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( this->ClearXCodeObjects(); this->RootObject = nullptr; this->MainGroupChildren = nullptr; + this->FrameworkGroup = nullptr; cmXCodeObject* group = this->CreateObject(cmXCodeObject::ATTRIBUTE_GROUP); group->AddAttribute("COPY_PHASE_STRIP", this->CreateString("NO")); cmXCodeObject* listObjs = this->CreateObject(cmXCodeObject::OBJECT_LIST); @@ -3198,6 +3290,15 @@ bool cmGlobalXCodeGenerator::CreateXCodeObjects( productGroup->AddAttribute("children", productGroupChildren); this->MainGroupChildren->AddObject(productGroup); + this->FrameworkGroup = this->CreateObject(cmXCodeObject::PBXGroup); + this->FrameworkGroup->AddAttribute("name", this->CreateString("Frameworks")); + this->FrameworkGroup->AddAttribute("sourceTree", + this->CreateString("<group>")); + cmXCodeObject* frameworkGroupChildren = + this->CreateObject(cmXCodeObject::OBJECT_LIST); + this->FrameworkGroup->AddAttribute("children", frameworkGroupChildren); + this->MainGroupChildren->AddObject(this->FrameworkGroup); + this->RootObject = this->CreateObject(cmXCodeObject::PBXProject); this->RootObject->SetComment("Project object"); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 11b9312..276a9ee 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -203,10 +203,10 @@ private: cmGeneratorTarget* target, const std::string& lang, cmSourceFile* sf); - cmXCodeObject* CreateXCodeSourceFileFromPath(const std::string& fullpath, - cmGeneratorTarget* target, - const std::string& lang, - cmSourceFile* sf); + cmXCodeObject* CreateXCodeBuildFileFromPath(const std::string& fullpath, + cmGeneratorTarget* target, + const std::string& lang, + cmSourceFile* sf); cmXCodeObject* CreateXCodeFileReference(cmSourceFile* sf, cmGeneratorTarget* target); cmXCodeObject* CreateXCodeSourceFile(cmLocalGenerator* gen, cmSourceFile* sf, @@ -281,6 +281,7 @@ private: std::string PostBuildMakeTarget(std::string const& tName, std::string const& configName); cmXCodeObject* MainGroupChildren; + cmXCodeObject* FrameworkGroup; cmMakefile* CurrentMakefile; cmLocalGenerator* CurrentLocalGenerator; std::vector<std::string> CurrentConfigurationTypes; @@ -294,6 +295,7 @@ private: std::map<std::string, cmXCodeObject*> GroupNameMap; std::map<std::string, cmXCodeObject*> TargetGroup; std::map<std::string, cmXCodeObject*> FileRefs; + std::map<std::string, cmXCodeObject*> ExternalLibRefs; std::map<cmGeneratorTarget const*, cmXCodeObject*> XCodeObjectMap; std::map<cmXCodeObject*, cmXCodeObject*> FileRefToBuildFileMap; std::vector<std::string> Architectures; |