Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal binary support #421

Closed
wants to merge 1 commit into from

Conversation

stuartcarnie
Copy link
Contributor

This PR includes all the changes for building iTerm2 as a Universal macOS Binary. There may be edits required so that it can be merged, but most of the time-consuming work as been done. The only change required to iTerm2 itself was to iTermBacktrace.mm (as anticipated).

It includes universal builds for a number of embedded frameworks, including:

  • BetterFontPicker.framework
  • ColorPicker.framework
  • SearchableComboListView.framework
  • CoreParse.framework
  • Updated NMSSH.framework as a Universal Binary
    • Recompiled OpenSSL's libcrypto.a and libssh.a as fat binaries
    • Recompiled libssh2.a as a fat binary
  • Sparkle.framework
  • libsixel
    • Embedded the small amount of source and created a static library target to simplify building

@gnachman
Copy link
Owner

gnachman commented Jul 4, 2020

Thank you for taking on this huge project! I think I need to build at least some of these myself so they will have the proper code signature, and also so I know how to do it next time they change. Also, some of this code came from my personal forks (like Sparkle and NMSSH). This was all a bit opaque which I apologize for. I've added submodules with all the external dependencies whose source wasn't already in the repo as of commit e83f5af.

Please help me learn what you did, because I spent some time fighting with libsixel's automake today and it was not much fun.

