『壹』 什麼是靜態鏈接庫什麼是動態鏈接庫他們有什麼區別
一、動態鏈接庫的概念
動態鏈接庫(Dynamic Link Library,縮寫為DLL)是一個可以被其它應用程序共享的程序模塊,其中封裝了一些可以被共享的常式和資源。動態鏈接庫文件的擴展名一般是dll,也有可能是drv、sys和fon,它和可執行文件(exe)非常類似,區別在於DLL中雖然包含了可執行代碼卻不能單獨執行,而應由Windows應用程序直接或間接調用。
動態鏈接是相對於靜態鏈接而言的。所謂靜態鏈接是指把要調用的函數或者過程鏈接到可執行文件中,成為可執行文件的一部分。換句話說,函數和過程的代碼就在程序的exe文件中,該文件包含了運行時所需的全部代碼。當多個程序都調用相同函數時,內存中就會存在這個函數的多個拷貝,這樣就浪費了寶貴的內存資源。而動態鏈接所調用的函數代碼並沒有被拷貝到應用程序的可執行文件中去,而是僅僅在其中加入了所調用函數的描述信息(往往是一些重定位信息)。僅當應用程序被裝入內存開始運行時,在Windows的管理下,才在應用程序與相應的DLL之間建立鏈接關系。當要執行所調用DLL中的函數時,根據鏈接產生的重定位信息,Windows才轉去執行DLL中相應的函數代碼。
一般情況下,如果一個應用程序使用了動態鏈接庫,Win32系統保證內存中只有DLL的一份復製品,這是通過內存映射文件實現的。DLL首先被調入Win32系統的全局堆棧,然後映射到調用這個DLL的進程地址空間。在Win32系統中,每個進程擁有自己的32位線性地址空間,如果一個DLL被多個進程調用,每個進程都會收到該DLL的一份映像。
『貳』 面試 | linux 下的動態鏈接庫問題
在 Linux 開發時,我們經常會看到一些形如 xxx.so 的名稱出現,其中 so 是 Shared Object 的縮寫,即可以共享的目標文件,也就是我們所稱為的動態鏈接庫,和在 Windows 下大家玩 游戲 時遇到的 xxx.dll 錯誤中的文件是一個類型的。
面試中經常會問到以下問題:
庫是寫好的現有的,成熟的,可以復用的代碼。現實中每個程序都要依賴很多基礎的底層庫,不可能每個人的代碼都從零開始,因此庫的存在意義非同尋常。本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。
庫有兩種:
在一個程序的編譯過程中,分為以下幾個步驟: 預處理 , 編譯 , 匯編 , 鏈接 。本文中討論的鏈接庫就是針對最後一個步驟「鏈接」而言的。
動態庫和靜態庫的區別
左圖為靜態鏈接庫,右圖為動態鏈接庫
對於靜態鏈接庫而言在鏈接階段,會將匯編生成的「目標文件.o」與引用到的庫一起鏈接打包到可執行文件中。因此對應的鏈接方式稱為靜態鏈接:
靜態鏈接可以理解為最後生成了一個「單文件免安裝綠色版」的程序,優點在於移植的時候只需要移動這一個文件,缺點在於文件體積非常大,為了解決這樣的問題,就有了動態鏈接庫。動態鏈接庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行時才被載入。
動態庫連接到系統空間,如果多個程序連接了同一個庫,那麼只需要一份,優點在於編譯程序的時候不會將對應的庫文件全部打包在生成的程序中,而是保留了到對應庫的鏈接,缺點就是移植的時候如果只移動了對應的程序沒有安裝相關的庫的話,就會看到類似以下喜聞樂見的結果了。
在 Linux 下一個動態庫有y三個不同名字的文件組成:
當程序在內部列出所需要的鏈接庫時,僅僅使用 soname。當你創建一個鏈接庫時,使用 real name。安裝一個新的鏈接庫時,把它復制到一個DLL文件夾里,然後運行程序 ldconfig。ldconfig 檢查存在的 real name 文件,並且創建指向它符號鏈接 soname 文件。可能大家比較常見到的有 libsodium 等。
有了上面關於庫的一些基礎知識之後,我們可以開始嘗試創建一個動態庫來供程序使用了。
比如我們有一個求最大值的函數 max(int a,int b,int c) ,放在文件 max.c 中文件內容如下:
可以通過:
將其編譯為共享庫,-fPIC是編譯選項,PIC是 Position Independent Code 的縮寫,表示要生成位置無關的代碼,這是動態庫需要的特性; -shared是鏈接選項,告訴 gcc 生成動態庫而不是可執行文件。為了讓用戶知道我們的動態庫中有哪些介面可用,我們需要編寫對應的頭文件,比如可以寫一個 max.h :
設置一個驅動函數來測試我們編寫的動態庫:
通過 gcc test.c -L. -lmax來生成 a.out,其中-lmax表示要鏈接 libmax.so,-L.表示搜索要鏈接的庫文件時包含當前路徑。
但是這樣直接運行的話,會出現一個錯誤:
由於 Linux 是通過/etc/ld.so.cache文件搜尋要鏈接的動態庫的,而 /etc/ld.so.cache 是 ldconfig 程序讀取 /etc/ld.so.conf 文件生成的,本次使用的動態庫 libmax.so 並不在對應的目錄下,就會導致程序無法找到對應的動態鏈接庫,這樣我們的解決方法有二:
小結
動態鏈接庫是各個系統中的一個重要的組成部分且在 Linux 開發相關領域中尤為重要,也是一個面試的高頻考點,除了動態鏈接庫以外,還有以下相關知識也是高頻考點,在面試前一定要准備好:
本文作者:Nova Kwok
『叄』 linuxopencv生成的靜態或動態庫怎樣在調用的時候不用安裝openvcv環境
使用cmake編譯opencv靜態鏈接庫(靜態庫),配置環境變數(動態庫和靜態庫一樣),復制dll文件。
將這三個dll分別復制到C:WindowsSystem32和C:WindowsSysWOW64目錄下。
配置包含目錄:視圖->其它窗口->屬性管理器。配置庫目錄然後配置附加依賴項。
『肆』 linux動態庫和靜態庫的區別
動態鏈接庫和靜態鏈接庫一般是編譯集成一系列的介面(函數)
在程序源代碼編譯完成後通過編譯器編譯並通過鏈接器與這些庫進行鏈接
動態鏈接庫與靜態鏈接庫的區別在於鏈接器在進行鏈接時靜態庫會被直接編譯進程序里
而動態鏈接庫並不會,我們這里將這些鏈接庫稱作依賴(動態庫和靜態庫)
程序的運行需要這些依賴,程序在靜態鏈接後該程序本身便已包含該依賴
而動態鏈接後的程序本身本不包含該依賴,這些依賴需要執行者自行安裝進操作系統(動態庫、運行時庫)
程序運行時會動態地載入這些庫
linux上動態庫一般的後綴後為.so
靜態庫一般的後綴為.a
由於靜態鏈接會直接將庫編譯進程序里所以靜態編譯後的程序相較於動態鏈接所要大
這就是因為靜態鏈接會將鏈接庫編譯進程序里的原因,所以佔用就要大了
出於這種原因,靜態庫不易於維護與更新,如果鏈接庫中有實現有bug等需要更新則需要更新整個程序,因為靜態庫被編譯進程序中了
但動態庫就沒有這種情況了,因為動態庫是程序運行時動態載入的,所以我們只需要更新動態庫而不需要更新所有依賴該庫的程序(軟體)
另一方面,很多程序的開發都會使用到相同的鏈接庫,也就是很多程序(軟體)會有相同的依賴
如果將這些依賴全部靜態編譯的話將會造成存儲資源佔用過多而造成資源浪費
而使用動態庫的方式這些程序(軟體)則可以共享一個鏈接庫,而不需要每個程序都帶一個鏈接庫,這樣就大大地減少了存儲資源佔用空間
『伍』 linux 動態鏈接和靜態鏈接的區別
兩者區別:a,靜態庫的使用需要:1包含一個對應的頭文件告知編譯器lib文件裡面的具體內容2設置lib文件允許編譯器去查找已經編譯好的二進制代碼b,動態庫的使用:程序運行時需要載入動態庫,對動態庫有依賴性,需要手動加入動態庫c,依賴性:靜態鏈接表示靜態性,在編譯鏈接之後,lib庫中需要的資源已經在可執行程序中了,也就是靜態存在,沒有依賴性了動態,就是實時性,在運行的時候載入需要的資源,那麼必須在運行的時候提供需要的動態庫,有依賴性,運行時候沒有找到庫就不能運行了d,區別:簡單講,靜態庫就是直接將需要的代碼連接進可執行程序;動態庫就是在需要調用其中的函數時,根據函數映射表找到該函數然後調入堆棧執行。做成靜態庫可執行文件本身比較大,但不必附帶動態庫做成動態庫可執行文件本身比較小,但需要附帶動態庫鏈接靜態庫,編譯的可執行文件比較大,當然可以用strip命令精簡一下(如:striplibtest.a),但還是要比鏈接動態庫的可執行文件大。程序運行時間速度稍微快一點。靜態庫是程序運行的時候已經調入內存,不管有沒有調用,都會在內存里頭。靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。其在編譯程序時若鏈接,程序運行時會在系統指定的路徑下搜索,然後導入內存,程序一般執行時間稍微長一點,但編譯的可執行文件比較小;動態庫是程序運行的時候需要調用的時候才裝入內存,不需要的時候是不會裝入內存的。動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態庫存在。動態鏈接庫的特點與優勢首先讓我們來看一下,把庫函數推遲到程序運行時期載入的好處:1.可以實現進程之間的資源共享。什麼概念呢?就是說,某個程序的在運行中要調用某個動態鏈接庫函數的時候,操作系統首先會查看所有正在運行的程序,看在內存里是否已有此庫函數的拷貝了。如果有,則讓其共享那一個拷貝;只有沒有才鏈接載入。這樣的模式雖然會帶來一些「動態鏈接」額外的開銷,卻大大的節省了系統的內存資源。C的標准庫就是動態鏈接庫,也就是說系統中所有運行的程序共享著同一個C標准庫的代碼段。2.將一些程序升級變得簡單。用戶只需要升級動態鏈接庫,而無需重新編譯鏈接其他原有的代碼就可以完成整個程序的升級。Windows就是一個很好的例子。3.甚至可以真正坐到鏈接載入完全由程序員在程序代碼中控制。程序員在編寫程序的時候,可以明確的指明什麼時候或者什麼情況下,鏈接載入哪個動態鏈接庫函數。你可以有一個相當大的軟體,但每次運行的時候,由於不同的操作需求,只有一小部分程序被載入內存。所有的函數本著「有需求才調入」的原則,於是大大節省了系統資源。比如現在的軟體通常都能打開若干種不同類型的文件,這些讀寫操作通常都用動態鏈接庫來實現。在一次運行當中,一般只有一種類型的文件將會被打開。所以直到程序知道文件的類型以後再載入相應的讀寫函數,而不是一開始就將所有的讀寫函數都載入,然後才發覺在整個程序中根本沒有用到它們。靜態庫:在編譯的時候載入生成目標文件,在運行時不用載入庫,在運行時對庫沒有依賴性。動態庫:在目標文件運行時載入,手動載入,且對庫有依賴性。具體在開發中用到哪種庫,我覺得還是根據實際的內存大小,ROM大小,運行的速度等綜合考慮。
『陸』 linux怎樣實現c語言動態庫與靜態庫的鏈接
Linux系統中靜態庫是.a文件,編譯鏈接.a文件只需要加上.a文件的完整的文件路徑就可以了,比如:
gcc -o hello hello.c /usr/lib/libm.a
Linux系統的動態庫是系統中的.so文件,編譯鏈接動態庫需要用-L參數指定動態庫的搜索路徑,還要用-l(這個是小寫的L)指定動態庫的名字,比如:
gcc -o hello hello.c -L/usr/openssl/lib -lcrypto
『柒』 linux下的靜態庫與動態庫的區別和使用
一、引言
我們通常把一些公用函數製作成函數庫,供其它程序使用。
函數庫分為靜態庫和動態庫兩種。
通常情況下,對函數庫的鏈接是放在編譯時期(compile time)完成的。所有相關的對象文件(object file)與牽涉到的函數庫(library)被鏈接合成一個可執行文件(executable file)。程序在運行時,與函數庫再無瓜葛,因為所有需要的函數已拷貝到相應目錄下下。所以這些函數庫被成為靜態庫(static libaray),通常文件名為「libxxx.a」的形式。
其實,我們也可以把對一些庫函數的鏈接載入推遲到程序運行的時期(runtime)。這就是動態鏈接庫(dynamic link library)技術。
二、兩者區別:
a,靜態庫的使用需要:
1 包含一個對應的頭文件告知編譯器lib文件裡面的具體內容
2 設置lib文件允許編譯器去查找已經編譯好的二進制代碼
b,動態庫的使用:
程序運行時需要載入動態庫,對動態庫有依賴性,需要手動加入動態庫
c,依賴性:
靜態鏈接表示靜態性,在編譯鏈接之後, lib庫中需要的資源已經在可執行程序中了, 也就是靜態存在,沒有依賴性了
動態,就是實時性,在運行的時候載入需要的資源,那麼必須在運行的時候提供 需要的 動態庫,有依賴性, 運行時候沒有找到庫就不能運行了
d,區別:
簡單講,靜態庫就是直接將需要的代碼連接進可執行程序;動態庫就是在需要調用其中的函數時,根據函數映射表找到該函數然後調入堆棧執行。
做成靜態庫可執行文件本身比較大,但不必附帶動態庫
做成動態庫可執行文件本身比較小,但需要附帶動態庫
鏈接靜態庫,編譯的可執行文件比較大,當然可以用strip命令精簡一下(如:strip libtest.a),但還是要比鏈接動態庫的可執行文件大。程序運行時間速度稍微快一點。
靜態庫是程序運行的時候已經調入內存,不管有沒有調用,都會在內存里頭。靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。
其在編譯程序時若鏈接,程序運行時會在系統指定的路徑下搜索,然後導入內存,程序一般執行時間稍微長一點,但編譯的可執行文件比較小;動態庫是程序運行的時候需要調用的時候才裝入內存,不需要的時候是不會裝入內存的。
動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態庫存在。
三、動態鏈接庫的特點與優勢
首先讓我們來看一下,把庫函數推遲到程序運行時期載入的好處:
1. 可以實現進程之間的資源共享。
什麼概念呢?就是說,某個程序的在運行中要調用某個動態鏈接庫函數的時候,操作系統首先會查看所有正在運行的程序,看在內存里是否已有此庫函數的拷貝了。如果有,則讓其共享那一個拷貝;只有沒有才鏈接載入。這樣的模式雖然會帶來一些「動態鏈接」額外的開銷,卻大大的節省了系統的內存資源。C的標准庫就是動態鏈接庫,也就是說系統中所有運行的程序共享著同一個C標准庫的代碼段。
2. 將一些程序升級變得簡單。用戶只需要升級動態鏈接庫,而無需重新編譯鏈接其他原有的代碼就可以完成整個程序的升級。Windows 就是一個很好的例子。
3. 甚至可以真正坐到鏈接載入完全由程序員在程序代碼中控制。
程序員在編寫程序的時候,可以明確的指明什麼時候或者什麼情況下,鏈接載入哪個動態鏈接庫函數。你可以有一個相當大的軟體,但每次運行的時候,由於不同的操作需求,只有一小部分程序被載入內存。所有的函數本著「有需求才調入」的原則,於是大大節省了系統資源。比如現在的軟體通常都能打開若干種不同類型的文件,這些讀寫操作通常都用動態鏈接庫來實現。在一次運行當中,一般只有一種類型的文件將會被打開。所以直到程序知道文件的類型以後再載入相應的讀寫函數,而不是一開始就將所有的讀寫函數都載入,然後才發覺在整個程序中根本沒有用到它們。
靜態庫:在編譯的時候載入生成目標文件,在運行時不用載入庫,在運行時對庫沒有依賴性。
動態庫:在目標文件運行時載入,手動載入,且對庫有依賴性。
具體在開發中用到哪種庫,我覺得還是根據實際的內存大小,ROM大小,運行的速度等綜合考慮。