From c0dd3dd2c13d8b7621bc86b6ea93e9188ab5dba7 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 25 Oct 2022 11:56:34 -0400 Subject: Xcode: Evaluate Swift compile definitions separately Xcode has a separate setting for Swift compile definitions, so we can compute a dedicated value for it. Therefore we can: * Support the COMPILE_LANGUAGE generator expression for Swift-specific filters. * Avoid passing the `=value` part of definitions, which Swift does not support. This revises commit 5cb625eb2f (Xcode: Pass compile definitions to Swift, 2022-06-19, v3.25.0-rc1~493^2) and reverts commit 12c6fec6b4 (Xcode: Drop CMAKE_INTDIR= definition in Swift targets, 2022-09-30, v3.25.0-rc1~60^2~2), as the latter is no longer needed. Fixes: #24086 --- Source/cmGlobalXCodeGenerator.cxx | 43 +++++++++++++++++++++++++++++---------- Tests/SwiftMix/CMain.c | 13 ++++++++++++ Tests/SwiftMix/CMakeLists.txt | 1 + Tests/SwiftMix/SwiftMain.swift | 20 ++++++++++++++++++ 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index a1af268..6328d29 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2387,7 +2387,20 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, gtgt->GetName()); return; } - std::string const& langForPreprocessor = llang; + + // Choose a language to use for target-wide preprocessor definitions. + static const char* ppLangs[] = { "CXX", "C", "OBJCXX", "OBJC" }; + std::string langForPreprocessor; + if (cm::contains(ppLangs, llang)) { + langForPreprocessor = llang; + } else { + for (const char* l : ppLangs) { + if (languages.count(l)) { + langForPreprocessor = l; + break; + } + } + } if (gtgt->IsIPOEnabled(llang, configName)) { const char* ltoValue = @@ -2404,13 +2417,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, // Add preprocessor definitions for this target and configuration. BuildObjectListOrString ppDefs(this, true); - if (languages.count("Swift")) { - // FIXME: Xcode warns that Swift does not support definition values. - // C/CXX sources mixed in Swift targets will not see CMAKE_INTDIR. - } else { - this->AppendDefines( - ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\""); - } + this->AppendDefines( + ppDefs, "CMAKE_INTDIR=\"$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)\""); if (const std::string* exportMacro = gtgt->GetExportMacro()) { // Add the export symbol definition for shared library objects. this->AppendDefines(ppDefs, exportMacro->c_str()); @@ -2424,15 +2432,28 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, buildSettings->AddAttribute("GCC_PREPROCESSOR_DEFINITIONS", ppDefs.CreateList()); if (languages.count("Swift")) { + // Swift uses a separate attribute for definitions. + std::vector 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 defines(targetDefines.begin(), - targetDefines.end()); + std::set defines(targetSwiftDefines.begin(), + targetSwiftDefines.end()); this->CurrentLocalGenerator->JoinDefines(defines, defineString, "Swift"); cflags["Swift"] += " " + defineString; } else { + BuildObjectListOrString swiftDefs(this, true); + this->AppendDefines(swiftDefs, targetSwiftDefines); buildSettings->AddAttribute("SWIFT_ACTIVE_COMPILATION_CONDITIONS", - ppDefs.CreateList()); + swiftDefs.CreateList()); } } diff --git a/Tests/SwiftMix/CMain.c b/Tests/SwiftMix/CMain.c index 519058e..b274322 100644 --- a/Tests/SwiftMix/CMain.c +++ b/Tests/SwiftMix/CMain.c @@ -1,3 +1,16 @@ +#if !defined(FOO) +# error "FOO not defined" +#endif +#if BAR != 3 +# error "FOO not defined to 3" +#endif +#if CCOND != 2 +# error "CCOND not defined to 2" +#endif +#if defined(SWIFTCOND) +# error "SWIFTCOND defined" +#endif + extern int ObjCMain(void); int main(void) { diff --git a/Tests/SwiftMix/CMakeLists.txt b/Tests/SwiftMix/CMakeLists.txt index 6d8e48b..e8b6521 100644 --- a/Tests/SwiftMix/CMakeLists.txt +++ b/Tests/SwiftMix/CMakeLists.txt @@ -4,3 +4,4 @@ project(SwiftMix C Swift) add_executable(SwiftMix CMain.c ObjCMain.m SwiftMain.swift ObjC-Swift.h) set_property(TARGET SwiftMix PROPERTY XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER "ObjC-Swift.h") target_compile_options(SwiftMix PRIVATE "$<$:-Werror=objc-method-access>") +target_compile_definitions(SwiftMix PRIVATE "$,SWIFTCOND,CCOND=2>" FOO BAR=3) diff --git a/Tests/SwiftMix/SwiftMain.swift b/Tests/SwiftMix/SwiftMain.swift index d9c8cd7..238059d 100644 --- a/Tests/SwiftMix/SwiftMain.swift +++ b/Tests/SwiftMix/SwiftMain.swift @@ -3,6 +3,26 @@ import Foundation @objc class SwiftMainClass : NSObject { @objc class func SwiftMain() -> Int32 { dump("Hello World!"); +#if FOO + dump("FOO defined"); +#else + fatalError("FOO not defined"); +#endif +#if BAR + dump("BAR defined"); +#else + fatalError("BAR not defined"); +#endif +#if CCOND + fatalError("CCOND defined"); +#else + dump("CCOND not defined"); +#endif +#if SWIFTCOND + dump("SWIFTCOND defined"); +#else + fatalError("SWIFTCOND not defined"); +#endif return 0; } } -- cgit v0.12