c++ so的undefined symbol問題

我有一隻簡單的範例程式如下,我想把它編成so好透過JNA存取:

test.c
int test()
{
        return 0;
}

接著透過以下指令把它編成so:

g++ -shared -fPIC -o libtest.so test.c

JNA與測試程式如下:

Tester.java
import com.sun.jna.Library;
import com.sun.jna.Native;
 
public class Tester {
 
	public interface Test extends Library {
		Test INSTANCE = (Test)Native.loadLibrary("test", Test.class);
 
		int test();
	}
 
	public static void main(String[] args) {
		System.out.println(Test.INSTANCE.test());
	}
}

在執行後會出現以下錯誤: (請記得要設定環境變數LD_LIBRARY_PATH)

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'test': /opt/test/libtest.so: undefined symbol: test
	at com.sun.jna.Function.<init>(Function.java:208)
	at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:536)
	at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:513)
	at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:499)
	at com.sun.jna.Library$Handler.invoke(Library.java:199)
	at com.sun.proxy.$Proxy0.test(Unknown Source)
	at com.supermicro.ssm.common.jna.Tester.main(Tester.java:15)

在我透過gcc編成so時,這問題是沒發生過的。到底兩者差在哪呢? 因此我也透過gcc指令去產生so檔來做比較:

gcc -shared -fPIC -o libtest.so test.c

接著使用nm -D去確認dynamic symbol的差異:

發現是由於g++所產生的symbol參雜了其它東西,這是由於C++為了function overloading使用了Name mangling的技術。 為了避免這個問題,我們可以透過在function宣告extern “C”:

test.c
extern "C" int test()
{
        return 0;
}

此時可以透過nm -D指令去確認編譯出來的so檔,是否保有原本的symbol名稱,與確認JNA已可正常使用。