Repository: swiftlang/swift-build
Pull request #488: Include xcspec resources in the CMake build
Author: login: owenv
Created: 2025-05-05T16:43:08Z | Merged: 2025-05-08T19:32:40Z

Builds on a rebased https://github.com/swiftlang/swift-build/pull/243 by @compnerd 

- Add SwiftBuild_Bundle to handle assembly of the resource bundles
- Move resource bundle access generation inside so it can be shared among all the targets


Diff:
diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt
index 6c2fd9d49..15dd49175 100644
--- a/Sources/CMakeLists.txt
+++ b/Sources/CMakeLists.txt
@@ -8,6 +8,48 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources" _SWIFT_BUILD_RESOURCE_BUNDLE_BUILD_PATH)
+  file(CONFIGURE
+    OUTPUT "${CMAKE_BINARY_DIR}/resource_accessors/SwiftBuild_${BundleXCSpecs_MODULE}_resource_bundle_accessor.swift"
+    CONTENT [[
+    import Foundation
+    extension Foundation.Bundle {
+      static let module: Bundle = {
+        let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_@BundleXCSpecs_MODULE@.resources").path
+        let buildPath = #"@_SWIFT_BUILD_RESOURCE_BUNDLE_BUILD_PATH@"#
+        let preferredBundle = Bundle(path: mainPath)
+        guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
+          Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
+        }
+        return bundle
+      }()
+    }
+    ]]
+    ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
+
+  target_sources("${BundleXCSpecs_MODULE}" PRIVATE
+    "${CMAKE_BINARY_DIR}/resource_accessors/SwiftBuild_${BundleXCSpecs_MODULE}_resource_bundle_accessor.swift")
+
+  install(DIRECTORY
+    "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources/"
+    DESTINATION share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources/)
+endfunction()
+
 add_subdirectory(SWBCSupport)
 add_subdirectory(SWBCLibc)
 add_subdirectory(SWBLibc)
diff --git a/Sources/SWBAndroidPlatform/CMakeLists.txt b/Sources/SWBAndroidPlatform/CMakeLists.txt
index 9cf4c2c49..fdb0bfa70 100644
--- a/Sources/SWBAndroidPlatform/CMakeLists.txt
+++ b/Sources/SWBAndroidPlatform/CMakeLists.txt
@@ -8,35 +8,15 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBAndroidPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBAndroidPlatform.resources").path
-      let buildPath = #"@_SWBAndroidPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBAndroidPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBAndroidPlatform
   AndroidSDK.swift
   Plugin.swift)
+SwiftBuild_Bundle(MODULE SWBAndroidPlatform FILES
+  Specs/Android.xcspec)
 target_link_libraries(SWBAndroidPlatform PUBLIC
   SWBCore
   SWBMacro
   SWBUtil)
