差異處
這裏顯示兩個版本的差異處。
下次修改 | 前次修改 | ||
java:jna:c_so的undefined_symbol問題 [2017/03/16 10:48] tony 建立 |
java:jna:c_so的undefined_symbol問題 [2023/06/25 09:48] (目前版本) |
||
---|---|---|---|
行 1: | 行 1: | ||
+ | {{tag>jna cpp mangling}} | ||
====== c++ so的undefined symbol問題 ====== | ====== c++ so的undefined symbol問題 ====== | ||
===== Problem ===== | ===== Problem ===== | ||
- | 我有一隻很簡單的程式如下,我想把它編成so好透過JNA存取: | + | 我有一隻簡單的範例程式如下,我想把它編成so好透過JNA存取: |
<file cpp test.c> | <file cpp test.c> | ||
int test() | int test() | ||
行 9: | 行 10: | ||
</file> | </file> | ||
+ | 接著透過以下指令把它編成so: | ||
+ | <code bash> | ||
+ | g++ -shared -fPIC -o libtest.so test.c | ||
+ | </code> | ||
+ | JNA與測試程式如下: | ||
+ | <file java 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()); | ||
+ | } | ||
+ | } | ||
+ | </file> | ||
+ | 在執行後會出現以下錯誤: (請記得要設定環境變數LD_LIBRARY_PATH) | ||
+ | <code> | ||
+ | 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) | ||
+ | </code> | ||
+ | ===== How to resolve? ===== | ||
+ | 在我透過gcc編成so時,這問題是沒發生過的。到底兩者差在哪呢? 因此我也透過gcc指令去產生so檔來做比較: | ||
+ | <code bash> | ||
+ | gcc -shared -fPIC -o libtest.so test.c | ||
+ | </code> | ||
+ | 接著使用nm -D去確認dynamic symbol的差異:\\ | ||
+ | {{:java:jna:jna_dump_d_symbol_between_cpp_and_c.png|}}\\ | ||
+ | 發現是由於g++所產生的symbol參雜了其它東西,這是由於C++為了function overloading使用了[[https://en.wikipedia.org/wiki/Name_mangling|Name mangling]]的技術。 | ||
+ | 為了避免這個問題,我們可以透過在function宣告extern "C": | ||
+ | <file cpp test.c> | ||
+ | extern "C" int test() | ||
+ | { | ||
+ | return 0; | ||
+ | } | ||
+ | </file> | ||
+ | 此時可以透過nm -D指令去確認編譯出來的so檔,是否保有原本的symbol名稱,與確認JNA已可正常使用。 | ||
+ | ===== Reference ===== | ||
+ | * [[http://stackoverflow.com/questions/31541451/create-shared-library-from-cpp-files-and-static-library-with-g|Create shared library from cpp files and static library with g++]] | ||
+ | * [[http://stackoverflow.com/questions/34732/how-do-i-list-the-symbols-in-a-so-file|How do I list the symbols in a .so file?]] | ||
+ | * [[http://stackoverflow.com/questions/15965592/calling-a-c-dll-method-from-java-using-jna-and-avoiding-method-name-mangling|Calling a C++ dll method from Java using JNA and avoiding Method Name Mangling]] | ||
+ | * [[https://puremonkey2010.blogspot.tw/2010/08/c-cextern-c.html|extern "C"的意義]] | ||
+ | * [[http://b8807053.pixnet.net/blog/post/3612202-c%2B%2B%E4%B8%ADextern-c%E5%90%AB%E7%BE%A9%E6%B7%B1%E5%B1%A4%E6%8E%A2%E7%B4%A2|C++中extern C含義深層探索]] | ||
+ | * [[https://en.wikipedia.org/wiki/Name_mangling|Name Mangling]] | ||
+ | |||
+ | ===== ===== | ||
+ | ---- | ||
+ | \\ | ||
+ | ~~DISQUS~~ | ||