line / rules_apple_line

LINE's Apple rules for Bazel
Apache License 2.0
207 stars 22 forks source link

Swift code is not being compiled or archived #20

Closed omarzl closed 3 years ago

omarzl commented 3 years ago

Hello I have 3 libraries, one in Objective-C (Amplitude-iOS), other one in Swift (ObjectMapper) and a mixed one (RxSwift + a dummy .m file)

I am running the following command

bazel build //:Amplitude-iOS //:ObjectMapper //:RxSwift --python_version=PY3 --cpu=ios_x86_64 --apple_platform_type=ios --verbose_failures --sandbox_debug --subcommands --ios_minimum_os=12.0

And when I look in the bazel-bin directory there are only two .a files: libAmplitude-iOS.a and libRxSwift.a

If a run ar -t with the libAmplitude-iOS.a I see that there are 14 .o files which corresponds with the number of .m source files

omarzl@mbp-omar exported_libs % ar -t bazel-bin/libAmplitude-iOS.a                                                                                                                                                            
__.SYMDEF
AMPConstants_69d0a734354b5db134c2893a4161a6d7.o
AMPDatabaseHelper_3ce394e8374a71ca185335530daf03f7.o
AMPDeviceInfo_6941f9a7f4f2f9c7b05ffb59cfcae914.o
AMPIdentify_b6e25ffb9a47bb738a3110067cbd6bdf.o
AMPLocationManagerDelegate_d6cc0574ce7b251a1a0de43f5096b8d9.o
AMPRevenue_edcc78e5e6939b0865f93de2b3781aa9.o
AMPTrackingOptions_5923c90a5ee0e9d29a35228ca584be61.o
AMPURLConnection_29b1a1224fd7ccf7036a8f66da53774f.o
AMPURLSession_ae5a05de96254d84934ab2d6e7a0ea27.o
AMPUtils_42cfe63f40eb632317ac07b38e0c9099.o
Amplitude_33a97a094c115fc384cad215184f0fbd.o
ISPCertificatePinning_5256c1810f4cd79ee1a3e3ed5f000abd.o
ISPPinnedNSURLConnectionDelegate_99c34a6f04fbfca446535d93f055ea8b.o
ISPPinnedNSURLSessionDelegate_d802e965b4b973ebb90843b7ad6c755a.o

But if I run ar -t with the libRxSwift.a library there is only the dummy m file but no swift object files are being archived

omarzl@mbp-omar exported_libs % ar -t bazel-bin/libRxSwift.a      
__.SYMDEF SORTED
RxSwift-dummy_e151122338dca6ddb0d82612c1760f0d.o

And finally with the target ObjectMapper that is swift only, there is no .a file and don't see it is compiling the code at all.

image

WORKSPACE

load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")

git_repository(
    name = "build_bazel_rules_apple",
    remote = "https://github.com/bazelbuild/rules_apple.git",
    commit = "18fbeadb089638eb2248de6e7685e0d4415c21cc",
)

git_repository(
    name = "build_bazel_rules_swift",
    remote = "https://github.com/bazelbuild/rules_swift.git",
    commit = "cd66dc7c0aa6010f56676dbb89091f882d4ec9c5",
)

git_repository(
    name = "rules_apple_line",
    remote = "https://github.com/line/rules_apple_line.git",
    commit = "d6a7706751634b938cb28fa666c4e04e1aeb4832",
)

load(
    "@build_bazel_rules_swift//swift:repositories.bzl",
    "swift_rules_dependencies",
)

swift_rules_dependencies()

load(
    "@build_bazel_rules_swift//swift:extras.bzl",
    "swift_rules_extra_dependencies",
)

swift_rules_extra_dependencies()

load(
    "@rules_apple_line//apple:repositories.bzl",
    "rules_apple_line_dependencies",
)

# If you want to lock apple_support, rules_apple and rules_swift to specific
# versions, be sure to call this function after their repository rules.
rules_apple_line_dependencies()

BUILD.bazel

load("@rules_apple_line//apple:apple_library.bzl", "apple_library")
load("@rules_apple_line//apple:objc_library.bzl", "objc_library")
load("@rules_apple_line//apple:swift_library.bzl", "swift_library")

