編譯通過動態庫載入失敗
A. WIN7 64位 下VS2015編譯通過,但是無法啟動程序 提示 WinTab32.dll 已經載入但是找不到入口點怎麼辦
方法/步驟
1、通常在運行中注冊動態庫文件:regsvr32 msi.dll (按回車鍵執行命令)都能順利通過。
2、但也有出錯提示:
模塊「xxx.dll」已載入,但找不到入口點DLLRegisterServer
請確保xxx.dll為有效的DLL或OCX文件,然後重試。
3、這就要看當前是單個動態鏈文件不能注冊,還是所有的文件都是注冊無效。如果是單個文件注冊無效,那就是這個動態鏈文件有問題,找到相同的操作系統(32位或者64位)相應的路徑中,復制一個(網上下載也行),保存到自己的操作系統中即可。64位操作系統的路徑是:C:\Windows\System32 文件夾內。
4、如果是64位的操作系統,那麼提取、保存正確的32位動態鏈文件的路徑是:
C:\Windows\SysWOW64 文件夾內。
5、如果所有的動態鏈文件注冊都無效,那就是當前的操作系統無許可權。可以載入許可權注冊即可。步驟如下:
開始→所有程序→附件→右鍵點擊命令提示符(CMD)→以管理員身份運行。
6、然後,再使用命令注冊: regsvr32 msi.dll
提示:可以先復制命令,再點擊左上角,在彈出來的菜單中點選編輯→粘貼命令。
7、注冊成功之後會有提示。
8、也可以將絕對路徑添加上去(先去該路徑查找是否有這個動態鏈文件):
regsvr32 C:\Windows\SysWOW64\msi.dll
9、最後,注意命令參數的應用,有時候需要先解除注冊,之後再注冊才可以。
1右鍵添加以管理員身份運行。
B. 關於linux下連接動態庫問題
gcc編譯時,當使用動態庫編譯可以按照幾種寫法
1.gcc test.c ./libSDL2-2.so
2.gcc test.c -lSDL2-2
3.gcc test.c -L/home/test -lSDL2-2
一般的編譯參數都是按照2或3去寫
2寫法的含義是從/lib或者/usr/lib目錄下尋找名稱為SDL2-2的庫,即尋找/lib/libSDL2-2.so或者/usr/lib/libSDL2-2.so文件進行鏈接,當然如果沒有動態庫就會去找靜態庫,再沒有應該就會在編譯時報錯
3寫法的含義是從-L參數首先從指定的目錄中尋找需要鏈接的庫文件,隨後再去尋找系統文件夾中是否存在需要的庫
1寫法的含義是將當前目錄下的./libSDL2-2.so.0文件鏈接進最終文件,因此執行readelf -a a.out後在動態庫部分所看到的路徑就是./libSDL2-2.so.0,進而在執行文件時僅會從當前目錄下尋找libSDL2-2.so.0文件,當執行文件時所在的目錄下沒有該文件時就會出現找不到庫文件的操作
你第二次操作時,因為function.so庫文件與a.out文件在同一個目錄,同時也是在該目錄下執行的ldd操作及運行a.out,a.out在載入動態庫時從當前目錄下找到了所需要的庫文件,此時能夠執行成功(ldd命令實質是一個腳本,通過設置環境變數運行動態庫鏈接器來輸出所有待鏈接的動態庫)。
你可以試試將a.out拷貝至其他目錄再次運行,將出現和第一次操作時一樣的現象,找不到function.so文件。
具體的解決方法就是修改編譯參數,將./libSDL2-2.so.0修改為-lSDL2-2並將libSDL2-2.so.0文件拷貝至/usr/lib目錄下,並且可能因為沒有修改鏈接器的緩存文件(將可能找不到帶版本號後綴的動態庫),需要在/usr/lib目錄下建立一個文件連接(ln -s libSDL2-2.so.0 libSDL2-2.so)或者直接修改名稱為libSDL2-2.so
C. linux 靜態庫和動態庫編譯的區別
Linux庫有動態與靜態兩種,動態通常用.so為後綴,靜態用.a為後綴。例如:libhello.so libhello.a
為了在同一系統中使用不同版本的庫,可以在庫文件名後加上版本號為後綴,例如: libhello.so.1.0,由於程序連接默認以.so為文件後綴名。所以為了使用這些庫,通常使用建立符號連接的方式。
ln -s libhello.so.1.0 libhello.so.1
ln -s libhello.so.1 libhello.so
動態庫和靜態庫的區別:
當要使用靜態的程序庫時,連接器會找出程序所需的函數,然後將它們拷貝到執行文件,由於這種拷貝是完整的,所以一旦連接成功,靜態程序庫也就不再需要了。然而,對動態庫而言,就不是這樣。動態庫會在執行程序內留下一個標記『指明當程序執行時,首先必須載入這個庫。由於動態庫節省空間,linux下進行連接的預設操作是首先連接動態庫,也就是說,如果同時存在靜態和動態庫,不特別指定的話,將與動態庫相連接。
兩種庫的編譯產生方法:
第一步要把源代碼編繹成目標代碼。以下面的代碼hello.c為例,生成hello庫:
/* hello.c */
#include
void sayhello()
{
printf("hello,world\n");
}
用gcc編繹該文件,在編繹時可以使用任何全法的編繹參數,例如-g加入調試代碼等:
gcc -c hello.c -o hello.o
1.連接成靜態庫
連接成靜態庫使用ar命令,其實ar是archive的意思
$ar cqs libhello.a hello.o
2.連接成動態庫
生成動態庫用gcc來完成,由於可能存在多個版本,因此通常指定版本號:
$gcc -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 hello.o
另外再建立兩個符號連接:
$ln -s libhello.so.1.0 libhello.so.1
$ln -s libhello.so.1 libhello.so
這樣一個libhello的動態連接庫就生成了。最重要的是傳gcc -shared 參數使其生成是動態庫而不是普通執行程序。
-Wl 表示後面的參數也就是-soname,libhello.so.1直接傳給連接器ld進行處理。實際上,每一個庫都有一個soname,當連接器發現它正在查找的程序庫中有這樣一個名稱,連接器便會將soname嵌入連結中的二進制文件內,而不是它正在運行的實際文件名,在程序執行期間,程序會查找擁有 soname名字的文件,%B
D. gcc編譯指定了庫路徑,但是還是找不到
不同版本的動態庫是為了升級方便,舊的程序需要與舊的庫鏈接,新的程序與新的. 一般的做法是把libabc.so連接(symbolic link, ln -s libabc.so.N libabc.so)到最新的版本,這樣以後的新程序,在用gcc -labc的時候,都會鏈接到新的版本
E. 缺少動態庫的情況下,能通過編譯嗎
>> 如果你是鏈接動態庫,在GCC後跟了一個-l參數,其後就是你所需庫的名稱,
>> 那麼你不僅需要那個你所需的庫文件,還需要你所需庫的頭文件才行,編譯時需要頭文件支持,
>> 鏈接時需要庫文件,不管你是動態還是靜態編譯都是如此!!!!
頭文件不是必須的。只要沒有出現未聲明的函數/變數的調用就可以。
>> 還需說明的一點是:只有用參數-o時才會有那個-satic的選項,
>> 也就是說只有在鏈接程序時才會有動態鏈接和靜態鏈接之分!!!!!!
沒有 -o 也可以 -static。-o 不代表鏈接
>> 動態鏈接庫是為了減少可執行文件的大小,就是在一個系統中只提供一個庫,
>> 可供多個動態鏈接的程序共同使用
同時也避免庫代碼被重復載入進入內存,減少系統內存佔用