Linux共享庫中的函數,默認都是可以外部可見的,也就是不需要像Windows下通過DEF文件或者dllexport指令來導出。先寫一個源文件:MyExportFunctions.cpp
,內容如下:
1
2
3
4
5
6
int Add(int a, int b) {
return a + b;
}
int Sub(int a, int b) {
return a - b;
}
用gcc編譯成共享庫:
1
gcc -shared -o libExportFunctions.so MyExportFunctions.cpp
用nm -g
命令看查看所有導出的函數,Add和Sub都已經導出了。
1
2
3
4
5
6
7
8
9
10
11
12
13
nm -g libExportFunctions.so
0000000000201028 B __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000201028 D _edata
0000000000201030 B _end
00000000000006ac T _fini
w __gmon_start__
0000000000000550 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000680 T _Z3Addii
0000000000000694 T _Z3Subii
不過為什麼函數名不是Add和Sub,而是_Z3Addii和_Z3Subii (可以給nm 加上參數 –demangle來把c++修飾後的名字翻譯回來,也可以用c++filt這個命令來轉換),這是因為這兩個函數是在c++源文件裡聲明的,而c++編譯器會給函數名自動加上一些修飾符,解決方法就是加extern “C”.
1
2
3
4
5
6
7
8
extern "C"{
int Add(int a, int b) {
return a + b;
}
int Sub(int a, int b) {
return a - b;
}
}
nm -g 的結果是這樣
1
2
3
4
5
6
7
8
9
10
11
12
13
nm -g libExportFunctions.so
0000000000000670 T Add
0000000000201028 B __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000201028 D _edata
0000000000201030 B _end
000000000000069c T _fini
w __gmon_start__
0000000000000540 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
0000000000000684 T Sub
這樣Add和Sub都是原來的名字了。
那怎麼樣只導出需要的函數呢?gcc的一篇關於可見性的wiki說得挺詳細gcc函數可見性
先在編譯時用-fvisibility=hidden把函數都改成默認不可見 ,然後在需要導出函數的聲明前加attribute ((visibility (“default”)))。修改後的代碼
1
2
3
4
5
6
7
8
extern "C"{
__attribute__ ((visibility ("default"))) int Add(int a, int b) {
return a + b;
}
int Sub(int a, int b) {
return a - b;
}
}
然後在編譯時加上-fvisibility=hidden
1
gcc -shared -fvisibility=hidden -o libExportFunctions.so MyExportFunctions.cpp
這次nm -g的輸出中就只有Add,沒有Sub了
1
2
3
4
5
6
7
8
9
10
11
12
nm -g libExportFunctions.so
0000000000000660 T Add
0000000000201028 B __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000201028 D _edata
0000000000201030 B _end
000000000000068c T _fini
w __gmon_start__
0000000000000528 T _init
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
上面說的這種方式類似Windows下的dllexport指令,那有沒有跟DEF文件類似的東西可以在配置文件裡配置哪些函數是導出的呢?gcc也有類似的配置文件,可以看GNU Export Maps。用法很簡單,創建一個文本文件,叫exportmap,內容是這樣
1
2
3
4
{
global: Sub;
local: *;
};
然後編譯時帶–version-script參數
1
gcc -shared -Wl,--version-script=exportmap -o libExportFunctions.so MyExportFunctions.cpp
用nm -g
查看,結果是
1
2
3
4
5
6
7
nm -g libExportFunctions.so
w __cxa_finalize@@GLIBC_2.2.5
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
00000000000005b4 T Sub