objc_library(
    name = "Amplitude-iOS",
    srcs = glob([
        "Amplitude-iOS/Sources/Amplitude/*.m",
        "Amplitude-iOS/Sources/Amplitude/SSLCertificatePinning/*.m",
    ]),
    hdrs = [
        "Amplitude-iOS/Sources/Amplitude/AMPConstants.h",
        "Amplitude-iOS/Sources/Amplitude/AMPDatabaseHelper.h",
        "Amplitude-iOS/Sources/Amplitude/AMPDeviceInfo.h",
        "Amplitude-iOS/Sources/Amplitude/AMPIdentify.h",
        "Amplitude-iOS/Sources/Amplitude/Amplitude+SSLPinning.h",
        "Amplitude-iOS/Sources/Amplitude/Amplitude.h",
        "Amplitude-iOS/Sources/Amplitude/AMPLocationManagerDelegate.h",
        "Amplitude-iOS/Sources/Amplitude/AMPRevenue.h",
        "Amplitude-iOS/Sources/Amplitude/AMPTrackingOptions.h",
        "Amplitude-iOS/Sources/Amplitude/AMPURLConnection.h",
        "Amplitude-iOS/Sources/Amplitude/AMPURLSession.h",
        "Amplitude-iOS/Sources/Amplitude/AMPUtils.h",
        "Amplitude-iOS/Sources/Amplitude/SSLCertificatePinning/ISPCertificatePinning.h",
        "Amplitude-iOS/Sources/Amplitude/SSLCertificatePinning/ISPPinnedNSURLConnectionDelegate.h",
        "Amplitude-iOS/Sources/Amplitude/SSLCertificatePinning/ISPPinnedNSURLSessionDelegate.h",
    ],
    copts = [
        "-w",
        "-Xanalyzer",
        "-analyzer-disable-all-checks",
    ],
    enable_modules = True,
    module_name = "Amplitude_iOS",
    sdk_dylibs = ["sqlite3.0"],
    visibility = ["//visibility:public"],
)

swift_library(
    name = "ObjectMapper",
    srcs = glob([
        "ObjectMapper/Sources/*.swift"
    ]),
    enable_modules = True,
    module_name = "ObjectMapper",
    visibility = ["//visibility:public"],
)

apple_library(
    name = "RxSwift",
    srcs = glob(
        [
            "RxSwift/RxSwift/**/*.swift",
            "RxSwift/Platform/**/*.swift",
            "RxSwift/RxSwift-dummy.m",
        ],
        exclude = [
            "RxSwift/RxSwift/Platform/**/*.swift",
        ],
    ),
    enable_modules = True,
    module_name = "RxSwift",
    objc_copts = [
        "-w",
        "-Xanalyzer",
        "-analyzer-disable-all-checks",
    ],
    visibility = ["//visibility:public"],
)

What I am missing? How could I make that all the targets generate an .a static archive?

I am using the latest commit for all the rules and here are the files to test with.

bazel_libs.zip

omarzl commented 3 years ago

I tried with the examples and I can't compile swift code neither, I tested with Bazel version 3.4.1 as it is set in the .bazelversion file, I also tried with versions: 3.5.0, 3.7.0 I tested with python 2 and python 3 I tried using Xcode 12 (12A7209) command line tools and Xcode 11.5 (11E608C) but didn't work neither

I am running this command:

bazel build //examples/ios/PureSwift:PureSwift

I also tried with the Mixed example

bazel build //examples/ios/Mixed:Mixed

But it only archives the objc o file not the swift code

omarzl@mbp-omar rules_apple_line-master % ar -t /private/var/tmp/_bazel_omarzl/c350e071a14135cbd8a76b67a94c7c5b/execroot/rules_apple_line/bazel-out/apl-darwin_x86_64-fastbuild/bin/examples/ios/Mixed/libMixed.a 
__.SYMDEF SORTED
MXDObjcGreeter_b490d1443bbe08f91ea2d2eedfda4a5b.o
omarzl@mbp-omar rules_apple_line-master % 

I am using macOS Catalina 10.15.7 if that affects somehow.

Our team just started migrating to Bazel, I have been looking in the code but I couldn't find how to solve it /:

thii commented 3 years ago

What do you want the static archive for? If you want to package a framework, you can do that with a {objc,swift,mixed}_static_framework target:

bazel build //examples/ios/Mixed:MixedFramework

If you want to package an app, you can do that with an ios_application target:

bazel build //examples/ios/App
omarzl commented 3 years ago

Hello @thii thank you for that information! It helped me a lot.

We are a large company that want to migrate to Bazel, currently our project uses Cocoapods as our dependency manager, we have around 200 dependencies, we want to do a phased migration and we also need to first demonstrate to all the tech heads that Bazel is a viable solution for our compilation time problem (around 60 mins), that's why we can't just remove the xcodeproj.

I am doing some tests in another app that we have that is a little smaller (69 dependencies), what I am doing is a hybrid between Bazel/Cocoapods/Xcode, I modify the Cocoapods targets and make the app compile under the hood with Bazel and then make Cocoapods to use those compiled libraries, I finally achieved to run the app with 53 libraries compiled with Bazel and only 16 with Xcode, that is why I need the .a static archive file, what I did is to use your rules to generate the framework and then unzip it and take the lib, in the future I hope we can have our own rules specific for our needs but right now yours have been very useful!

