14 靜態和動態鏈結 環境變數

2021-10-13 17:15:53 字數 4705 閱讀 2045

程式由源**變成可執行檔案,一般可以分解為四個步驟,分別是:

①預處理(prepressing):預處理過程主要處理源**中以「#」開始的預編譯指令;

②編譯(compilation):編譯過程把預處理完成的檔案進行詞法、語法、語義等分析並產生相應的彙編**檔案;

③彙編(assembly):彙編過程將彙編**檔案翻譯成機器可以執行的目標檔案;

④鏈結(linking):鏈結過程將彙編生成的目標檔案集合相連線並生成最終的可執行檔案。

如我們對乙個hello.c檔案的處理事實上它是經歷下面這些步驟。

gcc -e hello.c -o hello.i

gcc -s hello.i -o hello.s

gcc -c hello.s -o hello.o

gcc -o hello hello.o

最後一步是鏈結,此時只將乙個目標檔案鏈結起來了,事實上可能還存在許多的可執行檔案。

(1)靜態鏈結

鏈結器在鏈結靜態鏈結庫的時候是以目標檔案(.o)為單位的,如果該靜態庫里的某些方法沒有任何地方呼叫,則這些沒有被呼叫到的方法或變數將會被丟棄掉,不會被鏈結到目標程式中,這樣做可以大大減小生成二進位制檔案的體積。

(2)動態鏈結

動態鏈結在程式執行時才將它們鏈結在一起形成乙個完整的程式,而不是像靜態鏈結一樣把所有程式模組都鏈結成乙個單獨的可執行檔案。此時在程式的鏈結階段時,鏈結器只是拷貝了一些重定位和符號資訊。在程式載入(execve)時才會解析so檔案中**和資料的引用。某個程式在執行中要呼叫某個動態鏈結庫函式的時候,作業系統首先會檢視所有正在執行的程式,看在記憶體裡是否已有此庫函式的拷貝了。如果有,則讓其共享那乙個拷貝;只有沒有才鏈結載入。在程式執行的時候,被呼叫的動態鏈結庫函式被安置在記憶體的某個地方,所有呼叫它的程式將指向這個**段。因此,這些**必須使用相對位址,而不是絕對位址。在編譯的時候,我們需要告訴編譯器,這些物件檔案是用來做動態鏈結庫的,所以要用位址無關**(position independent code (pic))。

庫的搜尋路徑,包括編譯時的搜尋(.a和.so)和執行時的搜尋(.so)。所以雖然使用-l可以鏈結so編譯過程式,但是執行時並不會從-l指定的目錄搜尋從而導致可能執行時找不到檔案。

(1)-l選項指定的目錄,例如:g++ -o test_fun test_fun.c -l. -lfun

(2)-wl,rpath指定的目錄。例如:gcc -o foo foo.c -l. -lfoo -wl,-rpath=./

(3)環境變數ld_library_path中設定的目錄。

(4)/etc/ld.so.cache檔案中快取的檔案位置。

(5)預設的/usr/lib或者/usr/lib64。

(1)-wl,rpath指定的目錄。例如:gcc -o foo foo.c -l. -lfoo -wl,-rpath=./

(2)環境變數ld_library_path中設定的目錄。

(3)/etc/ld.so.cache檔案中快取的檔案位置。

(4)預設的/usr/lib或者/usr/lib64。

ldconfig命令是在預設搜尋目錄(/lib和/usr/lib)以及動態庫配置檔案/etc/ld.so.conf內所列的目錄下,搜尋出可共享的動態鏈結庫(lib*.so*),進而建立出動態裝入程式(ld.so)所需的連線和快取檔案,快取檔案預設為 /etc/ld.so.cache,此檔案儲存已排好序的動態鏈結庫名字列表。程式連線的時候首先從這個快取檔案裡邊查詢,然後再到ld.so.conf的路徑裡邊去詳細找。

(1)往/lib和/usr/lib裡面加東西。此時不用修改/etc/ld.so.conf檔案的,但是新增完後必須呼叫ldconfig,不然新增的library會找不到。另外如果是加到/lib64或者/usr/lib64,則不執行ldconfig也可以找到。

(2)往普通目錄新增library。此時一定要修改/etc/ld.so.conf檔案,往該檔案追加library所在的路徑,然後呼叫ldconfig命令。

舉例:比如你在部署軟體時,有些動態庫安裝在exe目錄下,可以通過如下方法實現,

1)配置exe.conf檔案,裡面加一行~/exe,然後將該檔案放到/etc/ld.so.conf.d目錄下;

