你很不清楚的問題提到.so
文件(但沒有提及任何操作系統)和nm
。所以我猜你在使用Linux,而我的答案只針對Linux。我不明白,如果你想編譯&構建時或在運行時。
給定的共享對象/some/path/to/foo.so
您可以使用dlopen(3)和dlsym(3)功能找出(在運行時),如果該共享對象定義了一個給定的符號。但請注意,在ELF文件符號是將近無類型(例如,您無法從ELF共享對象的名稱中知道某個函數的某些函數的簽名,而沒有某個C頭文件聲明它)。
或者,您可能需要更復雜的software build過程(例如,通過向您的Makefile
添加臨時規則)。請記住,您可以使用metaprogramming技術並在您的構建中使用一些專門的C代碼生成器。如果你的軟件足夠複雜(例如花費數週時間在這些工具上),你甚至可以使用GCC MELT(或者編寫你自己的GCC插件)來定製GCC編譯器。
注意,一些頭文件(對於給定的庫)可以定義一個函數作爲inline
或可限定具有用於它參數的宏(例如,參見waitpid(2),POSIX API的一部分; WIFEXITED
實際上是一個宏)。在這兩種情況下,該函數都不是ELF共享庫的符號,但可以從源代碼正確使用該庫(並正確使用該頭文件)來使用該函數。換句話說,API與一組ELF符號不同。
另請參閱Drepper的Good Practices in Library Design, Implementation, and Maintenance和How To Write Shared Libraries和D.Wheeler Program Library HOWTO。
最後,如果根據已知始終爲假的條件添加一些代碼(例如,讀取約opaque predicates),則編譯器無法優化。
int main(int argc, char**argv) {
// in practice, all the tests above are false,
// but the compiler is not clever enough to optimize
if (getpid()==0) funct1(); // always false
if (argc<0) funct2(); //always false
if (argv[0][0]==(char)0) funct3(); //always false
/// etc
如果職能的簽名需要一些參數,你可以簡單地測試他們的地址:
extern void func1(int); // actually, in some included header
if (argv[0]==NULL || (void*)func1 == NULL
|| (void*)func1 == (void*)3) abort();
(我相信,在C標準允許編譯器優化(void*)func1 == NULL
-as始終爲假 - 但它不會優化(void*)func1 == (void*)3
其中練習在Linux上始終爲false ...)
但是,API又超過了一組ELF符號和一個API「函數」實際上可以是inline
或宏。您可能會對weak symbols感興趣。
嘗試使用gcc「-O0」重新編譯它應該禁用所有優化 – Arseniy
問題很不明確。你能更具體一些,並給出實際的用例和動機。我甚至不明白「API中缺少的功能」的意思,因爲API是一組記錄的公共功能,所以請**編輯您的問題**以改進它並激勵它。要更具體和具體。 –
什麼是實際用途?你想從標準中獲取所有C函數,並檢查你的編譯器是否支持它們?這是很多工作。爲什麼不向編譯器的作者詢問編譯器支持什麼以及有哪些限制? –