From 775fde1ef8fd3c9cfbd2a102f22c444f0d8fda33 Mon Sep 17 00:00:00 2001 From: Nuntipat Narkthong Date: Sun, 11 Apr 2021 21:01:56 +0700 Subject: [PATCH] Add native support for Apple Silicon --- src/main/c/Posix/Makefile | 24 +++++++++++++++++- .../com/fazecast/jSerialComm/SerialPort.java | 4 ++- .../OSX/aarch64/libjSerialComm.jnilib | Bin 0 -> 56690 bytes 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100755 src/main/resources/OSX/aarch64/libjSerialComm.jnilib diff --git a/src/main/c/Posix/Makefile b/src/main/c/Posix/Makefile index d8040d6..e6ce1b5 100644 --- a/src/main/c/Posix/Makefile +++ b/src/main/c/Posix/Makefile @@ -6,6 +6,7 @@ COMPILE_ARM64 := aarch64-unknown-linux-gnueabi-gcc COMPILE_SOLARIS_X86 := x86_64-sun-solaris2.10-gcc COMPILE_SOLARIS_SPARC := sparc-sun-solaris2.10-gcc COMPILE_APPLE := /usr/local/bin/gcc-9 +COMPILE_APPLE_AARCH64 := /usr/bin/gcc LINK := gcc LINK_ARM32 := arm32-unknown-linux-gnueabi-gcc LINK_ARM32HF := arm32hf-unknown-linux-gnueabi-gcc @@ -13,16 +14,20 @@ LINK_ARM64 := aarch64-unknown-linux-gnueabi-gcc LINK_SOLARIS_X86 := x86_64-sun-solaris2.10-gcc LINK_SOLARIS_SPARC := sparc-sun-solaris2.10-gcc LINK_APPLE := /usr/local/bin/gcc-9 +LINK_APPLE_AARCH64 := /usr/bin/gcc CFLAGS := -fPIC -Os -flto -static-libgcc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 CFLAGS_POSIX := -fuse-linker-plugin CFLAGS_APPLE := +CFLAGS_APPLE_AARCH64 := -fPIC -Os -flto -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 LDFLAGS := -Os -flto -static-libgcc LDFLAGS_POSIX := -shared -fuse-linker-plugin -s LDFLAGS_APPLE := -dynamiclib +LDFLAGS_APPLE_AARCH64 := -Os -flto -dynamiclib JDK_HOME := $(shell if [ "`uname`" = "Darwin" ]; then echo "`/usr/libexec/java_home`"; else echo "$$JDK_HOME"; fi) INCLUDES := -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/linux" -I"$(JDK_HOME)/include/darwin" -I"$(JDK_HOME)/include/solaris" LIBRARIES_POSIX := LIBRARIES_APPLE := -framework Cocoa -framework IOKit -framework JavaVM +LIBRARIES_APPLE_AARCH64 := -framework Cocoa -framework IOKit DELETE := @rm MKDIR := @mkdir COPY := @cp @@ -53,6 +58,7 @@ OBJECTSsolaris64 := $(BUILD_DIR)/solaris_x86_64/SerialPort_Posix.o $(BUILD_DIR OBJECTSsolarisSparc32 := $(BUILD_DIR)/solaris_sparc32/SerialPort_Posix.o $(BUILD_DIR)/solaris_sparc32/PosixHelperFunctions.o OBJECTSsolarisSparc64 := $(BUILD_DIR)/solaris_sparc64/SerialPort_Posix.o $(BUILD_DIR)/solaris_sparc64/PosixHelperFunctions.o OBJECTSosx64 := $(BUILD_DIR)/osx_x86_64/SerialPort_Posix.o $(BUILD_DIR)/osx_x86_64/PosixHelperFunctions.o +OBJECTSosxaarch64 := $(BUILD_DIR)/osx_aarch64/SerialPort_Posix.o $(BUILD_DIR)/osx_aarch64/PosixHelperFunctions.o CPATH_APPLE := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include FLAGSlinux32 := -m32 FLAGSlinux64 := -m64 @@ -68,6 +74,7 @@ FLAGSsolaris64 := -m64 FLAGSsolarisSparc32 := -mno-app-regs -mcpu=v8 -mv8plus -m32 FLAGSsolarisSparc64 := -mno-app-regs -mcpu=v9 -m64 FLAGSosx64 := -m64 +FLAGSosxaarch64 := JNI_HEADER := ../com_fazecast_jSerialComm_SerialPort.h JAVA_CLASS := $(JAVA_CLASS_DIR)/SerialPort.class @@ -103,6 +110,11 @@ osx : osx64 $(DELETE) -rf "$(BUILD_DIR)" $(DELETE) -rf ../*.h +# Build all OSX (Apple Silicon) libraries +osx_aarch64 : osxaarch64 + $(DELETE) -rf "$(BUILD_DIR)" + $(DELETE) -rf ../*.h + # Build architecture-specific Linux libraries linux32 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/linux_x86 $(BUILD_DIR)/linux_x86/$(LIBRARY_NAME_POSIX) $(DELETE) -rf $(BUILD_DIR)/linux_x86/*.o @@ -152,7 +164,11 @@ solarisSparc64 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/solaris_sparc64 $(BUILD_DIR)/sol osx64 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/osx_x86_64 $(BUILD_DIR)/osx_x86_64/$(LIBRARY_NAME_APPLE) $(DELETE) -rf $(BUILD_DIR)/osx_x86_64/*.o $(COPY) $(BUILD_DIR)/osx_x86_64/*.* $(RESOURCE_DIR_OSX)/x86_64 - + +osxaarch64 : $(JAVA_CLASS_DIR) $(BUILD_DIR)/osx_aarch64 $(BUILD_DIR)/osx_aarch64/$(LIBRARY_NAME_APPLE) + $(DELETE) -rf $(BUILD_DIR)/osx_aarch64/*.o + $(COPY) $(BUILD_DIR)/osx_aarch64/*.* $(RESOURCE_DIR_OSX)/aarch64 + # Rule to create build directories $(BUILD_DIR)/linux_x86 : $(MKDIR) -p $@ @@ -182,6 +198,8 @@ $(BUILD_DIR)/solaris_sparc64 : $(MKDIR) -p $@ $(BUILD_DIR)/osx_x86_64 : $(MKDIR) -p $@ +$(BUILD_DIR)/osx_aarch64 : + $(MKDIR) -p $@ $(JAVA_CLASS_DIR) : $(MKDIR) -p $@ @@ -214,6 +232,8 @@ $(BUILD_DIR)/solaris_sparc64/$(LIBRARY_NAME_POSIX) : $(JNI_HEADER) $(OBJECTSsola $(LINK_SOLARIS_SPARC) $(LDFLAGS) $(LDFLAGS_POSIX) $(FLAGSsolarisSparc64) -o $@ $(OBJECTSsolarisSparc64) $(LIBRARIES_POSIX) $(BUILD_DIR)/osx_x86_64/$(LIBRARY_NAME_APPLE) : $(JNI_HEADER) $(OBJECTSosx64) $(LINK_APPLE) $(LDFLAGS) $(LDFLAGS_APPLE) $(FLAGSosx64) -o $@ $(OBJECTSosx64) $(LIBRARIES_APPLE) +$(BUILD_DIR)/osx_aarch64/$(LIBRARY_NAME_APPLE) : $(JNI_HEADER) $(OBJECTSosxaarch64) + $(LINK_APPLE_AARCH64) $(LDFLAGS_APPLE_AARCH64) $(FLAGSosxaarch64) -o $@ $(OBJECTSosxaarch64) $(LIBRARIES_APPLE_AARCH64) # Suffix rules to get from *.c -> *.o $(BUILD_DIR)/linux_x86/%.o : %.c @@ -244,6 +264,8 @@ $(BUILD_DIR)/solaris_sparc64/%.o : %.c $(COMPILE_SOLARIS_SPARC) $(INCLUDES) $(CFLAGS) $(CFLAGS_POSIX) $(FLAGSsolarisSparc64) -c $< -o $@ $(BUILD_DIR)/osx_x86_64/%.o : %.c CPATH=$(CPATH_APPLE) $(COMPILE_APPLE) $(INCLUDES) $(CFLAGS) $(CFLAGS_APPLE) $(FLAGSosx64) -c $< -o $@ +$(BUILD_DIR)/osx_aarch64/%.o : %.c + CPATH=$(CPATH_APPLE) $(COMPILE_APPLE_AARCH64) $(INCLUDES) $(CFLAGS_APPLE_AARCH64) $(FLAGSosxaarch64) -c $< -o $@ # Rule to build JNI header file $(JNI_HEADER) : $(JAVA_CLASS) diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 4f9983a..412c276 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -105,7 +105,9 @@ public final class SerialPort } else if (OS.indexOf("mac") >= 0) { - if (System.getProperty("os.arch").indexOf("64") >= 0) + if (System.getProperty("os.arch").equals("aarch64")) + libraryPath = "OSX/aarch64"; + else if (System.getProperty("os.arch").indexOf("64") >= 0) libraryPath = "OSX/x86_64"; else libraryPath = "OSX/x86"; diff --git a/src/main/resources/OSX/aarch64/libjSerialComm.jnilib b/src/main/resources/OSX/aarch64/libjSerialComm.jnilib new file mode 100755 index 0000000000000000000000000000000000000000..b20718ef5525a5cdf31b6e5d3f18cd0942804632 GIT binary patch literal 56690 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