Consensys / jblst

MIT License
8 stars 12 forks source link

Add Apple Silicon Support #15

Closed ajsutton closed 2 years ago

ajsutton commented 3 years ago

Builds in the MacOS library targeting both x86_64 and arm64 which should produce a single FAT library file that works on both architectures automatically.

fixes #13

ajsutton commented 3 years ago

There's a couple of hacks in here to work around the fact that the blst build system doesn't work well with Mac fat binaries. Firstly blst uses the ar command to build an archive of the two compilation outputs (server.o and assembly.o). We can set CFLAGS to get those .o files to be compiled as fat, but ar doesn't support fat archives - you need to use libtool -static which does essentially the same job but supports fat binaries and unfortunately has different CLI syntax. We can't make that work just by setting env vars so use ar to expand the built archive again then recreate it with libtool -static which fortunately works.

But then the final built jar has the fat library under Mac/x86_64/ directory and the swig code is configured to find the library to load based on the OS and arch names, so on ARM it would be looking in Mac/arm64. We get around that by just copying the library to Mac/arm64 directory. Down side is we're including two copies of the fat binary when we could just use one but it makes it work with the current version of blst. We may be able to push some changes back upstream to avoid these work arounds in future releases.

paulmillr commented 3 years ago

Can we get this one merged?

ajsutton commented 3 years ago

Can we get this one merged?

Unfortunately when I've been able to get people testing this on an M1 Mac the native library doesn't seem to load correctly when using an M1 native JVM. It looks like the dylib is correctly multi-arch so I suspect there's something in the loading process that isn't writing out the right library or something like that. Though it could still be that the compilation isn't right.

dwhjames commented 2 years ago

@ajsutton here’s an alternative approach that does not attempt to make a universal binary:

assumptions:

# must run within blst/bindings/java

# assume run on x86_64 arch Mac
# test compiler architectures
cc -dM -E -x c /dev/null | grep -q x86_64
cc -arch arm64 -dM -E -x c /dev/null | grep -q AARCH64

build steps:

# start clean
rm -f libblst.a supranational.blst.jar
rm -fr supranational

# CC for build of libblst.a
# CXX for build of SWIG layer
CC="cc -arch arm64 " CXX="c++ -arch arm64" ./build.sh

# os.arch of this JVM is x86_64, but we cross compiled above
mv supranational/blst/Mac/x86_64 supranational/blst/Mac/aarch64

# reset for new compile
rm -f libblst.a supranational.blst.jar

# build with defaults of x86_64
./build.sh

double check the output

lipo -info supranational/blst/Mac/x86_64/libblst.dylib
lipo -info supranational/blst/Mac/aarch64/libblst.dylib
jar tf supranational.blst.jar
ajsutton commented 2 years ago

@ajsutton here’s an alternative approach that does not attempt to make a universal binary:

ooo, that's really cool and definitely reduces the hackiness a step. Have you been able to test if the resulting jar actually loads BLST on an M1 Mac using a native JVM?

ajsutton commented 2 years ago

Ah, the downside of just calling ./build.sh is it doesn't build the portable version of BLST - it builds the fully optimised one which doesn't work on all CPUs. The key question is whether there are any Macs that don't work with the optimised version - I'd have to go read up on the details of what's required in a CPU. Might be able to just call the top level build.sh with the portable arg like was done previously to solve it...

Also seems the latest blst doesn't like my approach which isn't so great...

ajsutton commented 2 years ago

@dwhjames I've switched over to your approach with a couple of tweaks to ensure we keep building a compatible library. I note that you called the directory aarch64 and I previously had it as arm64 so there's a good chance that's all that was stopping it from working previously.

Attached is a zip file with the jblst jar built from this PR and a little test class that tries to init the BLST native library. It works on my x86 Mac but I don't have an M1 Mac to try it on.

blst-test.zip

dwhjames commented 2 years ago

The arm64 vs. aarch64 is annoying

❯ echo $OSTYPE
darwin20.0
❯ echo $CPUTYPE
arm64

yet

System.getProperty(“os.name”) == "Mac OS X"
System.getProperty(“os.arch”) == "aarch64"

and clang -arch arm64 rather than -aarch aarch64 🤯


Anyway, I don’t have a M1 Mac either, but I got a colleague to run my version of this and it succeeded.

Our only differences are:

  1. ~my environment has the 11.3 SDK~ (Looks like Xcode 12.5.0 has macOS SDK 11.3)
  2. I ran without "-D__BLST_PORTABLE__"

Your variation looks 👍