-target_sources(SWBAndroidPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBAndroidPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBApplePlatform/CMakeLists.txt b/Sources/SWBApplePlatform/CMakeLists.txt
index fb516d7b9..49009e0b6 100644
--- a/Sources/SWBApplePlatform/CMakeLists.txt
+++ b/Sources/SWBApplePlatform/CMakeLists.txt
@@ -8,26 +8,6 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBApplePlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBApplePlatform.resources").path
-      let buildPath = #"@_SWBApplePlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBApplePlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBApplePlatform
   AppIntentsMetadataCompiler.swift
   AppIntentsMetadataTaskProducer.swift
@@ -65,6 +45,77 @@ add_library(SWBApplePlatform
   StringCatalogCompilerOutputParser.swift
   StubBinaryTaskProducer.swift
   XCStringsInputFileGroupingStrategy.swift)
+SwiftBuild_Bundle(MODULE SWBApplePlatform FILES
+  Specs/AppIntentsMetadata.xcspec
+  Specs/AppIntentsNLTraining.xcspec
+  Specs/AppShortcutStringsMetadata.xcspec
+  Specs/AssetCatalogCompiler.xcspec
+  Specs/CompileSkybox.xcspec
+  Specs/CopyPNGFile.xcspec
+  Specs/CopyTiffFile.xcspec
+  "Specs/Core Data.xcspec"
+  Specs/CoreML.xcspec
+  "Specs/Darwin Package Types.xcspec"
+  "Specs/Darwin Product Types.xcspec"
+  Specs/DriverKit.xcspec
+  Specs/DTrace.xcspec
+  Specs/Embedded-Device.xcspec
+  Specs/Embedded-Shared.xcspec
+  Specs/Embedded-Simulator.xcspec
+  Specs/EmbeddedBinaryValidationUtility.xcspec
+  Specs/GenerateAppPlaygroundAssetCatalog.xcspec
+  Specs/GenerateTextureAtlas.xcspec
+  Specs/IBCompiler.xcspec
+  Specs/IBPostprocessor.xcspec
+  Specs/IBStoryboardCompiler.xcspec
+  Specs/IBStoryboardLinker.xcspec
+  Specs/IBStoryboardPostprocessor.xcspec
+  Specs/Iconutil.xcspec
+  Specs/Iig.xcspec
+  Specs/InfoPlistUtility.xcspec
+  Specs/InstrumentsPackage.xcspec
+  Specs/Intents.xcspec
+  "Specs/Interface Builder File Types.xcspec"
+  "Specs/iOS Device.xcspec"
+  "Specs/iOS Shared.xcspec"
+  "Specs/iOS Simulator.xcspec"
+  Specs/KernelExtension.xcspec
+  Specs/Lipo.xcspec
+  Specs/LSRegisterURL.xcspec
+  "Specs/MacOSX Architectures.xcspec"
+  "Specs/MacOSX Core Build System.xcspec"
+  "Specs/MacOSX Native Build System.xcspec"
+  "Specs/MacOSX Package Types.xcspec"
+  "Specs/MacOSX Product Types.xcspec"
+  Specs/MetalCompiler.xcspec
+  Specs/MetalFileTypes.xcspec
+  Specs/MetalLinker.xcspec
+  Specs/MetalPackageTypes.xcspec
+  Specs/MetalProductTypes.xcspec
+  Specs/MiG.xcspec
+  Specs/OpenCL.xcspec
+  Specs/OSACompile.xcspec
+  Specs/RCFileTypes.xcspec
+  Specs/RealityAssets.xcspec
+  Specs/ReferenceObject.xcspec
+  Specs/ResMerger.xcspec
+  Specs/Rez.xcspec
+  "Specs/SceneKit FileTypes.xcspec"
+  "Specs/SceneKit Tools.xcspec"
+  Specs/SpriteKitFileTypes.xcspec
+  Specs/TiffUtil.xcspec
+  "Specs/tvOS Device.xcspec"
+  "Specs/tvOS Shared.xcspec"
+  "Specs/tvOS Simulator.xcspec"
+  Specs/WatchKit1ProductTypes.xcspec
+  "Specs/watchOS Device.xcspec"
+  "Specs/watchOS Shared.xcspec"
+  "Specs/watchOS Simulator.xcspec"
+  Specs/XCAppExtensionPoints.xcspec
+  Specs/XCStrings.xcspec
+  "Specs/xrOS Device.xcspec"
+  "Specs/xrOS Shared.xcspec"
+  "Specs/xrOS Simulator.xcspec")
 set_target_properties(SWBApplePlatform PROPERTIES
   Swift_LANGUAGE_VERSION 6)
 target_link_libraries(SWBApplePlatform PUBLIC
@@ -73,8 +124,6 @@ target_link_libraries(SWBApplePlatform PUBLIC
   SWBUtil
   SWBProtocol
   SWBTaskConstruction)
-target_sources(SWBApplePlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBApplePlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBCore/CMakeLists.txt b/Sources/SWBCore/CMakeLists.txt
index aecee403c..9dd6a4bb9 100644
--- a/Sources/SWBCore/CMakeLists.txt
+++ b/Sources/SWBCore/CMakeLists.txt
@@ -8,26 +8,6 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBCore_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBCore.resources").path
-      let buildPath = #"@_SWBCore_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBCore.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBCore
   ActivityReporting.swift
   Apple/DeviceFamily.swift
@@ -195,6 +175,10 @@ add_library(SWBCore
   WorkspaceContext.swift
   WorkspaceSettingsCache.swift
   XCFramework.swift)
+SwiftBuild_Bundle(MODULE SWBCore FILES
+  Specs/CoreBuildSystem.xcspec
+  Specs/ExternalBuildSystem.xcspec
+  Specs/NativeBuildSystem.xcspec)
 set_target_properties(SWBCore PROPERTIES
   Swift_LANGUAGE_VERSION 5)
 target_link_libraries(SWBCore PUBLIC
@@ -205,8 +189,6 @@ target_link_libraries(SWBCore PUBLIC
   SWBCAS
   SWBLLBuild
   SwiftDriver)
-target_sources(SWBCore PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBCore PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBGenericUnixPlatform/CMakeLists.txt b/Sources/SWBGenericUnixPlatform/CMakeLists.txt
index 4a7550cf3..b0858c296 100644
--- a/Sources/SWBGenericUnixPlatform/CMakeLists.txt
+++ b/Sources/SWBGenericUnixPlatform/CMakeLists.txt
@@ -8,33 +8,16 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBGenericUnixPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBGenericUnixPlatform.resources").path
-      let buildPath = #"@_SWBGenericUnixPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBGenericUnixPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBGenericUnixPlatform
   Plugin.swift)
+SwiftBuild_Bundle(MODULE SWBGenericUnixPlatform FILES
+  Specs/Unix.xcspec
+  Specs/UnixCompile.xcspec
+  Specs/UnixLd.xcspec
+  Specs/UnixLibtool.xcspec)
 target_link_libraries(SWBGenericUnixPlatform PUBLIC
   SWBCore
   SWBUtil)
-target_sources(SWBGenericUnixPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBGenericUnixPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBQNXPlatform/CMakeLists.txt b/Sources/SWBQNXPlatform/CMakeLists.txt
index 23249e86c..83f809a65 100644
--- a/Sources/SWBQNXPlatform/CMakeLists.txt
+++ b/Sources/SWBQNXPlatform/CMakeLists.txt
@@ -8,35 +8,18 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBQNXPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBQNXPlatform.resources").path
-      let buildPath = #"@_SWBQNXPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBQNXPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBQNXPlatform
   Plugin.swift
   QNXSDP.swift)
+SwiftBuild_Bundle(MODULE SWBQNXPlatform FILES
+  Specs/QNX.xcspec
+  Specs/QNXCompile.xcspec
+  Specs/QNXLd.xcspec
+  Specs/QNXLibtool.xcspec)
 target_link_libraries(SWBQNXPlatform PUBLIC
   SWBCore
   SWBMacro
   SWBUtil)
-target_sources(SWBQNXPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBQNXPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBUniversalPlatform/CMakeLists.txt b/Sources/SWBUniversalPlatform/CMakeLists.txt
index 7b0fffd76..796d74a1e 100644
--- a/Sources/SWBUniversalPlatform/CMakeLists.txt
+++ b/Sources/SWBUniversalPlatform/CMakeLists.txt
@@ -8,26 +8,6 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBUniversalPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBUniversalPlatform.resources").path
-      let buildPath = #"@_SWBUniversalPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBUniversalPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBUniversalPlatform
   CopyPlistFile.swift
   CopyStringsFile.swift
@@ -39,6 +19,37 @@ add_library(SWBUniversalPlatform
   TestEntryPointTaskProducer.swift
   YaccCompiler.swift
   Plugin.swift)
+SwiftBuild_Bundle(MODULE SWBUniversalPlatform FILES
+  Specs/BuiltInBuildRules.xcbuildrules
+  Specs/BuiltInCompilers.xcspec
+  Specs/BuiltInFileTypes.xcspec
+  "Specs/Clang LLVM 1.0.xcspec"
+  Specs/ClangModuleVerifierInputGenerator.xcspec
+  Specs/ClangStatCache.xcspec
+  Specs/ClangSymbolExtractor.xcspec
+  Specs/ClangVerifier.xcspec
+  Specs/CodeSign.xcspec
+  Specs/CopyPlistFile.xcspec
+  Specs/CopyStringsFile.xcspec
+  Specs/Cpp.xcspec
+  "Specs/Default Compiler.xcspec"
+  Specs/Documentation.xcspec
+  Specs/Ld.xcspec
+  Specs/Lex.xcspec
+  Specs/Libtool.xcspec
+  Specs/PackageTypes.xcspec
+  Specs/PBXCp.xcspec
+  Specs/ProductTypes.xcspec
+  Specs/ProductTypeValidationTool.xcspec
+  Specs/StandardFileTypes.xcspec
+  Specs/StripSymbols.xcspec
+  Specs/swift-stdlib-tool.xcspec
+  Specs/Swift.xcspec
+  Specs/SwiftBuildSettings.xcspec
+  Specs/TAPI.xcspec
+  Specs/TestEntryPointGenerator.xcspec
+  Specs/Unifdef.xcspec
+  Specs/Yacc.xcspec)
 target_link_libraries(SWBUniversalPlatform PUBLIC
   SWBCore
   SWBMacro
@@ -46,8 +57,6 @@ target_link_libraries(SWBUniversalPlatform PUBLIC
   SWBTaskConstruction
   SWBTaskExecution
   ArgumentParser)
-target_sources(SWBUniversalPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBUniversalPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
diff --git a/Sources/SWBWebAssemblyPlatform/CMakeLists.txt b/Sources/SWBWebAssemblyPlatform/CMakeLists.txt
index 0c12e39a9..716defdf9 100644
--- a/Sources/SWBWebAssemblyPlatform/CMakeLists.txt
+++ b/Sources/SWBWebAssemblyPlatform/CMakeLists.txt
@@ -8,35 +8,17 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBWebAssemblyPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBWebAssemblyPlatform.resources").path
-      let buildPath = #"@_SWBWebAssemblyPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBWebAssemblyPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBWebAssemblyPlatform
   Plugin.swift)
+SwiftBuild_Bundle(MODULE SWBWebAssemblyPlatform FILES
+  Specs/WasmCompile.xcspec
+  Specs/WasmLd.xcspec
+  Specs/WasmLibtool.xcspec
+  Specs/WebAssembly.xcspec)
 target_link_libraries(SWBWebAssemblyPlatform PUBLIC
   SWBCore
   SWBMacro
   SWBUtil)
-target_sources(SWBWebAssemblyPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
-
 set_target_properties(SWBWebAssemblyPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
 
diff --git a/Sources/SWBWindowsPlatform/CMakeLists.txt b/Sources/SWBWindowsPlatform/CMakeLists.txt
index 8f40d3c5a..4658b1c5d 100644
--- a/Sources/SWBWindowsPlatform/CMakeLists.txt
+++ b/Sources/SWBWindowsPlatform/CMakeLists.txt
@@ -8,36 +8,19 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
-file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}"
-  _SWBWindowsPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR)
-file(CONFIGURE
-  OUTPUT resource_bundle_accessor.swift
-  CONTENT [[
-  import Foundation
-  extension Foundation.Bundle {
-    static let module: Bundle = {
-      let mainPath = Bundle.main.bundleURL.appendingPathComponent("SwiftBuild_SWBWindowsPlatform.resources").path
-      let buildPath = #"@_SWBWindowsPlatform_NATIVE_CMAKE_CURRENT_BINARY_DIR@\SwiftBuild_SWBWindowsPlatform.resources"#
-      let preferredBundle = Bundle(path: mainPath)
-      guard let bundle = preferredBundle ?? Bundle(path: buildPath) else {
-        Swift.fatalError("could not load resource bundle: from \(mainPath) or \(buildPath)")
-      }
-      return bundle
-    }()
-  }
-  ]]
-  ESCAPE_QUOTES @ONLY NEWLINE_STYLE LF)
-
 add_library(SWBWindowsPlatform
   KnownFolders.swift
   Plugin.swift
   VSInstallation.swift)
+SwiftBuild_Bundle(MODULE SWBWindowsPlatform FILES
+  Specs/Windows.xcspec
+  Specs/WindowsCompile.xcspec
+  Specs/WindowsLd.xcspec
+  Specs/WindowsLibtool.xcspec)
 target_link_libraries(SWBWindowsPlatform PUBLIC
   SWBCore
   SWBMacro
   SWBUtil)
-target_sources(SWBWindowsPlatform PRIVATE
-  "${CMAKE_CURRENT_BINARY_DIR}/resource_bundle_accessor.swift")
 
 set_target_properties(SWBWindowsPlatform PROPERTIES
   INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})


Reviews:
user: login: neonichu
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-05T17:58:12Z
user: login: compnerd
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-05T18:00:48Z
user: login: owenv
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-05T18:29:16Z
user: login: jakepetroules
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-05T21:18:09Z
user: login: compnerd
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T15:45:33Z
user: login: owenv
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-06T16:38:25Z
user: login: compnerd
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T20:10:04Z
user: login: owenv
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-06T23:32:28Z

Review comments:
diff_hunk: @@ -8,6 +8,47 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(CONFIGURE
+    OUTPUT resource_bundle_accessor.swift
path: Sources/CMakeLists.txt
user: login: compnerd
body: I think that the absolute path with the conversion is important. Otherwise, the output location is not very well defined.
created_at: 2025-05-05T18:00:26Z
author_association: MEMBER
diff_hunk: @@ -8,6 +8,47 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(CONFIGURE
+    OUTPUT resource_bundle_accessor.swift
path: Sources/CMakeLists.txt
user: login: owenv
body: Are you referring to the native path conversion for the path used in the generated code, or the use of a relative path when setting the output for file(CONFIGURE? I restored the former, the latter I thought was ok to remain relative since it's documented to be relative to CMAKE_CURRENT_BINARY_DIR
created_at: 2025-05-05T18:29:16Z
author_association: COLLABORATOR
diff_hunk: @@ -8,6 +8,47 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(CONFIGURE
+    OUTPUT resource_bundle_accessor.swift
path: Sources/CMakeLists.txt
user: login: compnerd
body: Yes, it is documented to be relative to that, and I originally tried to use the relative path but ended up running into some issues. Furthermore, now that it is extracted into a helper, you no longer have a good idea of where `CMAKE_CURRENT_BINARY_DIR` is pointing to.
created_at: 2025-05-06T15:45:33Z
author_association: MEMBER
diff_hunk: @@ -8,6 +8,47 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_CURRENT_BINARY_DIR}/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(CONFIGURE
+    OUTPUT resource_bundle_accessor.swift
path: Sources/CMakeLists.txt
user: login: owenv
body: ok, that makes sense to me, thanks. Updated the patch to use an absolute path here and avoid use of CMAKE_CURRENT_BINARY_DIR in general
created_at: 2025-05-06T16:38:25Z
author_association: COLLABORATOR
diff_hunk: @@ -8,6 +8,48 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources" _SWIFT_BUILD_RESOURCE_BUNDLE_BUILD_PATH)
path: Sources/CMakeLists.txt
user: login: compnerd
body: I wonder if we can use `$<TARGET_PROEPRTY:${BundleXCSpecs_MODULE},BINARY_DIR>` to get the module's binary dir rather than placing this at the top-level.
created_at: 2025-05-06T20:09:32Z
author_association: MEMBER
diff_hunk: @@ -8,6 +8,48 @@ See http://swift.org/LICENSE.txt for license information
 See http://swift.org/CONTRIBUTORS.txt for Swift project authors
 ]]
 
+include(CMakeParseArguments)
+function(SwiftBuild_Bundle)
+  set(Options)
+  set(OneValueArguments MODULE)
+  set(MultiValueArguments FILES)
+  cmake_parse_arguments(PARSE_ARGV 0 BundleXCSpecs
+    "${Options}" "${OneValueArguments}" "${MultiValueArguments}")
+
+  list(TRANSFORM BundleXCSpecs_FILES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
+  add_custom_command(TARGET ${BundleXCSpecs_MODULE} POST_BUILD
+    COMMAND
+      ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources"
+    COMMAND
+      ${CMAKE_COMMAND} -E copy_if_different ${BundleXCSpecs_FILES} "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources/")
+
+  file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/share/pm/SwiftBuild_${BundleXCSpecs_MODULE}.resources" _SWIFT_BUILD_RESOURCE_BUNDLE_BUILD_PATH)
path: Sources/CMakeLists.txt
user: login: owenv
body: gave this a try but I was unable to use a generator expression in the output path when creating the resource accessor
created_at: 2025-05-06T23:32:28Z
author_association: COLLABORATOR

PR comments:
user: login: owenv
created_at: 2025-05-05T16:44:54Z
body: @swift-ci test
author_association: COLLABORATOR
user: login: owenv
created_at: 2025-05-06T16:38:34Z
body: @swift-ci test
author_association: COLLABORATOR
user: login: owenv
created_at: 2025-05-08T17:17:59Z
body: Going to look at landing this as-is and look for simplification opportunities as follow-ups

@swift-ci test
author_association: COLLABORATOR