diff --git a/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst index 122b9f6b0..be683d668 100644 --- a/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst +++ b/Help/variable/CMAKE_XCODE_ATTRIBUTE_an-attribute.rst @@ -8,3 +8,9 @@ in the generated Xcode project. Ignored on other generators. See the :prop_tgt:`XCODE_ATTRIBUTE_` target property to set attributes on a specific target. + +Contents of ``CMAKE_XCODE_ATTRIBUTE_`` may use +"generator expressions" with the syntax ``$<...>``. See the +:manual:`cmake-generator-expressions(7)` manual for available +expressions. See the :manual:`cmake-buildsystem(7)` manual +for more on defining buildsystem properties. diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 3ac113782..fa9af121b 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -709,6 +709,15 @@ cmXCodeObject* cmGlobalXCodeGenerator return obj; } +//---------------------------------------------------------------------------- +cmXCodeObject* cmGlobalXCodeGenerator +::CreateFlatClone(cmXCodeObject* orig) +{ + cmXCodeObject* obj = this->CreateObject(orig->GetType()); + obj->CopyAttributes(orig); + return obj; +} + //---------------------------------------------------------------------------- std::string GetGroupMapKeyFromPath(cmGeneratorTarget* target, const std::string& fullpath) @@ -3531,25 +3540,33 @@ bool cmGlobalXCodeGenerator symroot += "/build"; buildSettings->AddAttribute("SYMROOT", this->CreateString(symroot.c_str())); - // Put this last so it can override existing settings - // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. - { - std::vector vars = this->CurrentMakefile->GetDefinitions(); - for(std::vector::const_iterator i = vars.begin(); - i != vars.end(); ++i) - { - if(i->find("CMAKE_XCODE_ATTRIBUTE_") == 0) - { - buildSettings->AddAttribute(i->substr(22).c_str(), - this->CreateString( - this->CurrentMakefile->GetDefinition(i->c_str()))); - } - } - } - for(Configs::iterator i = configs.begin(); i != configs.end(); ++i) { - i->second->AddAttribute("buildSettings", buildSettings); + cmXCodeObject* buildSettingsForCfg = this->CreateFlatClone(buildSettings); + + // Put this last so it can override existing settings + // Convert "CMAKE_XCODE_ATTRIBUTE_*" variables directly. + std::vector vars = this->CurrentMakefile->GetDefinitions(); + for(std::vector::const_iterator d = vars.begin(); + d != vars.end(); ++d) + { + if(d->find("CMAKE_XCODE_ATTRIBUTE_") == 0) + { + std::string attribute = d->substr(22); + this->FilterConfigurationAttribute(i->first, attribute); + if(!attribute.empty()) + { + cmGeneratorExpression ge; + std::string processed = + ge.Parse(this->CurrentMakefile->GetDefinition(*d)) + ->Evaluate(this->CurrentLocalGenerator, i->first); + buildSettingsForCfg->AddAttribute(attribute, + this->CreateString(processed)); + } + } + } + // store per-config buildSettings into configuration object + i->second->AddAttribute("buildSettings", buildSettingsForCfg); } this->RootObject->AddAttribute("buildConfigurationList", diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 4801064c2..965982235 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -131,6 +131,7 @@ private: cmXCodeObject* CreateObject(cmXCodeObject::Type type); cmXCodeObject* CreateString(const std::string& s); cmXCodeObject* CreateObjectReference(cmXCodeObject*); + cmXCodeObject* CreateFlatClone(cmXCodeObject*); cmXCodeObject* CreateXCodeTarget(cmGeneratorTarget *gtgt, cmXCodeObject* buildPhases); void ForceLinkerLanguages(); diff --git a/Tests/RunCMake/XcodeProject/XcodeAttributeGenex-check.cmake b/Tests/RunCMake/XcodeProject/XcodeAttributeGenex-check.cmake index 637df0fd7..8a3950671 100644 --- a/Tests/RunCMake/XcodeProject/XcodeAttributeGenex-check.cmake +++ b/Tests/RunCMake/XcodeProject/XcodeAttributeGenex-check.cmake @@ -1,3 +1,5 @@ +# per target attribute with genex + set(expect "TEST_HOST = \"[^;\"]*Tests/RunCMake/XcodeProject/XcodeAttributeGenex-build/[^;\"/]*/some\"") file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodeAttributeGenex.xcodeproj/project.pbxproj actual REGEX "TEST_HOST = .*;" LIMIT_COUNT 1) @@ -5,3 +7,49 @@ if(NOT "${actual}" MATCHES "${expect}") message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" "which does not match expected regex:\n ${expect}\n") endif() + +# per target attribute with variant + +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodeAttributeGenex.xcodeproj/project.pbxproj actual + REGEX "CONFIG_SPECIFIC = .*;") +list(REMOVE_DUPLICATES actual) + +set(expect "CONFIG_SPECIFIC = general") +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() + +set(expect "CONFIG_SPECIFIC = release") +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() + +# global attribute with genex + +set(expect "ANOTHER_GLOBAL = \"[^;\"]*Tests/RunCMake/XcodeProject/XcodeAttributeGenex-build/[^;\"/]*/another\"") +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodeAttributeGenex.xcodeproj/project.pbxproj actual + REGEX "ANOTHER_GLOBAL = .*;" LIMIT_COUNT 1) +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() + +# global attribute with variant + +file(STRINGS ${RunCMake_TEST_BINARY_DIR}/XcodeAttributeGenex.xcodeproj/project.pbxproj actual + REGEX "ANOTHER_CONFIG = .*;" LIMIT_COUNT 4) +list(REMOVE_DUPLICATES actual) + +set(expect "ANOTHER_CONFIG = general") +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() + +set(expect "ANOTHER_CONFIG = debug") +if(NOT "${actual}" MATCHES "${expect}") + message(SEND_ERROR "The actual project contains the line:\n ${actual}\n" + "which does not match expected regex:\n ${expect}\n") +endif() diff --git a/Tests/RunCMake/XcodeProject/XcodeAttributeGenex.cmake b/Tests/RunCMake/XcodeProject/XcodeAttributeGenex.cmake index 760b882c6..d8cb3bd23 100644 --- a/Tests/RunCMake/XcodeProject/XcodeAttributeGenex.cmake +++ b/Tests/RunCMake/XcodeProject/XcodeAttributeGenex.cmake @@ -1,4 +1,16 @@ enable_language(C) add_executable(some main.c) add_executable(another main.c) -set_property(TARGET another PROPERTY XCODE_ATTRIBUTE_TEST_HOST "$") +set_target_properties(another PROPERTIES + # per target attribute with genex + XCODE_ATTRIBUTE_TEST_HOST "$" + # per target attribute with variant + XCODE_ATTRIBUTE_CONFIG_SPECIFIC[variant=Release] "release" + XCODE_ATTRIBUTE_CONFIG_SPECIFIC "general") + +# global attribute with genex +set(CMAKE_XCODE_ATTRIBUTE_ANOTHER_GLOBAL "$") + +# global attribute with variant +set(CMAKE_XCODE_ATTRIBUTE_ANOTHER_CONFIG "general") +set(CMAKE_XCODE_ATTRIBUTE_ANOTHER_CONFIG[variant=Debug] "debug")