2)在/etc/ld.so.conf檔案中增加一行include ld.so.conf.d/exe.conf

3)執行 ldconfig命令

之後程式執行時,會自動增加在exe目錄中搜尋動態庫。

(3)設定環境變數ld_library_path。因為ldconfig的作用和這個環境變數無關,所以不用執行ldconfig。例如

export ld_library_path=/usr/local/test
系統環境變數是使用者登入系統時,由系統自動生成並設定的一組變數。所有的程序、指令碼都可以引用這些變數,因此環境變數的值通常與系統息息相關,下面介紹常見的環境變數。

(1)家目錄位置變數home

home變數用於儲存當前登入使用者的家目錄位置,這個變數的值是由系統使用者檔案/etc/passwd中的使用者家目錄字段定義的

(2)系統語言變數lang

lang變數用於儲存系統當前使用的語言,如果要臨時修改當前系統使用的語言,通常可以通過修改該變數的值來實現。

臨時修改系統語言可以重新指定此變數的值:

#修改環境變數lang的值為zh_cn.utf-8

#zh_cn.utf-8表示簡體中文

lang=zh_cn.utf-8

(3)互動程式變數shell

shell變數用於儲存使用者當前使用的shell。可以通過檢視該變數值的方法,快速檢視當前使用的shell:

#快速檢視當前使用者使用的shell

echo

$shell

#/bin/bash

(4)命令搜尋路徑變數path

path變數用於儲存當前使用者使用的命令搜尋路徑。當使用者輸入命令時,系統會嘗試在該變數儲存的目錄中查詢命令檔案。

echo

$path

set

envecho

$path

(1)路徑寫法:
#可執行檔案(一般在資料夾bin內): 

export path=/usr/local/cuda-8.0/bin:$path

#庫檔案(一般在資料夾lib內 .so):

export ld_library_path=/home/opencv2.4.9/lib:$ld_library_path

#pkg_config_path

export pkg_config_path=/test/:$pkg_config_path

或者

#將mplayer的程式目錄儲存到環境變數path

path=

$path:/usr/local/mplayer/bin

#使用export將path變數定義為全域性變數

export path

(2)臨時設定:

安裝乙個軟體的時候在終端敲

export path=/usr/local/cuda-8.0/bin:$path
(3)當前使用者的全域性設定:
sudo gedit ~/.bashrc

export path=/home/public/software_install/protobuf-3.1.0/bin:$path

export ld_library_path=/home/public/software_install/protobuf-3.1.0/lib:$ld_library_path

source ~/.bashrc

(4)所有使用者的全域性設定
sudo gedit ~/.bashrc

export path=/home/public/software_install/protobuf-3.1.0/bin:$path

export ld_library_path=/home/public/software_install/protobuf-3.1.0/lib:$ld_library_path

// 重啟或者source /etc/profile 聽說最好重啟比較好

(5)相關重要配置檔案

在linux系統中,使用者環境變數的定義工作主要是在以下檔案中完成的。

/etc/profile:全域性使用者配置檔案。如果修改了此檔案中的設定,修改的設定將會影響系統中的所有使用者。

~/.bash_profile:使用者個人配置檔案。如果修改了此檔案中的設定,修改的設定只會影響單個使用者。

/etc/bashrc:全域性環境變數配置檔案。此檔案中定義了所有使用者的環境變數。

~/.bashrc:個人環境變數配置檔案。此檔案中定義了使用者的環境變數。

Linux編譯鏈結環境變數

1.ld會去找gcc命令中的引數 l 2.再找gcc的環境變數library path 3.再找內定目錄 lib usr lib usr local lib 這是當初compile gcc時寫在程式內的 動態鏈結時 執行時搜尋路徑順序 1.編譯目標 時指定的動態庫搜尋路徑 2.環境變數ld libr...

靜態鏈結和動態鏈結

靜態載入dll dll工程b 專案屬性 配置屬性 常規 配置型別 動態庫 dll 在宣告檔案中,宣告匯出函式 declspec dllexport int xx 如果是c檔案,要在c 檔案中被呼叫,註明extern c 可以 ifdef cplusplus extern c endif 呼叫dll的...

靜態鏈結和動態鏈結

1 靜態鏈結庫只包含 lib檔案 動態鏈結庫包含 lib檔案和dll檔案,靜態鏈結庫中不能再包含其他的動態鏈結庫或者靜態庫,而在動態鏈結庫中還可以再包含其他的動態或靜態鏈結庫。此外他們都會用到定義了函式和相關資料結構的.h標頭檔案,其中 h標頭檔案是編譯時必須的,lib是鏈結時需要的,dll是執行時...