Skip to main content
Stack Overflow
  1. About
  2. For Teams

Return to Answer

added 25 characters in body
Source Link
life888888
  • 4.1k
  • 2
  • 8
  • 15

For my case, I compile programs on an x86_64 system targeting the ARM platform.

For your case, you should be compiling on your ARM environment to target the x86_64 (amd64) platform.

Since I don't have a Mac M environment, I can only compile in x86_64 environment and test in ARM environment to simulate the cross-platform compilation process.

Since I don't have a Mac M environment, I can only compile in x86_64 environment and test in ARM environment to simulate the cross-platform compilation process.

For my case, I compile programs on an x86_64 system targeting the ARM platform.

For your case, you should be compiling on your ARM environment to target the x86_64 (amd64) platform.

Source Link
life888888
  • 4.1k
  • 2
  • 8
  • 15

Since I don't have a Mac M, I can only provide my approach to compiling ARM on x86_64:

Project Directory

create a base directory: Java-JNA-Go-MultiArch

The following commands, unless otherwise stated, are executed in the Java-JNA-Go-MultiArch directory by default.

Verify that Docker's QEMU is supported.

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

Test ARM container

Then test whether the ARM container can be executed:

docker run --rm --platform linux/arm64 alpine uname -m

If aarch64 is output, it means QEMU has started normally.

Test AMD container (x86_64)

docker run --rm --platform linux/amd64 alpine uname -m

output: x86_64, it means QEMU has started normally.

go_mylib

crate go_mylib directory.

Java-JNA-Go-MultiArch
└── go_mylib
  ├── mylib.go
  ├── linux-arm-64 (dir)
  └── linux-x86-64 (dir)

mylib.go

package main
import "C"
//export add_integers
func add_integers(a C.int, b C.int) C.int {
 return a + b
}
//export concat_strings
func concat_strings(x *C.char, y *C.char) *C.char {
 result := C.CString(C.GoString(x) + C.GoString(y))
 return result
}
func main() {}

Build

Build ARM64

docker run --rm --platform linux/arm64 \
 -v $(pwd)/go_mylib:/app -w /app \
 golang:latest \
 go build -o linux-arm-64/libmylib.so -buildmode=c-shared mylib.go

Build AMD 64

docker run --rm --platform linux/amd64 \
 -v $(pwd)/go_mylib:/app -w /app \
 golang:latest \
 go build -o linux-x86-64/libmylib.so -buildmode=c-shared mylib.go

Final Result

Java-JNA-Go-MultiArch
└── go_mylib
  ├── mylib.go
  ├── linux-arm-64
  │  ├── libmylib.h
  │  └── libmylib.so
  └── linux-x86-64
    ├── libmylib.h
   └── libmylib.so

Important

When compiling into a shared library (.so) using the Go language, it will reference the version of GLIBC, so you must know which GLIBC version is being used.

Run command:

docker run -it --rm --platform linux/arm64 \
 golang:latest \
 bash

and

docker run -it --rm --platform linux/amd64 \
 golang:latest \
 bash

In container:

ldd --version

get result: GLIBC 2.36

ldd (Debian GLIBC 2.36-9+deb12u9) 2.36

java_app_call_mylib

Project Driectory

Java-JNA-Go-MultiArch
└── java_app_call_mylib
 ├── pom.xml
 └── src
 └── main
 └── java
 └── com
 └── example
 └── JnaExample.java

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>com.example</groupId>
 <artifactId>go-jna-example</artifactId>
 <version>1.0-SNAPSHOT</version>
 <packaging>jar</packaging>
 <properties>
 <maven.compiler.source>17</maven.compiler.source>
 <maven.compiler.target>17</maven.compiler.target>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
 </properties>
 <dependencies>
 <!-- JNA dependency for native library access -->
 <dependency>
 <groupId>net.java.dev.jna</groupId>
 <artifactId>jna</artifactId>
 <version>5.11.0</version>
 </dependency>
 </dependencies>
 <build>
 <finalName>app</finalName>
 </build>
</project>

JnaExample.java

package com.example;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
public class JnaExample {
 // Define interface mapping to local library
 public interface MyLib extends Library {
 
 //Load dynamic library
 MyLib INSTANCE = Native.load("mylib", MyLib.class);
 int add_integers(int a, int b);
 Pointer concat_strings(String x, String y);
 }
 public static void main(String[] args) {
 // Call the add_integers function
 int sum = MyLib.INSTANCE.add_integers(10, 20);
 System.out.println("Sum: " + sum);
 //Call concat_strings function
 Pointer resultPointer = MyLib.INSTANCE.concat_strings("Hello, ", "World!");
 String resultString = resultPointer.getString(0); //Read string from pointer
 System.out.println("Concatenated String: " + resultString);
 // Manually release the memory allocated by malloc
 Native.free(Pointer.nativeValue(resultPointer));
 } 
}

Build

Build in docker container

run command in Java-JNA-Go-MultiArch

docker run --rm \
 -v $(pwd)/java_app_call_mylib:/app -w /app \
 maven:3.8.2-eclipse-temurin-17 \
 mvn clean package
 
docker run --rm \
 -v $(pwd)/java_app_call_mylib:/app -w /app \
 maven:3.8.2-eclipse-temurin-17 \
 mvn dependency:copy-dependencies -DoutputDirectory=target/libs

or

you can run command in Java-JNA-Go-MultiArch/java_app_call_mylib

mvn clean package
mvn dependency:copy-dependencies -DoutputDirectory=target/libs

Output Result

Java-JNA-Go-MultiArch
└── java_app_call_mylib
 ...
 └── target
 ├── app.jar
 └── libs
 └── jna-5.11.0.jar

app

We create an app directory and test it based on the above results.

create app under Java-JNA-Go-MultiArch

Java-JNA-Go-MultiArch
└── app
 ├── app.jar
 ├── libs
 │  └── jna-5.11.0.jar
 ├── linux-arm-64
 │  └── libmylib.so
 └── linux-x86-64
 └── libmylib.so
  • app.jar : copy it from java_app_call_mylib/target
  • libs/jna-5.11.0.jar : copy it from java_app_call_mylib/target
  • linux-arm-64/libmylib.so : copy it from go_mylib
  • linux-x86-64/libmylib.so : copy it from go_mylib

Test ARM64

in Java-JNA-Go-MultiArch

Run command:

docker run -it --rm --platform linux/arm64 \
 -v $(pwd)/app:/app -w /app \
 openjdk:24-ea-17-jdk-bookworm \
 bash

in container:

export LD_LIBRARY_PATH=`pwd`/linux-arm-64
java --enable-native-access=ALL-UNNAMED -cp "libs/*:app.jar" com.example.JnaExample

Test AMD64 (For your needs)

in Java-JNA-Go-MultiArch

Run command:

docker run -it --rm --platform linux/amd64 \
 -v $(pwd)/app:/app -w /app \
 openjdk:24-ea-17-jdk-bookworm \
 bash

in container:

export LD_LIBRARY_PATH=`pwd`/linux-x86-64
java --enable-native-access=ALL-UNNAMED -cp "libs/*:app.jar" com.example.JnaExample

output:

Sum: 30
Concatenated String: Hello, World!

in container:

ldd --version

output:

ldd (Debian GLIBC 2.36-9+deb12u8) 2.36

Why, it keeps checking the GLIBC version?

Run openjdk:17

docker run -it --rm --platform linux/amd64 \
 -v $(pwd)/app:/app -w /app \
 openjdk:17 \
 bash

in container:

# ldd --version
ldd (GNU libc) 2.28
export LD_LIBRARY_PATH=`pwd`/linux-x86-64
java --enable-native-access=ALL-UNNAMED -cp "libs/*:app.jar" com.example.JnaExample

output error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'mylib':
/lib64/libc.so.6: version `GLIBC_2.34' not found (required by /app/linux-x86-64/libmylib.so)
Native library (linux-x86-64/libmylib.so) not found in resource path (libs/jna-5.11.0.jar:app.jar)
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:301)
...
...
Suppressed: java.lang.UnsatisfiedLinkError: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by /app/linux-x86-64/libmylib.so)

That is to say, if your x86_64 target machine has an older GLIBC version, the same error may occur when JDK calls libxxx.so generated by GO.

Since I don't have a Mac M environment, I can only compile in x86_64 environment and test in ARM environment to simulate the cross-platform compilation process.

lang-golang

AltStyle によって変換されたページ (->オリジナル) /