During these days I found a lot of problems that I have been sorting out, one of them was that your rules aren't sending the module_name into the bundle_name of the rule, this causes the following issue:

omarzl@mbp-omar issue_bundle_name_demo % bazel build //:Mixed-LibFramework                                                   
INFO: Analyzed target //:Mixed-LibFramework (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
ERROR: /Users/omarzl/Documents/Rappi/dev/bazel/issue_bundle_name_demo/BUILD.bazel:5:14: Compiling Swift module Mixed_Lib failed (Exit 1): worker failed: error executing command bazel-out/host/bin/external/build_bazel_rules_swift/tools/worker/worker swiftc @bazel-out/applebin_ios-ios_x86_64-fastbuild-ST-1665503f7bef/bin/Mixed_Lib.swiftmodule-0.params
/private/var/tmp/_bazel_omarzl/d4b15372538f584ee97a74abbcce56ce/execroot/__main__/bazel-out/applebin_ios-ios_x86_64-fastbuild-ST-1665503f7bef/bin/Swift-Lib.intermediate-intermediates/module.modulemap:1:24: error: expected module declaration
framework module Swift-Lib {
Target //:Mixed-LibFramework failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 0.662s, Critical Path: 0.58s
INFO: 3 processes: 3 internal.
FAILED: Build did NOT complete successfully
omarzl@mbp-omar issue_bundle_name_demo % cat /private/var/tmp/_bazel_omarzl/d4b15372538f584ee97a74abbcce56ce/execroot/__main__/bazel-out/applebin_ios-ios_x86_64-fastbuild-ST-1665503f7bef/bin/Mixed-Lib.intermediate-intermediates/module.modulemap
framework module Mixed-Lib {
  umbrella header "Mixed-Lib.h"
  export *
  module * { export * }
}

Since we are doing a "bridge" between Cocoapods dependencies to Bazel I can't modify the code and this issue raised because we use Amplitude, the lib name is: "Amplitude-iOS" but the hyphen is not permitted as a module name so they change it to: "Amplitude_iOS", I was sending that way in the module_name but your objc_library was showing that error.

Maybe I am confusing you a little bit so here is a project that demonstrates the issue I am talking about, I am also sending the pull request: https://github.com/line/rules_apple_line/pull/24 fixing this, can you take it a look? issue_bundle_name_demo.zip


Finally the second issue is with IGListKit, we have a large codebase depending on it, they have two pods IGListKit and IGListDiffKit, and one uses private headers from the other one, that might be the issue but well since is not my code I can't do the modifications, here is a demo project that shows the error I am talking about:

omarzl@mbp-omar issue_iglistkit_demo % bazel build //:IGListKitFramework //:IGListDiffKitFramework //:DemoFramework
INFO: Analyzed 3 targets (9 packages loaded, 848 targets configured).
INFO: Found 3 targets...
ERROR: /Users/omarzl/Documents/Rappi/dev/bazel/issue_iglistkit_demo/BUILD.bazel:4:14: Compiling Swift module Demo failed (Exit 1)
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "../../../Demo/NSObject+IGListDiffable.h"
        ^
/private/var/tmp/_bazel_omarzl/ed7e4ede385a3fe0ff93eb9080f3a35b/execroot/__main__/bazel-out/applebin_ios-ios_x86_64-fastbuild-ST-5dc50b810145/bin/../../../Demo/NSObject+IGListDiffable.h:10:9: error: 'IGListDiffKit/IGListDiffable.h' file not found
#import <IGListDiffKit/IGListDiffable.h>
        ^
<unknown>:0: error: could not build Objective-C module 'Demo'

ERROR: /Users/omarzl/Documents/Rappi/dev/bazel/issue_iglistkit_demo/BUILD.bazel:4:14 Compiling Swift module Demo failed (Exit 1)
INFO: Elapsed time: 39.647s, Critical Path: 28.05s
INFO: 219 processes: 218 darwin-sandbox, 1 worker.
FAILED: Build did NOT complete successfully

issue_iglistkit_demo.zip

Could you take a look at what is going on with this case? I will be really grateful!

thii commented 3 years ago

Let me split your issue into 3 smaller ones, so I can take a look at them one by one.

thii commented 3 years ago

@omarzl Updated my comment.

omarzl commented 3 years ago

Thii thank you for your response, I ended up doing what you said, I unzip the framework and rename the binary and it works great! For the IGListKit header issues I added -iquote and -I header search flags and it worked too. I am almost done migrating all our dependencies, you help have been useful for us, the only real bug was the bundle name so feel free to close this issue 😁 Hope we can contribute more to Bazel community in the future!

thii commented 3 years ago

Glad to hear that this helps!