cgrindel / rules_swift_package_manager

Collection of utilities and Bazel rules to aid in the development and maintenance of Swift repositories using Bazel.
Apache License 2.0
74 stars 29 forks source link

Issues with BranchSDK and Swift macros #941

Closed jpsim closed 8 months ago

jpsim commented 8 months ago

This is a bit of a tricky one. If I have BranchSDK and Swift macros in my iOS app, everything works fine on the command line, but break in one way or another in rules_xcodeproj.

Here's some sample changes applied to the Lottie iOS example in this repo as a repro case:

--- a/examples/lottie_ios_example/LottieExample/AppDelegate.swift
+++ b/examples/lottie_ios_example/LottieExample/AppDelegate.swift
@@ -2,6 +2,7 @@
 // Copyright © 2022 Airbnb Inc. All rights reserved.

 import UIKit
+import BranchSDK

 @main
 class AppDelegate: UIResponder, UIApplicationDelegate {
@@ -14,3 +15,27 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
   }
 }

+
+import Foundation
+import Dependencies
+import DependenciesMacros
+
+// MARK: - MyDependency
+
+extension DependencyValues {
+    var myDep: MyDependency {
+        get { self[MyDependency.self] }
+        set { self[MyDependency.self] = newValue }
+    }
+}
+
+@DependencyClient
+struct MyDependency: Sendable {
+    var perform: @Sendable () throws -> Void
+}
+
+extension MyDependency: DependencyKey {
+    static let liveValue = MyDependency(perform: {
+        print("Hello from MyDependency")
+    })
+}
--- a/examples/lottie_ios_example/LottieExample/BUILD.bazel
+++ b/examples/lottie_ios_example/LottieExample/BUILD.bazel
@@ -13,7 +13,12 @@ swift_library(
     module_name = "LottieExample",
     tags = ["manual"],
     visibility = ["//visibility:public"],
-    deps = ["@swiftpkg_lottie_spm//:Lottie"],
+    deps = [
+        "@swiftpkg_ios_branch_sdk_spm//:BranchSDK",
+        "@swiftpkg_swift_dependencies//:Dependencies",
+        "@swiftpkg_swift_dependencies//:DependenciesMacros",
+        "@swiftpkg_lottie_spm//:Lottie",
+    ],
 )

 ios_application(
--- a/examples/lottie_ios_example/MODULE.bazel
+++ b/examples/lottie_ios_example/MODULE.bazel
@@ -49,6 +49,8 @@ swift_deps.from_file(
 )
 use_repo(
     swift_deps,
+    "swiftpkg_ios_branch_sdk_spm",
     "swiftpkg_lottie_spm",
+    "swiftpkg_swift_dependencies",
 )
 # swift_deps END
--- a/examples/lottie_ios_example/Package.swift
+++ b/examples/lottie_ios_example/Package.swift
@@ -6,5 +6,7 @@ let package = Package(
     name: "lottie_ios_example",
     dependencies: [
         .package(url: "https://github.com/airbnb/lottie-spm", from: "4.4.1"),
+        .package(url: "https://github.com/BranchMetrics/ios-branch-sdk-spm", exact: "3.3.0"),
+        .package(url: "https://github.com/pointfreeco/swift-dependencies", exact: "1.2.1"),
     ]
 )

Everything builds fine with bazel build //LottieExample:iosapp.

However, with Xcode and rules_xcodeproj, I get errors like this:

rules_swift_package_manager~override~swift_deps~swiftpkg_ios_branch_sdk_spm/BranchSDK/module.modulemap:1:8: error: redefinition of module 'BranchSDK'
module "BranchSDK" {
       ^
rules_swift_package_manager~override~swift_deps~swiftpkg_ios_branch_sdk_spm/Framework/module.modulemap:1:18: note: previously defined here
framework module BranchSDK {
                 ^

Similarly, I get the same errors if I build from the command with bazel build --spawn_strategy=standalone //LottieExample:iosapp.

If I follow the instructions in the FAQ to enable sandboxing to work around this, then the BranchSDK module builds but Swift macros break because they violate the sandbox:

$ bazel build --spawn_strategy=sandboxed,remote,worker,local //LottieExample:iosapp
INFO: From Compiling Swift module @@rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies//:DependenciesMacros.rspm:
sandbox-exec: sandbox_apply: Operation not permitted
<unknown>:0: warning: compiler plugin not loaded: '/private/var/tmp/_bazel_jsimard/00d2abe118e4e56c1b7d05adaab0b6c8/execroot/_main/bazel-out/darwin_arm64-opt-exec-ST-13d3ddad9198/bin/external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/DependenciesMacrosPlugin.rspm; failed to initialize
external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/Sources/DependenciesMacros/Macros.swift:118:14: warning: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
public macro DependencyClient() =
             ^
external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/Sources/DependenciesMacros/Macros.swift:187:14: warning: external macro implementation type 'DependenciesMacrosPlugin.DependencyEndpointMacro' could not be found for macro 'DependencyEndpoint(method:)'
public macro DependencyEndpoint(method: String = "") =
             ^
sandbox-exec: sandbox_apply: Operation not permitted
<unknown>:0: warning: compiler plugin not loaded: '/private/var/tmp/_bazel_jsimard/00d2abe118e4e56c1b7d05adaab0b6c8/execroot/_main/bazel-out/darwin_arm64-opt-exec-ST-13d3ddad9198/bin/external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/DependenciesMacrosPlugin.rspm; failed to initialize
external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/Sources/DependenciesMacros/Macros.swift:118:14: warning: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
public macro DependencyClient() =
             ^
external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/Sources/DependenciesMacros/Macros.swift:187:14: warning: external macro implementation type 'DependenciesMacrosPlugin.DependencyEndpointMacro' could not be found for macro 'DependencyEndpoint(method:)'
public macro DependencyEndpoint(method: String = "") =
             ^

ERROR: /Users/jsimard/src/rules_swift_package_manager/examples/lottie_ios_example/LottieExample/BUILD.bazel:6:14: Compiling Swift module //LottieExample:LottieExample failed: (Exit 1): worker failed: error executing SwiftCompile command (from target //LottieExample:LottieExample) 
  (cd /private/var/tmp/_bazel_jsimard/00d2abe118e4e56c1b7d05adaab0b6c8/sandbox/darwin-sandbox/152/execroot/_main && \
  exec env - \
    APPLE_SDK_PLATFORM=iPhoneSimulator \
    APPLE_SDK_VERSION_OVERRIDE=17.2 \
    PATH=/bin:/usr/bin:/usr/local/bin \
    SWIFT_AVOID_WARNING_USING_OLD_DRIVER=1 \
    XCODE_VERSION_OVERRIDE=15.2.0.15C500b \
  bazel-out/darwin_arm64-opt-exec-ST-13d3ddad9198/bin/external/rules_swift~1.16.0/tools/worker/worker swiftc @bazel-out/ios_sim_arm64-fastbuild-ios-sim_arm64-min13.0-applebin_ios-ST-91e00ca0df9e/bin/LottieExample/LottieExample.swiftmodule-0.params)
# Configuration: 46ae69df7f021f5ca14c686c812107a06acd0a16562cc65620238f9a52de920b
# Execution platform: @@local_config_platform//:host

Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging
sandbox-exec: sandbox_apply: Operation not permitted
<unknown>:0: warning: compiler plugin not loaded: '/private/var/tmp/_bazel_jsimard/00d2abe118e4e56c1b7d05adaab0b6c8/execroot/_main/bazel-out/darwin_arm64-opt-exec-ST-13d3ddad9198/bin/external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/DependenciesMacrosPlugin.rspm; failed to initialize
LottieExample/AppDelegate.swift:33:8: error: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
struct MyDependency: Sendable {
       ^
DependenciesMacros.DependencyClient:1:79: note: 'DependencyClient()' declared here
@attached(member, names: named(init)) @attached(memberAttribute) public macro DependencyClient() = #externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyClientMacro")
                                                                              ^
LottieExample/AppDelegate.swift:34:9: error: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
    var perform: @Sendable () throws -> Void
        ^
DependenciesMacros.DependencyClient:1:79: note: 'DependencyClient()' declared here
@attached(member, names: named(init)) @attached(memberAttribute) public macro DependencyClient() = #externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyClientMacro")
                                                                              ^
error: emit-module command failed with exit code 1 (use -v to see invocation)
sandbox-exec: sandbox_apply: Operation not permitted
<unknown>:0: warning: compiler plugin not loaded: '/private/var/tmp/_bazel_jsimard/00d2abe118e4e56c1b7d05adaab0b6c8/execroot/_main/bazel-out/darwin_arm64-opt-exec-ST-13d3ddad9198/bin/external/rules_swift_package_manager~override~swift_deps~swiftpkg_swift_dependencies/DependenciesMacrosPlugin.rspm; failed to initialize
LottieExample/AppDelegate.swift:33:8: error: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
struct MyDependency: Sendable {
       ^
DependenciesMacros.DependencyClient:1:79: note: 'DependencyClient()' declared here
@attached(member, names: named(init)) @attached(memberAttribute) public macro DependencyClient() = #externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyClientMacro")
                                                                              ^
LottieExample/AppDelegate.swift:34:9: error: external macro implementation type 'DependenciesMacrosPlugin.DependencyClientMacro' could not be found for macro 'DependencyClient()'
    var perform: @Sendable () throws -> Void
        ^
DependenciesMacros.DependencyClient:1:79: note: 'DependencyClient()' declared here
@attached(member, names: named(init)) @attached(memberAttribute) public macro DependencyClient() = #externalMacro(module: "DependenciesMacrosPlugin", type: "DependencyClientMacro")
                                                                              ^
error: fatalError

So any way I slice it, I can't get both BranchSDK and Swift macros to be buildable in Xcode.

It's possible that some of this becomes fixable (in rules_swift?) in Swift 5.10 which will include this change: https://github.com/apple/swift/pull/70079

But it seems like the right fix would be to get packages like BranchSDK (and Firebase I imagine) buildable with sandboxing disabled.

jpsim commented 8 months ago

Also noteworthy is that something changed between BranchSDK's 3.1.0 and 3.3.0 releases, because this issue doesn't happen with 3.1.0.

.package(url: "https://github.com/BranchMetrics/ios-branch-sdk-spm", exact: "3.1.0"),
brentleyjones commented 8 months ago

@cgrindel your suggestion doesn't set the default value: https://bazel.build/reference/command-line-reference#flag--spawn_strategy

I think it should be--spawn_strategy=remote,worker,sandboxed,local instead.

jpsim commented 8 months ago

Indeed, --spawn_strategy=remote,worker,sandboxed,local fixes things in both the repro case above and in my real project.

Thanks @brentleyjones!

cgrindel commented 8 months ago

I think it should be--spawn_strategy=remote,worker,sandboxed,local instead.

Cool. I will update the doc.

brentleyjones commented 8 months ago

We might want to suggest --strategy_regexp as a way to target the problematic targets. In this case I think it would be --strategy_regexp=Compiling Sources/BranchSDK/.*=sandboxed (it matches on the description of the action, which is something like Compiling Sources/BranchSDK/BNCContentDiscoveryManager.m).

jpsim commented 8 months ago

Thanks Brentley and Chuck!