Skip to content

A rule to update ARM dependencies to run on M1 arm64 sim#346

Merged
jerrymarino merged 12 commits intomasterfrom
jmarino/import_middle_man_rfc_without_bazel_5_fixes
Nov 12, 2021
Merged

A rule to update ARM dependencies to run on M1 arm64 sim#346
jerrymarino merged 12 commits intomasterfrom
jmarino/import_middle_man_rfc_without_bazel_5_fixes

Conversation

@jerrymarino
Copy link
Copy Markdown
Contributor

@jerrymarino jerrymarino commented Nov 4, 2021

This PR is an RFC on an additional rule to rules_ios that adds the ability to
update the Mach-o header on imported libraries and frameworks to get arm64
binaires running on Apple silicon simulator. For the demo, it's added in
app.bzl but will need a feature flag and more.

Why bother doing this? Well some apps have many dependencies which could take
along time on vendors or other parties to update. Because the M1 chip has the
same ISA as iOS ARM64, most binaries will run transparently. Much iOS developers
code is high level enough and isn't specifc to a device or simulator. There are
many caveats and exceptions but getting it running is better than nothing. ( e.g.
TARGET_OS_SIMULATOR )

This solves the problem at the build system level with the power of bazel. The
idea is pretty straight forward:

  1. collect all imported paths
  2. update the macho headers with Apples vtool and arm-to-sim
  3. update the linker invocation to use the new libs

Now it updates all of the inputs automatically - the action can be taught to do
all of this conditionally if necessary.

Additionally the apsect was generating the action but I moved it into the rule.
Mainly because you can't make an executable input to an aspect to scheudle
actions there. This has an interesting propery: you get a single path for
framework lookups at link time. Today with bazel and rules_ios ld has an
O(MFrameworks*NFrameworkPaths) search requirmenet. This is an additional
consequence and worth comparing link time impovements but is a future exercise.

There are some minor followups, but seeing what people think about it

This PR is an RFC on an _additional_ rule to rules_ios that adds the ability to
update the Mach-o header on imported libraries and frameworks to get arm64
binaires running on Apple silicon simulator. For the demo, it's added in
`app.bzl` but will need a feature flag and more.

Why bother doing this? Well some apps have many dependencies which could take
along time on vendors or other parties to update. Because the M1 chip has the
same ISA as ARM64, most binaries will run transparently. Most iOS developers
code is high level enough and isn't specifc to a device or simulator. There are
many caveats and eceptions but getting it running is better than nothing. ( e.g.
`TARGET_OS_SIMULATOR` )

This solves the problem at the build system level with the power of bazel. The
idea is pretty straight forward:
1. collect all imported paths
2. update the macho headers with Apples vtool and arm-to-sim
3. update the linker invocation to use the new libs

Now it updates all of the inputs automatically - the action can be taught to do
all of this conditionally if necessary.

Additionally the apsect was generating the action but I moved it into the rule.
Mainly because you can't make an executable input to an aspect to scheudle
actions there.  This has an interesting propery: you get a single path for
framework lookups at linktim.  Today with bazel and rules_ios ld has an
O(MFrameworks*NFrameworkPaths) search requirmenet. This is an additional
consequence and worth comparing link time impovements but is a future exercise.

There are some minor followups, but seeing what people think about it
@bogo
Copy link
Copy Markdown

bogo commented Nov 8, 2021

👍 Love the idea!

Every time we bump one of the few holdout frameworks, it's an adventure full of unarchiving, transmogrifying, archiving, vtooling, codesigning, etc. This would make the whole process transparent. Plus, it will be even more important down the line, when these holdout frameworks become increasingly rare and obscure.

One (likely completely out of scope) improvement here could be automating transmogrification of older .frameworks into multi-platform .xcframeworks. Then this would be a truly one stop shop.

@jerrymarino
Copy link
Copy Markdown
Contributor Author

@bogo first off, thanks for the excellent write-up on all of this! Second, thank you for publishing the source to handle the object file fix-up 🙏

Having this capability in the build system dramatically simplifies dealing with this and makes M1 a reality. There's a lot of iOS dependencies out there without an xcframework right now and a lot of people looking to get up and running on the M1 simulator. I suspect a decent amount of these dependencies could continue to have updates that don't have an xcframework slice, making updates an ongoing problem.

One (likely completely out of scope) improvement here could be automating transmogrification of older .frameworks into multi-platform .xcframeworks. Then this would be a truly one stop shop.

The current version of this code takes any .framework and provides a compatible one to the linker and bundling so there is no need to create an xcframework for the Bazel with this for apps just running on a simulator. To your point, it would be a nice ability to produce an xcframework for consumers. With the primitives in this PR, you could take the output frameworks from the import_middleman and produce a new shiny xcframework - coming full circle! We should be able to produce xcframeworks from Bazel in some capacity, I'm not 100% sure that exists yet.

- fix missing plists
- add to tests
@jerrymarino jerrymarino force-pushed the jmarino/import_middle_man_rfc_without_bazel_5_fixes branch from 258a7b1 to 4dd1bb2 Compare November 11, 2021 00:37
- Add missing framework files
- Remove redundant dep search
@jerrymarino jerrymarino changed the title [RFC] A rule to update ARM binaries to run on M1 arm64 sim A rule to update ARM dependencies to run on M1 arm64 sim Nov 11, 2021
@jerrymarino
Copy link
Copy Markdown
Contributor Author

jerrymarino commented Nov 11, 2021

Fixed many issues and cleaned this to remove RFC status. There's a couple planned TODOs which I'll fix tomorrow AM:

  • build the arm-to-sim dep from source or create a gh action to release a fat binary
  • conditionally enable the middleman feature

Additionally, as other PRs:

  • Ensure edge-case of M1 ready xcframeworks are working with the middleman rule
  • For M1 sim in general, Bazel 5 is a dep but needs more work for release. I can publish stand-in Bazel 4 "frankenstein" c++ toolchain mentioned on mobile native forum
  • follow up on hack in rules_swift toolchain or publish a tag with above hack
  • test cases, support for standalone dylibs

@jerrymarino jerrymarino force-pushed the jmarino/import_middle_man_rfc_without_bazel_5_fixes branch 2 times, most recently from cf40ec2 to 3341948 Compare November 11, 2021 01:51
@jerrymarino jerrymarino force-pushed the jmarino/import_middle_man_rfc_without_bazel_5_fixes branch from 3341948 to f88b1aa Compare November 11, 2021 01:56
Copy link
Copy Markdown
Contributor

@thiagohmcruz thiagohmcruz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few questions on the starlark side for now!

jerrymarino and others added 5 commits November 11, 2021 10:16
- remove syslibroot from libtool
- cleanup aspect refactoring code
Moves it out of the main rule body and cleanups up dynamic framework
calculation
Co-authored-by: Thiago Cruz <thiago.hmcruz@gmail.com>
@jerrymarino jerrymarino force-pushed the jmarino/import_middle_man_rfc_without_bazel_5_fixes branch from bb049f6 to 813329a Compare November 11, 2021 20:30
This was a TODO but will require more effort because rules_swift isn't working
here
Additionally namespace tmp dirs and run buildifier
Copy link
Copy Markdown
Contributor

@thiagohmcruz thiagohmcruz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

- Manual
- Fat arm64-to-sim
- buildifier
@jerrymarino jerrymarino enabled auto-merge (squash) November 12, 2021 20:06
@jerrymarino jerrymarino merged commit 8c3c7fe into master Nov 12, 2021
@jerrymarino jerrymarino deleted the jmarino/import_middle_man_rfc_without_bazel_5_fixes branch November 12, 2021 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants