java调用golang

人活着,是一种责任,也是一种迁就,走在自己的路上,总有一些无奈,也有一些放弃,时间沉醉,人生迷茫

Posted by yishuifengxiao on 2025-06-05

前提准备

在Windows中开发时

安装一个window平台可用的c编译器,以下两个安装任意一个即可

安装成功之后,执行以下命令:

λ gcc -v
specs
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C:/TDM-GCC-64/bin/../libexec/gcc/x86_64-w64-mingw32/10.3.0/lto-wrapper.exe
x86_64-w64-mingw32
../../../src/gcc-git-10.3.0/configure --build=x86_64-w64-mingw32 --enable-targets=all --enable-languages=ada,c,c++,fortran,jit,lto,objc,obj-c++ --enable-libgomp --enable-lto --enable-graphite --enable-cxx-flags=-DWINPTHREAD_STATIC --disable-build-with-cxx --disable-build-poststage1-with-cxx --enable-libstdcxx-debug --enable-threads=posix --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts=yes --disable-libstdcxx-pch --enable-libstdcxx-threads --enable-libstdcxx-time=yes --enable-mingw-wildcard --with-gnu-ld --disable-werror --enable-nls --disable-win32-registry --enable-large-address-aware --disable-rpath --disable-symvers --prefix=/mingw64tdm --with-local-prefix=/mingw64tdm --with-pkgversion=tdm64-1 --with-bugurl=https://github.com/jmeubank/tdm-gcc/issues
posix
Supported LTO compression algorithms: zlib zstd
gcc 10.3.0 (tdm64-1)

若出现类似提示则说明安装成功。

在linux中开发时

先安装gcc-mingw-w64-x86-64

sudo apt install gcc-mingw-w64-x86-64

开发golang代码

golang示例代码如下:

package main

import "C"
import (
"fmt"
"reflect"
"unsafe"
)

var step = 1

//export Add
func Add(a, b C.int) C.int {
step++
return a + b
}

//export AddInt32
func AddInt32(a, b int32) int32 {
step++
return a + b
}

//export AddInt64
func AddInt64(a, b int64) int64 {
step++
return a + b
}

//export AddFloat32
func AddFloat32(a, b float32) float32 {
step++
return a + b
}

//export AddFloat64
func AddFloat64(a, b float64) float64 {
step++
return a + b
}

//export VoidDemo
func VoidDemo() {
step++
fmt.Println("VoidDemo")
}

//export Greet
func Greet(name *C.char) *C.char {
step++
goName := C.GoString(name)
greeting := "Hello, " + goName + "!"
return C.CString(greeting)
}

//export ProcessArray
func ProcessArray(input *C.int, length C.int, output *C.int) {
step++
// 转换为Go的切片以便操作
inSlice := (*[1 << 30]C.int)(unsafe.Pointer(input))[:length:length]
outSlice := (*[1 << 30]C.int)(unsafe.Pointer(output))[:length:length]

for i := 0; i < int(length); i++ {
fmt.Println("reflect.TypeOf(inSlice[i]) = ", reflect.TypeOf(inSlice[i]))

outSlice[i] = inSlice[i] + 1
}
}

//export FinalStep
func FinalStep() int {

fmt.Println("最终步骤为:", step)
return step
}

func main() {} // 必须存在main函数

在Windows中编译

编译成dll文件

go build -buildmode=c-shared -o add.dll mian.go

编译成so文件

# 设置目标平台为Linux
set GOOS=linux
set GOARCH=amd64 # 根据目标CPU架构调整(如arm64)

# 执行交叉编译
go build -buildmode=c-shared -o add.so main.go

在linux中编译时

编译成so文件

若目标为Linux系统:直接生成.so文件(无需交叉编译):

go build -buildmode=c-shared -o add.so add.go

编译成dll文件

32位系统兼容:交叉编译时指定GOARCH=386

GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -buildmode=c-shared -o add32.dll add.go

开发Java代码

先引入jna依赖

<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.13.0</version>
</dependency>

接下来以windows平台上调用生成的DLL文件为例演示如何调用

package com.whty.demo;

import com.sun.jna.Library;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

import javax.swing.filechooser.FileSystemView;
import java.io.File;
import java.util.Arrays;

/**
* 1: 先安装 sudo apt install gcc-mingw-w64-x86-64
* 2 linux 上交叉编译为dll ,命令为 GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc go build
* -buildmode=c-shared -o add.dll add.go
*/
public class GoAddExample {
public interface AddDLL extends Library {

AddDLL INSTANCE = Native.loadLibrary(new File(FileSystemView.getFileSystemView().getHomeDirectory(),
"add.dll").getAbsolutePath(), AddDLL.class);

int Add(int a, int b);

float AddFloat32(float a, float b);

double AddFloat64(double a, double b);

int AddInt32(int a, int b);

long AddInt64(long a, long b);

void VoidDemo();

String Greet(String name);

void ProcessArray(Pointer input, int length, Pointer output);

int FinalStep();
}

public static void main(String[] args) {

System.out.println("3 + 5 = " + AddDLL.INSTANCE.Add(3, 5)); // 输出 8

System.out.println(" AddDLL.INSTANCE.Greet = " + AddDLL.INSTANCE.Greet("hello go"));
AddDLL.INSTANCE.VoidDemo();
System.out.println(" AddDLL.INSTANCE.AddInt32 = " + AddDLL.INSTANCE.AddInt32(1, 2));
System.out.println(" AddDLL.INSTANCE.AddInt64 = " + AddDLL.INSTANCE.AddInt64(1, 2));
System.out.println(" AddDLL.INSTANCE.AddFloat32 = " + AddDLL.INSTANCE.AddFloat32(1, 2));
System.out.println(" AddDLL.INSTANCE.AddFloat64 = " + AddDLL.INSTANCE.AddFloat64(1, 2));
int[] inputs = {1, 2, 3, 4, 5};
int[] outputs = processArray(inputs);
System.out.println("原始值:" + Arrays.toString(inputs) + " 输出值为:" + Arrays.toString(outputs));
System.out.println(" AddDLL.INSTANCE.FinalStep = " + AddDLL.INSTANCE.FinalStep());
}


public static int[] processArray(int[] input) {
// 分配输入输出内存
int elemSize = Native.getNativeSize(Integer.TYPE);
Pointer inPtr = new Memory(input.length * elemSize);
Pointer outPtr = new Memory(input.length * elemSize);

// 写入输入数据
inPtr.write(0, input, 0, input.length);

// 调用Go函数
AddDLL.INSTANCE.ProcessArray(inPtr, input.length, outPtr);

// 读取输出数据
int[] output = new int[input.length];
outPtr.read(0, output, 0, output.length);
return output;
}

}

对于上述代码,输出的结果如下:

3 + 5 = 8
AddDLL.INSTANCE.Greet = Hello, hello go!
VoidDemo
AddDLL.INSTANCE.AddInt32 = 3
AddDLL.INSTANCE.AddInt64 = 3
AddDLL.INSTANCE.AddFloat32 = 3.0
AddDLL.INSTANCE.AddFloat64 = 3.0
reflect.TypeOf(inSlice[i]) = main._Ctype_int
reflect.TypeOf(inSlice[i]) = main._Ctype_int
reflect.TypeOf(inSlice[i]) = main._Ctype_int
reflect.TypeOf(inSlice[i]) = main._Ctype_int
reflect.TypeOf(inSlice[i]) = main._Ctype_int
原始值:[1, 2, 3, 4, 5] 输出值为:[2, 3, 4, 5, 6]
最终步骤为: 9
AddDLL.INSTANCE.FinalStep = 9