in Source/cmGlobalXCodeGenerator.cxx [2391:3122]
void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt,
cmXCodeObject* buildSettings,
std::string const& configName)
{
if (!gtgt->IsInBuildSystem()) {
return;
}
std::string defFlags;
bool shared = ((gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) ||
(gtgt->GetType() == cmStateEnums::MODULE_LIBRARY));
bool binary = ((gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) ||
(gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) ||
(gtgt->GetType() == cmStateEnums::EXECUTABLE) || shared);
// Compute the compilation flags for each language.
std::set<std::string> languages;
gtgt->GetLanguages(languages, configName);
std::map<std::string, std::string> cflags;
for (auto const& lang : languages) {
std::string& flags = cflags[lang];
// Add language-specific flags.
this->CurrentLocalGenerator->AddLanguageFlags(
flags, gtgt, cmBuildStep::Compile, lang, configName);
if (gtgt->IsIPOEnabled(lang, configName)) {
this->CurrentLocalGenerator->AppendFeatureOptions(flags, lang, "IPO");
}
this->CurrentLocalGenerator->AddFeatureFlags(flags, gtgt, lang,
configName);
this->CurrentLocalGenerator->AddVisibilityPresetFlags(flags, gtgt, lang);
this->CurrentLocalGenerator->AddCompileOptions(flags, gtgt, lang,
configName);
}
std::string llang = gtgt->GetLinkerLanguage(configName);
if (binary && llang.empty()) {
cmSystemTools::Error(
cmStrCat("CMake can not determine linker language for target: ",
gtgt->GetName()));
return;
}
// Choose a language to use for target-wide preprocessor definitions.
static char const* ppLangs[] = { "CXX", "C", "OBJCXX", "OBJC" };
std::string langForPreprocessorDefinitions;
if (cm::contains(ppLangs, llang)) {
langForPreprocessorDefinitions = llang;
} else {
for (char const* l : ppLangs) {
if (languages.count(l)) {
langForPreprocessorDefinitions = l;
break;
}
}
}
if (gtgt->IsIPOEnabled(llang, configName)) {
char const* ltoValue =
this->CurrentMakefile->IsOn("_CMAKE_LTO_THIN") ? "YES_THIN" : "YES";
buildSettings->AddAttribute("LLVM_LTO", this->CreateString(ltoValue));
}
// Handle PIE linker configuration
this->AddPositionIndependentLinkAttribute(gtgt, buildSettings, configName);
// Add define flags
this->CurrentLocalGenerator->AppendFlags(
defFlags, this->CurrentMakefile->GetDefineFlags());
// Add preprocessor definitions for this target and configuration.
BuildObjectListOrString ppDefs(this, true);
this->AppendDefines(
ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\"");
if (std::string const* exportMacro = gtgt->GetExportMacro()) {
// Add the export symbol definition for shared library objects.
this->AppendDefines(ppDefs, exportMacro->c_str());
}
std::vector<std::string> targetDefines;
if (!langForPreprocessorDefinitions.empty()) {
gtgt->GetCompileDefinitions(targetDefines, configName,
langForPreprocessorDefinitions);
}
this->AppendDefines(ppDefs, targetDefines);
buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS",
ppDefs.CreateList());
if (languages.count("Swift")) {
// Swift uses a separate attribute for definitions.
std::vector<std::string> targetSwiftDefines;
gtgt->GetCompileDefinitions(targetSwiftDefines, configName, "Swift");
// Remove the '=value' parts, as Swift does not support them.
std::for_each(targetSwiftDefines.begin(), targetSwiftDefines.end(),
[](std::string& def) {
std::string::size_type pos = def.find('=');
if (pos != std::string::npos) {
def.erase(pos);
}
});
if (this->XcodeVersion < 80) {
std::string defineString;
std::set<std::string> defines(targetSwiftDefines.begin(),
targetSwiftDefines.end());
this->CurrentLocalGenerator->JoinDefines(defines, defineString, "Swift");
cflags["Swift"] += cmStrCat(' ', defineString);
} else {
BuildObjectListOrString swiftDefs(this, true);
this->AppendDefines(swiftDefs, targetSwiftDefines);
buildSettings->AddAttribute("SWIFT_ACTIVE_COMPILATION_CONDITIONS",
swiftDefs.CreateList());
}
if (cm::optional<cmSwiftCompileMode> swiftCompileMode =
this->CurrentLocalGenerator->GetSwiftCompileMode(gtgt, configName)) {
switch (*swiftCompileMode) {
case cmSwiftCompileMode::Wholemodule:
buildSettings->AddAttribute("SWIFT_COMPILATION_MODE",
this->CreateString("wholemodule"));
break;
case cmSwiftCompileMode::Incremental:
case cmSwiftCompileMode::Singlefile:
break;
case cmSwiftCompileMode::Unknown:
this->CurrentLocalGenerator->IssueMessage(
MessageType::AUTHOR_WARNING,
cmStrCat("Unknown Swift_COMPILATION_MODE on target '",
gtgt->GetName(), "'"));
break;
}
}
}
std::string extraLinkOptionsVar;
std::string extraLinkOptions;
if (gtgt->GetType() == cmStateEnums::EXECUTABLE) {
extraLinkOptionsVar = "CMAKE_EXE_LINKER_FLAGS";
} else if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
extraLinkOptionsVar = "CMAKE_SHARED_LINKER_FLAGS";
} else if (gtgt->GetType() == cmStateEnums::MODULE_LIBRARY) {
extraLinkOptionsVar = "CMAKE_MODULE_LINKER_FLAGS";
}
if (!extraLinkOptionsVar.empty()) {
this->CurrentLocalGenerator->AddConfigVariableFlags(
extraLinkOptions, extraLinkOptionsVar, gtgt, cmBuildStep::Link, llang,
configName);
}
if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY ||
gtgt->GetType() == cmStateEnums::STATIC_LIBRARY) {
this->CurrentLocalGenerator->GetStaticLibraryFlags(
extraLinkOptions, configName, llang, gtgt);
} else {
this->CurrentLocalGenerator->AppendLinkerTypeFlags(extraLinkOptions, gtgt,
configName, llang);
this->CurrentLocalGenerator->AppendWarningAsErrorLinkerFlags(
extraLinkOptions, gtgt, llang);
cmValue targetLinkFlags = gtgt->GetProperty("LINK_FLAGS");
if (targetLinkFlags) {
this->CurrentLocalGenerator->AppendFlags(extraLinkOptions,
*targetLinkFlags);
}
if (!configName.empty()) {
std::string linkFlagsVar =
cmStrCat("LINK_FLAGS_", cmSystemTools::UpperCase(configName));
if (cmValue linkFlags = gtgt->GetProperty(linkFlagsVar)) {
this->CurrentLocalGenerator->AppendFlags(extraLinkOptions, *linkFlags);
}
}
std::vector<std::string> opts;
gtgt->GetLinkOptions(opts, configName, llang);
// LINK_OPTIONS are escaped.
this->CurrentLocalGenerator->AppendCompileOptions(extraLinkOptions, opts);
}
// Set target-specific architectures.
std::vector<std::string> archs =
gtgt->GetAppleArchs(configName, cm::nullopt);
if (!archs.empty()) {
// Enable ARCHS attribute.
buildSettings->AddAttribute("ONLY_ACTIVE_ARCH", this->CreateString("NO"));
// Store ARCHS value.
if (archs.size() == 1) {
buildSettings->AddAttribute("ARCHS", this->CreateString(archs[0]));
} else {
cmXCodeObject* archObjects =
this->CreateObject(cmXCodeObject::OBJECT_LIST);
for (auto& arch : archs) {
archObjects->AddObject(this->CreateString(arch));
}
buildSettings->AddAttribute("ARCHS", archObjects);
}
}
// Get the product name components.
cmGeneratorTarget::NameComponents const& components =
gtgt->GetFullNameComponents(configName);
cmValue version = gtgt->GetProperty("VERSION");
cmValue soversion = gtgt->GetProperty("SOVERSION");
if (!gtgt->HasSOName(configName) || gtgt->IsFrameworkOnApple()) {
version = nullptr;
soversion = nullptr;
}
if (version && !soversion) {
soversion = version;
}
if (!version && soversion) {
version = soversion;
}
std::string realName = components.base;
std::string soName = components.base;
if (version && soversion) {
realName += '.';
realName += *version;
soName += '.';
soName += *soversion;
}
if (gtgt->CanCompileSources()) {
std::string const tmpDir =
this->GetTargetTempDir(gtgt, this->GetCMakeCFGIntDir());
buildSettings->AddAttribute("TARGET_TEMP_DIR", this->CreateString(tmpDir));
std::string outDir;
if (gtgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
// We cannot suppress the archive, so hide it with intermediate files.
outDir = tmpDir;
} else {
outDir = gtgt->GetDirectory(configName);
}
buildSettings->AddAttribute("CONFIGURATION_BUILD_DIR",
this->CreateString(outDir));
}
// Set attributes to specify the proper name for the target.
std::string pndir = this->CurrentLocalGenerator->GetCurrentBinaryDirectory();
if (gtgt->GetType() == cmStateEnums::STATIC_LIBRARY ||
gtgt->GetType() == cmStateEnums::SHARED_LIBRARY ||
gtgt->GetType() == cmStateEnums::MODULE_LIBRARY ||
gtgt->GetType() == cmStateEnums::EXECUTABLE) {
std::string prefix = components.prefix;
if (gtgt->IsFrameworkOnApple() || gtgt->IsCFBundleOnApple()) {
prefix = "";
}
buildSettings->AddAttribute("EXECUTABLE_PREFIX",
this->CreateString(prefix));
buildSettings->AddAttribute("EXECUTABLE_SUFFIX",
this->CreateString(components.suffix));
}
// Store the product name for all target types.
buildSettings->AddAttribute("PRODUCT_NAME", this->CreateString(realName));
// Handle settings for each target type.
switch (gtgt->GetType()) {
case cmStateEnums::STATIC_LIBRARY:
if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
std::string fw_version = gtgt->GetFrameworkVersion();
buildSettings->AddAttribute("FRAMEWORK_VERSION",
this->CreateString(fw_version));
cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
if (ext) {
buildSettings->AddAttribute("WRAPPER_EXTENSION",
this->CreateString(*ext));
}
std::string plist = this->ComputeInfoPListLocation(gtgt);
// Xcode will create the final version of Info.plist at build time,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
buildSettings->AddAttribute("MACH_O_TYPE",
this->CreateString("staticlib"));
} else {
buildSettings->AddAttribute("LIBRARY_STYLE",
this->CreateString("STATIC"));
}
break;
case cmStateEnums::OBJECT_LIBRARY: {
buildSettings->AddAttribute("LIBRARY_STYLE",
this->CreateString("STATIC"));
break;
}
case cmStateEnums::MODULE_LIBRARY: {
buildSettings->AddAttribute("LIBRARY_STYLE",
this->CreateString("BUNDLE"));
if (gtgt->IsCFBundleOnApple()) {
// It turns out that a BUNDLE is basically the same
// in many ways as an application bundle, as far as
// link flags go
std::string createFlags = this->LookupFlags(
"CMAKE_SHARED_MODULE_CREATE_", llang, "_FLAGS", gtgt, "-bundle");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
}
cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
if (ext) {
buildSettings->AddAttribute("WRAPPER_EXTENSION",
this->CreateString(*ext));
}
std::string plist = this->ComputeInfoPListLocation(gtgt);
// Xcode will create the final version of Info.plist at build time,
// so let it replace the cfbundle name. This avoids creating
// a per-configuration Info.plist file. The cfbundle plist
// is very similar to the application bundle plist
this->CurrentLocalGenerator->GenerateAppleInfoPList(
gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
buildSettings->AddAttribute("MACH_O_TYPE",
this->CreateString("mh_bundle"));
buildSettings->AddAttribute("GCC_DYNAMIC_NO_PIC",
this->CreateString("NO"));
// Add the flags to create an executable.
std::string createFlags =
this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt, "");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
}
}
break;
}
case cmStateEnums::SHARED_LIBRARY: {
if (gtgt->GetPropertyAsBool("FRAMEWORK")) {
std::string fw_version = gtgt->GetFrameworkVersion();
buildSettings->AddAttribute("FRAMEWORK_VERSION",
this->CreateString(fw_version));
cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
if (ext) {
buildSettings->AddAttribute("WRAPPER_EXTENSION",
this->CreateString(*ext));
}
std::string plist = this->ComputeInfoPListLocation(gtgt);
// Xcode will create the final version of Info.plist at build time,
// so let it replace the framework name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateFrameworkInfoPList(
gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
} else {
// Add the flags to create a shared library.
std::string createFlags =
this->LookupFlags("CMAKE_SHARED_LIBRARY_CREATE_", llang, "_FLAGS",
gtgt, "-dynamiclib");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
}
}
buildSettings->AddAttribute("LIBRARY_STYLE",
this->CreateString("DYNAMIC"));
if (gtgt->HasImportLibrary(configName)) {
// Request .tbd file generation
buildSettings->AddAttribute("GENERATE_TEXT_BASED_STUBS",
this->CreateString("YES"));
}
break;
}
case cmStateEnums::EXECUTABLE: {
// Add the flags to create an executable.
std::string createFlags =
this->LookupFlags("CMAKE_", llang, "_LINK_FLAGS", gtgt, "");
if (!createFlags.empty()) {
extraLinkOptions += ' ';
extraLinkOptions += createFlags;
}
// Handle bundles and normal executables separately.
if (gtgt->GetPropertyAsBool("MACOSX_BUNDLE")) {
cmValue ext = gtgt->GetProperty("BUNDLE_EXTENSION");
if (ext) {
buildSettings->AddAttribute("WRAPPER_EXTENSION",
this->CreateString(*ext));
}
std::string plist = this->ComputeInfoPListLocation(gtgt);
// Xcode will create the final version of Info.plist at build time,
// so let it replace the executable name. This avoids creating
// a per-configuration Info.plist file.
this->CurrentLocalGenerator->GenerateAppleInfoPList(
gtgt, "$(EXECUTABLE_NAME)", plist);
buildSettings->AddAttribute("INFOPLIST_FILE",
this->CreateString(plist));
}
} break;
default:
break;
}
BuildObjectListOrString dirs(this, true);
BuildObjectListOrString fdirs(this, true);
BuildObjectListOrString sysdirs(this, true);
BuildObjectListOrString sysfdirs(this, true);
bool const emitSystemIncludes = this->XcodeVersion >= 83;
// Choose a language to use for target-wide include directories.
std::string const& langForIncludes = llang;
std::vector<std::string> includes;
if (!langForIncludes.empty()) {
this->CurrentLocalGenerator->GetIncludeDirectories(
includes, gtgt, langForIncludes, configName);
}
std::set<std::string> emitted;
emitted.insert("/System/Library/Frameworks");
for (auto& include : includes) {
if (this->NameResolvesToFramework(include)) {
std::string frameworkDir = cmStrCat(include, "/../");
frameworkDir = cmSystemTools::CollapseFullPath(frameworkDir);
if (emitted.insert(frameworkDir).second) {
std::string incpath = this->XCodeEscapePath(frameworkDir);
if (emitSystemIncludes &&
gtgt->IsSystemIncludeDirectory(frameworkDir, configName,
langForIncludes)) {
sysfdirs.Add(incpath);
} else {
fdirs.Add(incpath);
}
}
} else {
std::string incpath = this->XCodeEscapePath(include);
if (emitSystemIncludes &&
gtgt->IsSystemIncludeDirectory(include, configName,
langForIncludes)) {
sysdirs.Add(incpath);
} else {
dirs.Add(incpath);
}
}
}
// Add framework search paths needed for linking.
if (cmComputeLinkInformation* cli = gtgt->GetLinkInformation(configName)) {
for (auto const& fwDir : cli->GetFrameworkPaths()) {
if (emitted.insert(fwDir).second) {
std::string incpath = this->XCodeEscapePath(fwDir);
if (emitSystemIncludes &&
gtgt->IsSystemIncludeDirectory(fwDir, configName,
langForIncludes)) {
sysfdirs.Add(incpath);
} else {
fdirs.Add(incpath);
}
}
}
}
if (!fdirs.IsEmpty()) {
buildSettings->AddAttribute("FRAMEWORK_SEARCH_PATHS", fdirs.CreateList());
}
if (!dirs.IsEmpty()) {
buildSettings->AddAttribute("HEADER_SEARCH_PATHS", dirs.CreateList());
if (languages.count("Swift")) {
buildSettings->AddAttribute("SWIFT_INCLUDE_PATHS", dirs.CreateList());
}
}
if (!sysfdirs.IsEmpty()) {
buildSettings->AddAttribute("SYSTEM_FRAMEWORK_SEARCH_PATHS",
sysfdirs.CreateList());
}
if (!sysdirs.IsEmpty()) {
buildSettings->AddAttribute("SYSTEM_HEADER_SEARCH_PATHS",
sysdirs.CreateList());
}
if (this->XcodeVersion >= 60 && !emitSystemIncludes) {
// Add those per-language flags in addition to HEADER_SEARCH_PATHS to gain
// system include directory awareness. We need to also keep on setting
// HEADER_SEARCH_PATHS to work around a missing compile options flag for
// GNU assembly files (#16449)
for (auto const& language : languages) {
std::string includeFlags = this->CurrentLocalGenerator->GetIncludeFlags(
includes, gtgt, language, configName);
if (!includeFlags.empty()) {
cflags[language] += cmStrCat(' ', includeFlags);
}
}
}
bool same_gflags = true;
std::map<std::string, std::string> gflags;
std::string const* last_gflag = nullptr;
std::string optLevel = "0";
// Minimal map of flags to build settings.
for (auto const& language : languages) {
std::string& flags = cflags[language];
std::string& gflag = gflags[language];
std::string oflag =
this->ExtractFlagRegex("(^| )(-Ofast|-Os|-O[0-9]*)( |$)", 2, flags);
if (oflag.size() == 2) {
optLevel = "1";
} else if (oflag.size() > 2) {
optLevel = oflag.substr(2);
}
gflag = this->ExtractFlag("-g", flags);
// put back gdwarf-2 if used since there is no way
// to represent it in the gui, but we still want debug yes
if (gflag == "-gdwarf-2"_s) {
flags += ' ';
flags += gflag;
}
if (last_gflag && *last_gflag != gflag) {
same_gflags = false;
}
last_gflag = &gflag;
}
char const* debugStr = "YES";
if (!same_gflags) {
// We can't set the Xcode flag differently depending on the language,
// so put them back in this case.
for (auto const& language : languages) {
cflags[language] += ' ';
cflags[language] += gflags[language];
}
debugStr = "NO";
} else if (last_gflag && (last_gflag->empty() || *last_gflag == "-g0"_s)) {
debugStr = "NO";
}
// extract C++ stdlib
for (auto const& language : languages) {
if (language != "CXX"_s && language != "OBJCXX"_s) {
continue;
}
std::string& flags = cflags[language];
auto stdlib =
this->ExtractFlagRegex("(^| )(-stdlib=[^ ]+)( |$)", 2, flags);
if (stdlib.size() > 8) {
auto const cxxLibrary = stdlib.substr(8);
if (language == "CXX"_s ||
!buildSettings->GetAttribute("CLANG_CXX_LIBRARY")) {
buildSettings->AddAttribute("CLANG_CXX_LIBRARY",
this->CreateString(cxxLibrary));
}
}
}
buildSettings->AddAttribute("COMBINE_HIDPI_IMAGES",
this->CreateString("YES"));
buildSettings->AddAttribute("GCC_GENERATE_DEBUGGING_SYMBOLS",
this->CreateString(debugStr));
buildSettings->AddAttribute("GCC_OPTIMIZATION_LEVEL",
this->CreateString(optLevel));
buildSettings->AddAttribute("GCC_SYMBOLS_PRIVATE_EXTERN",
this->CreateString("NO"));
buildSettings->AddAttribute("GCC_INLINES_ARE_PRIVATE_EXTERN",
this->CreateString("NO"));
for (auto const& language : languages) {
std::string flags = cmStrCat(cflags[language], ' ', defFlags);
if (language == "CXX"_s || language == "OBJCXX"_s) {
if (language == "CXX"_s ||
!buildSettings->GetAttribute("OTHER_CPLUSPLUSFLAGS")) {
buildSettings->AddAttribute("OTHER_CPLUSPLUSFLAGS",
this->CreateString(flags));
}
} else if (language == "Fortran"_s) {
buildSettings->AddAttribute("IFORT_OTHER_FLAGS",
this->CreateString(flags));
} else if (language == "C"_s || language == "OBJC"_s) {
if (language == "C"_s || !buildSettings->GetAttribute("OTHER_CFLAGS")) {
buildSettings->AddAttribute("OTHER_CFLAGS", this->CreateString(flags));
}
} else if (language == "Swift"_s) {
buildSettings->AddAttribute("OTHER_SWIFT_FLAGS",
this->CreateString(flags));
}
}
// Add Fortran source format attribute if property is set.
char const* format = nullptr;
std::string const& tgtfmt = gtgt->GetSafeProperty("Fortran_FORMAT");
switch (cmOutputConverter::GetFortranFormat(tgtfmt)) {
case cmOutputConverter::FortranFormatFixed:
format = "fixed";
break;
case cmOutputConverter::FortranFormatFree:
format = "free";
break;
default:
break;
}
if (format) {
buildSettings->AddAttribute("IFORT_LANG_SRCFMT",
this->CreateString(format));
}
// Create the INSTALL_PATH attribute.
std::string install_name_dir;
if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
// Get the install_name directory for the build tree.
install_name_dir = gtgt->GetInstallNameDirForBuildTree(configName);
// Xcode doesn't create the correct install_name in some cases.
// That is, if the INSTALL_PATH is empty, or if we have versioning
// of dylib libraries, we want to specify the install_name.
// This is done by adding a link flag to create an install_name
// with just the library soname.
std::string install_name;
if (!install_name_dir.empty()) {
// Convert to a path for the native build tool.
cmSystemTools::ConvertToUnixSlashes(install_name_dir);
install_name += install_name_dir;
install_name += '/';
}
install_name += gtgt->GetSOName(configName);
if ((realName != soName) || install_name_dir.empty()) {
install_name_dir = "";
extraLinkOptions += " -install_name ";
extraLinkOptions += XCodeEscapePath(install_name);
}
}
buildSettings->AddAttribute("INSTALL_PATH",
this->CreateString(install_name_dir));
// Create the LD_RUNPATH_SEARCH_PATHS
cmComputeLinkInformation* pcli = gtgt->GetLinkInformation(configName);
if (pcli) {
std::string search_paths;
std::vector<std::string> runtimeDirs;
pcli->GetRPath(runtimeDirs, false);
// runpath dirs needs to be unique to prevent corruption
std::set<std::string> unique_dirs;
for (auto runpath : runtimeDirs) {
runpath = this->ExpandCFGIntDir(runpath, configName);
if (unique_dirs.find(runpath) == unique_dirs.end()) {
unique_dirs.insert(runpath);
if (!search_paths.empty()) {
search_paths += ' ';
}
search_paths += this->XCodeEscapePath(runpath);
}
}
if (!search_paths.empty()) {
buildSettings->AddAttribute("LD_RUNPATH_SEARCH_PATHS",
this->CreateString(search_paths));
}
}
buildSettings->AddAttribute(this->GetTargetLinkFlagsVar(gtgt),
this->CreateString(extraLinkOptions));
buildSettings->AddAttribute("OTHER_REZFLAGS", this->CreateString(""));
buildSettings->AddAttribute("SECTORDER_FLAGS", this->CreateString(""));
buildSettings->AddAttribute("ALWAYS_SEARCH_USER_PATHS",
this->CreateString("NO"));
buildSettings->AddAttribute("USE_HEADERMAP", this->CreateString("NO"));
cmXCodeObject* group = this->CreateObject(cmXCodeObject::OBJECT_LIST);
group->AddObject(this->CreateString("$(inherited)"));
buildSettings->AddAttribute("WARNING_CFLAGS", group);
// Runtime version information.
if (gtgt->GetType() == cmStateEnums::SHARED_LIBRARY) {
int major;
int minor;
int patch;
// MACHO_CURRENT_VERSION or VERSION -> current_version
gtgt->GetTargetVersionFallback("MACHO_CURRENT_VERSION", "VERSION", major,
minor, patch);
std::ostringstream v;
// Xcode always wants at least 1.0.0 or nothing
if (!(major == 0 && minor == 0 && patch == 0)) {
v << major << '.' << minor << '.' << patch;
}
buildSettings->AddAttribute("DYLIB_CURRENT_VERSION",
this->CreateString(v.str()));
// MACHO_COMPATIBILITY_VERSION or SOVERSION -> compatibility_version
gtgt->GetTargetVersionFallback("MACHO_COMPATIBILITY_VERSION", "SOVERSION",
major, minor, patch);
std::ostringstream vso;
// Xcode always wants at least 1.0.0 or nothing
if (!(major == 0 && minor == 0 && patch == 0)) {
vso << major << '.' << minor << '.' << patch;
}
buildSettings->AddAttribute("DYLIB_COMPATIBILITY_VERSION",
this->CreateString(vso.str()));
}
// Precompile Headers
std::string pchHeader =
gtgt->GetPchHeader(configName, langForPreprocessorDefinitions);
if (!pchHeader.empty()) {
buildSettings->AddAttribute("GCC_PREFIX_HEADER",
this->CreateString(pchHeader));
buildSettings->AddAttribute("GCC_PRECOMPILE_PREFIX_HEADER",
this->CreateString("YES"));
}
// put this last so it can override existing settings
// Convert "XCODE_ATTRIBUTE_*" properties directly.
{
for (auto const& prop : gtgt->GetPropertyKeys()) {
if (cmHasLiteralPrefix(prop, "XCODE_ATTRIBUTE_")) {
std::string attribute = prop.substr(16);
this->FilterConfigurationAttribute(configName, attribute);
if (!attribute.empty()) {
std::string const& pr = gtgt->GetSafeProperty(prop);
std::string processed = cmGeneratorExpression::Evaluate(
pr, this->CurrentLocalGenerator, configName);
buildSettings->AddAttribute(attribute,
this->CreateString(processed));
}
}
}
}
}