diff --git a/Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift b/Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift index 89f2637ff0b..721153fb251 100644 --- a/Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift +++ b/Sources/Build/BuildDescription/SwiftModuleBuildDescription.swift @@ -969,6 +969,12 @@ public final class SwiftModuleBuildDescription { break } + if bundlePath != nil { + compilationConditions += ["-DSWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + } else { + compilationConditions += ["-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + } + return compilationConditions } diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift index 028c9e537ea..c7204032eb2 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Modules.swift @@ -596,6 +596,20 @@ extension PackagePIFProjectBuilder { settings[.COREML_COMPILER_CONTAINER] = "swift-package" } + if sourceModule.usesSwift { + // Leave an explicit indicator regarding whether we are generating a Bundle.module accessor. + // This will be read by the #bundle macro defined in Foundation. + if !shouldGenerateBundleAccessor { + // No resources, so explicitly indicate that. + // #bundle will then produce an error about there being no resources. + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitializeAndMutate(initialValue: ["$(inherited)"]) { $0.append("SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE") } + } else if !(resourceBundleName?.isEmpty ?? true) { + // We have an explicit resource bundle via Bundle.module. + // #bundle should call into that. + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitializeAndMutate(initialValue: ["$(inherited)"]) { $0.append("SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE") } + } // else we won't set either of those and just let #bundle point to the same bundle as the source code. + } + if desiredModuleType == .macro { settings[.SWIFT_IMPLEMENTS_MACROS_FOR_MODULE_NAMES] = [sourceModule.c99name] } diff --git a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift index d9cb5d42b7f..32abc8fd371 100644 --- a/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift +++ b/Sources/SwiftBuildSupport/PackagePIFProjectBuilder+Products.swift @@ -245,6 +245,9 @@ extension PackagePIFProjectBuilder { if result.shouldGenerateBundleAccessor { settings[.GENERATE_RESOURCE_ACCESSORS] = "YES" + + // Do not set `SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE` here since it is just going to point to the same bundle as code. + // #bundle can use its default implementation for that. } if result.shouldGenerateEmbedInCodeAccessor { settings[.GENERATE_EMBED_IN_CODE_ACCESSORS] = "YES" @@ -264,6 +267,12 @@ extension PackagePIFProjectBuilder { if result.shouldGenerateBundleAccessor { settings[.GENERATE_RESOURCE_ACCESSORS] = "YES" + + if mainModule.usesSwift { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitializeAndMutate(initialValue: ["$(inherited)"]) { $0.append("SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE") } + } + } else if mainModule.usesSwift { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS].lazilyInitializeAndMutate(initialValue: ["$(inherited)"]) { $0.append("SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE") } } if result.shouldGenerateEmbedInCodeAccessor { settings[.GENERATE_EMBED_IN_CODE_ACCESSORS] = "YES" @@ -305,6 +314,9 @@ extension PackagePIFProjectBuilder { settings[.GENERATE_RESOURCE_ACCESSORS] = "YES" settings[.GENERATE_EMBED_IN_CODE_ACCESSORS] = "NO" + // Do not set `SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE` here since it is just going to point to the same bundle as code. + // #bundle can use its default implementation for that. + // If we did not create a resource bundle target, // we still need to add build tool commands for any generated files. addBuildToolCommands( diff --git a/Sources/XCBuildSupport/PIFBuilder.swift b/Sources/XCBuildSupport/PIFBuilder.swift index 3d020614783..283379fedd1 100644 --- a/Sources/XCBuildSupport/PIFBuilder.swift +++ b/Sources/XCBuildSupport/PIFBuilder.swift @@ -488,12 +488,14 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { settings[.GENERATE_INFOPLIST_FILE] = "YES" } + var isSwiftModule = false if let clangTarget = mainTarget.underlying as? ClangModule { // Let the target itself find its own headers. settings[.HEADER_SEARCH_PATHS, default: ["$(inherited)"]].append(clangTarget.includeDir.pathString) settings[.GCC_C_LANGUAGE_STANDARD] = clangTarget.cLanguageStandard settings[.CLANG_CXX_LANGUAGE_STANDARD] = clangTarget.cxxLanguageStandard } else if let swiftTarget = mainTarget.underlying as? SwiftModule { + isSwiftModule = true try settings.addSwiftVersionSettings(target: swiftTarget, parameters: self.parameters) settings.addCommonSwiftSettings(package: self.package, target: mainTarget, parameters: self.parameters) } @@ -501,6 +503,12 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { if let resourceBundle = addResourceBundle(for: mainTarget, in: pifTarget) { settings[.PACKAGE_RESOURCE_BUNDLE_NAME] = resourceBundle settings[.GENERATE_RESOURCE_ACCESSORS] = "YES" + + if isSwiftModule { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS, default: ["$(inherited)"]].append("SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE") + } + } else if isSwiftModule { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS, default: ["$(inherited)"]].append("SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE") } // For targets, we use the common build settings for both the "Debug" and the "Release" configurations (all @@ -654,6 +662,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { let moduleMapFileContents: String? let shouldImpartModuleMap: Bool + var isSwiftModule = false if let clangTarget = target.underlying as? ClangModule { // Let the target itself find its own headers. settings[.HEADER_SEARCH_PATHS, default: ["$(inherited)"]].append(clangTarget.includeDir.pathString) @@ -680,6 +689,7 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { shouldImpartModuleMap = false } } else if let swiftTarget = target.underlying as? SwiftModule { + isSwiftModule = true try settings.addSwiftVersionSettings(target: swiftTarget, parameters: self.parameters) // Generate ObjC compatibility header for Swift library targets. @@ -729,7 +739,12 @@ final class PackagePIFProjectBuilder: PIFProjectBuilder { if let resourceBundle = addResourceBundle(for: target, in: pifTarget) { settings[.PACKAGE_RESOURCE_BUNDLE_NAME] = resourceBundle settings[.GENERATE_RESOURCE_ACCESSORS] = "YES" + if isSwiftModule { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS, default: ["$(inherited)"]].append("SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE") + } impartedSettings[.EMBED_PACKAGE_RESOURCE_BUNDLE_NAMES, default: ["$(inherited)"]].append(resourceBundle) + } else if isSwiftModule { + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS, default: ["$(inherited)"]].append("SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE") } // For targets, we use the common build settings for both the "Debug" and the "Release" configurations (all diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 914b46130a4..a526f38f4d9 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -792,6 +792,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -811,6 +812,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -1224,6 +1226,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { "-O", .equal(self.j), "-DSWIFT_PACKAGE", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -1318,6 +1321,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { "-O", .equal(self.j), "-DSWIFT_PACKAGE", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -1863,6 +1867,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-Xcc", "-fmodule-map-file=\(buildPath.appending(components: "lib.build", "module.modulemap"))", "-Xcc", "-I", "-Xcc", "\(Pkg.appending(components: "Sources", "lib", "include"))", @@ -2365,6 +2370,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -2387,6 +2393,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -2499,6 +2506,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { "-O", .equal(self.j), "-DSWIFT_PACKAGE", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -2864,6 +2872,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-Xcc", "-fmodule-map-file=\(Clibgit.appending(components: "module.modulemap"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, @@ -3166,6 +3175,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -3185,6 +3195,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { .equal(self.j), "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, "-swift-version", "4", @@ -3824,7 +3835,7 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { "-Onone", "-enable-testing", .equal(self.j), - "-DSWIFT_PACKAGE", "-DDEBUG", + "-DSWIFT_PACKAGE", "-DDEBUG", "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-Xcc", "-fmodule-map-file=\(buildPath.appending(components: "lib.build", "module.modulemap"))", "-Xcc", "-I", "-Xcc", "\(Pkg.appending(components: "Sources", "lib", "include"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", @@ -5888,6 +5899,9 @@ class BuildPlanTestCase: BuildSystemProviderTestCase { XCTAssertEqual(try barTarget.objects.map(\.pathString), [ buildPath.appending(components: "Bar.build", "Bar.swift.o").pathString, ]) + + XCTAssertTrue(try fooTarget.compileArguments().contains(["-DSWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"])) + XCTAssertTrue(try barTarget.compileArguments().contains(["-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"])) } func testSwiftWASIBundleAccessor() async throws { diff --git a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift index 698ad2c8183..27a5412487b 100644 --- a/Tests/BuildTests/CrossCompilationBuildPlanTests.swift +++ b/Tests/BuildTests/CrossCompilationBuildPlanTests.swift @@ -179,7 +179,7 @@ final class CrossCompilationBuildPlanTests: XCTestCase { exe, [ "-enable-batch-mode", "-serialize-diagnostics", "-Onone", "-enable-testing", - "-j3", "-DSWIFT_PACKAGE", "-DDEBUG", "-Xcc", + "-j3", "-DSWIFT_PACKAGE", "-DDEBUG", "-DSWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE", "-Xcc", "-fmodule-map-file=\(buildPath.appending(components: "lib.build", "module.modulemap"))", "-Xcc", "-I", "-Xcc", "\(pkgPath.appending(components: "Sources", "lib", "include"))", "-module-cache-path", "\(buildPath.appending(components: "ModuleCache"))", .anySequence, diff --git a/Tests/XCBuildSupportTests/PIFBuilderTests.swift b/Tests/XCBuildSupportTests/PIFBuilderTests.swift index 172d59f255b..3d380a77dcf 100644 --- a/Tests/XCBuildSupportTests/PIFBuilderTests.swift +++ b/Tests/XCBuildSupportTests/PIFBuilderTests.swift @@ -542,6 +542,10 @@ final class PIFBuilderTests: XCTestCase { settings[.LIBRARY_SEARCH_PATHS], ["$(inherited)", "/toolchain/lib/swift/macosx"] ) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -567,6 +571,10 @@ final class PIFBuilderTests: XCTestCase { settings[.LIBRARY_SEARCH_PATHS], ["$(inherited)", "/toolchain/lib/swift/macosx"] ) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -671,6 +679,10 @@ final class PIFBuilderTests: XCTestCase { settings[.LIBRARY_SEARCH_PATHS], ["$(inherited)", "/toolchain/lib/swift/macosx"] ) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -690,6 +702,10 @@ final class PIFBuilderTests: XCTestCase { settings[.LIBRARY_SEARCH_PATHS], ["$(inherited)", "/toolchain/lib/swift/macosx"] ) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -877,6 +893,10 @@ final class PIFBuilderTests: XCTestCase { "$(inherited)", "/toolchain/lib/swift/macosx", ]) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) XCTAssertEqual(settings[.PACKAGE_RESOURCE_TARGET_KIND], "regular") XCTAssertEqual(settings[.PRODUCT_BUNDLE_IDENTIFIER], "FooTests") XCTAssertEqual(settings[.PRODUCT_MODULE_NAME], "FooTests") @@ -924,6 +944,10 @@ final class PIFBuilderTests: XCTestCase { "$(inherited)", "/toolchain/lib/swift/macosx", ]) + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) XCTAssertEqual(settings[.PACKAGE_RESOURCE_TARGET_KIND], "regular") XCTAssertEqual(settings[.PRODUCT_BUNDLE_IDENTIFIER], "FooTests") XCTAssertEqual(settings[.PRODUCT_MODULE_NAME], "FooTests") @@ -1395,6 +1419,10 @@ final class PIFBuilderTests: XCTestCase { XCTAssertEqual(settings[.SWIFT_OBJC_INTERFACE_HEADER_NAME], "FooLib1-Swift.h") XCTAssertEqual(settings[.SWIFT_VERSION], "5") XCTAssertEqual(settings[.TARGET_NAME], "FooLib1_Module") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -1428,6 +1456,10 @@ final class PIFBuilderTests: XCTestCase { XCTAssertEqual(settings[.SWIFT_OBJC_INTERFACE_HEADER_NAME], "FooLib1-Swift.h") XCTAssertEqual(settings[.SWIFT_VERSION], "5") XCTAssertEqual(settings[.TARGET_NAME], "FooLib1_Module") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_UNAVAILABLE"] + ) } } @@ -2224,12 +2256,20 @@ final class PIFBuilderTests: XCTestCase { target.checkBuildConfiguration("Debug") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_foo") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } } - target.checkBuildConfiguration("Debug") { configuration in + target.checkBuildConfiguration("Release") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_foo") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } } @@ -2287,7 +2327,7 @@ final class PIFBuilderTests: XCTestCase { } } - target.checkBuildConfiguration("Debug") { configuration in + target.checkBuildConfiguration("Release") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], nil) } @@ -2305,12 +2345,20 @@ final class PIFBuilderTests: XCTestCase { target.checkBuildConfiguration("Debug") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_FooLib") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } } - target.checkBuildConfiguration("Debug") { configuration in + target.checkBuildConfiguration("Release") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_FooLib") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } } @@ -2326,12 +2374,20 @@ final class PIFBuilderTests: XCTestCase { target.checkBuildConfiguration("Debug") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_FooTests") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } } - target.checkBuildConfiguration("Debug") { configuration in + target.checkBuildConfiguration("Release") { configuration in configuration.checkBuildSettings { settings in XCTAssertEqual(settings[.PACKAGE_RESOURCE_BUNDLE_NAME], "Foo_FooTests") + XCTAssertEqual( + settings[.SWIFT_ACTIVE_COMPILATION_CONDITIONS], + ["$(inherited)", "SWIFT_MODULE_RESOURCE_BUNDLE_AVAILABLE"] + ) } }