The parts I'm not sure how to do are:

  1. Rebuilding libcrypto and libssh as fat binaries
  2. Rebuilding libssh2.a as a fat binary
  3. Rebuilding libsixel as a fat binary (and whatever else you had to do, which isn't quite clear to me)

@stuartcarnie
Copy link
Contributor Author

Hi @gnachman

libsixel

I committed libsixel configured source to the repo, so if you don't mind, you could run with that as-is. I added it as a new static target with multi-architecture support, so it will automatically compile as a fat binary. I've verified it works by decoding multiple images to my terminal using imgcat.

Fat binaries

tl;dr:

  1. Compile the target for each architecture (arm64, x86_64) and then use lipo to combine the individual archives into a single, fat archive. To combine multiple libssl architectures, the lipo command will look something like the following:
$ lipo -create -output libssl.a libssl-arm64.a libssl-x86_64.a

And to verify your archive:

$ lipo -info libssl.a
Architectures in the fat file: libssl.a are: x86_64 arm64

OpenSSL

This was the most involved.

  1. Checkout OpenSSL_1_1_1-stable branch

Build arm64 target

  1. Apply this patch, which adds a darwin-arm64 target to OpenSSL
diff --git Configurations/10-main.conf Configurations/10-main.conf
index 3b07731db8..fdcdb6a514 100644
--- Configurations/10-main.conf
+++ Configurations/10-main.conf
@@ -1557,6 +1557,14 @@ my %targets = (
         bn_ops           => "SIXTY_FOUR_BIT_LONG",
         perlasm_scheme   => "macosx",
     },
+    "darwin64-arm64-cc" => {
+        inherit_from     => [ "darwin-common", asm("aarch64_asm") ],
+        CFLAGS           => add("-Wall"),
+        cflags           => add("-arch arm64"),
+        lib_cppflags     => add("-DL_ENDIAN"),
+        bn_ops           => "SIXTY_FOUR_BIT_LONG",
+        perlasm_scheme   => "ios64",
+    },
 
 ##### GNU Hurd
     "hurd-x86" => {

NOTE: This updated patch ensures arm64 assembly optimizations are utilized, which I missed from my first version.

  1. Configure and build arm64 target:
$ ./Configure darwin64-arm64-cc
$ make build_generated
$ make libcrypto.a libssl.a -j4
  1. Move the archives to a new name, to save them for later
$ mv libcrypto.a libcrypto-arm64.a
$ mv libssl.a libssl-arm64.a
  1. Cleanup
$ make clean

Configure and build the x86_64 target

$ ./Configure darwin64-x86_64-cc
$ make build_generated
$ make libcrypto.a libssl.a -j4
  1. Move the archives to a new name
$ mv libcrypto.a libcrypto-x86_64.a
$ mv libssl.a libssl-x86_64.a

Fat binary

  1. Make a fat binary of libcrypto:
$ lipo -create -output libcrypto.a libcrypto-arm64.a libcrypto-x86_64.a
  1. Make a fat binary of libssl:
$ lipo -create -output libssl.a libssl-arm64.a libssl-x86_64.a

libssh2

I checked out the latest (1.9-DEV), which seems to work fine, but you could fetch a specific version.

Build x86_64 target

  1. Generate x86_64 project dir
$ mkdir build_x86_64
$ cd build_x86_64
  1. Invoke CMake generator, noting you'll have to replace OPENSSL_ROOT_DIR with your path
$ cmake -DOPENSSL_ROOT_DIR=~/projects/macos/openssl -DBUILD_EXAMPLES=NO -DBUILD_TESTING=NO -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCRYPTO_BACKEND=OpenSSL ..
  1. Build target
$ make libssh2 -j4

NOTE: libssh2.a output is in ./src

Build arm64 target

  1. Generate x86_64 project dir
$ mkdir build_arm64
$ cd build_arm64
  1. Invoke CMake generator, noting you'll have to replace OPENSSL_ROOT_DIR with your path
$ cmake -DOPENSSL_ROOT_DIR=~/projects/macos/openssl -DBUILD_EXAMPLES=NO -DBUILD_TESTING=NO -DCMAKE_OSX_ARCHITECTURES=arm64 -DCRYPTO_BACKEND=OpenSSL ..
  1. Build target
$ make libssh2 -j4

Create libssh2 fat binary

  1. Change to libssl2 source root
$ cd ..
  1. Combine both targets using lipo
$ lipo -create -output libssh2.a build_arm64/src/libssh2.a build_x86_64/src/libssh2.a

gnachman added a commit to gnachman/openssl that referenced this pull request Jul 4, 2020
@stuartcarnie
Copy link
Contributor Author

stuartcarnie commented Jul 4, 2020

Update: libssh2

I checked out the latest (1.9-DEV), which seems to work fine, but you could fetch a specific version.

Turns out CMake can utilize the ability for the clang toolchain to build multiple architectures in a single compilation using CMAKE_OSX_ARCHITECTURES='arm64;x86_64'

Build fat binary

  1. Create a build dir
$ mkdir build
$ cd build
  1. Invoke CMake generator, noting you'll have to replace OPENSSL_ROOT_DIR with your path
$ cmake -DOPENSSL_ROOT_DIR=~/projects/macos/openssl -DBUILD_EXAMPLES=NO -DBUILD_TESTING=NO -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' -DCRYPTO_BACKEND=OpenSSL ..
  1. Build target
$ make libssh2 -j4

NOTE: libssh2.a output is in ./src

@stuartcarnie
Copy link
Contributor Author

I've pushed a new version that is rebased on your latest. This version is using your forks of the NMSSH and Sparkle frameworks.

@tomhamming
Copy link

Did you have to modify it further to support older versions of macOS? I used this to build a fat binary of OpenSSL for my Mac app that supports back to 10.10, and initially got warnings about linking against a library built for a newer macOS version than I was targeting. I had to add to the darwin64-x86_64-cc target:

cppflags         => add("-target x86_64-apple-macos10.10")

* Updated to use George's forks of NMSSH and Sparkle
* Still uses embedded libsixel

TODOs

* Determine updated make libsixel invocation to
  build a universal static binary
@gnachman
Copy link
Owner

gnachman commented Jul 8, 2020

I have a makefile that should automate this, but Apple has suggested to me that this might be under NDA for now. Hang tight and I'll try to get a straight answer from them on whether there's any problem making these changes public yet.

@tomhamming You shouldn't need to go back as far as 10.10. iTerm2 only supports 10.12+

@tomhamming
Copy link

@gnachman thanks. I was actually building OpenSSL for my app that supports back to 10.10. I mainly asked the question to clarify that that's the proper way to build for older macOS versions - I'm not familiar with make so it took me a while to figure that out. I suspect other developers trying to update their OpenSSL libraries for Apple Silicon will land here after searching, as I did after seeing @stuartcarnie post about this on Twitter.

@gnachman
Copy link
Owner

gnachman commented Jul 9, 2020

Commit 83a3c75 adds Makefile targets to build everything as fat binaries. If you build it on a DTK you should get a fat binary. Please let me know if I missed anything.

Thanks for your help in getting this done, @stuartcarnie. I am allergic to automake and your help was really valuable.

@gnachman gnachman closed this Jul 9, 2020
@stuartcarnie
Copy link
Contributor Author

@gnachman awesome to hear – I'll give master a shot today!

@stuartcarnie
Copy link
Contributor Author

Works great!

@stuartcarnie stuartcarnie deleted the sgc/universal branch July 10, 2020 03:08
@djerfy djerfy mentioned this pull request Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants