對於支持共享庫的系統, 'ld'可能還會搜索擴展名不是'.a'庫.特別的,在ELF和SunOS系統上,'ld'會在搜索帶有'.a'擴展名的庫前搜索帶'.so'擴展名的庫.
-llibrary
-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified.
Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
The linker searches a standard list of directories for the library, which is actually a file named liblibrary.a. The linker then uses this file as if it had been specified precisely by name.
The directories searched include several standard system directories plus any that you specify with -L.
Normally the files found this way are library files---archive files whose members are object files. The linker handles an archive file by scanning through it for members which define symbols that have so far been referenced but not defined. But if the file that is found is an ordinary object file, it is linked in the usual fashion. The only difference between using an -l option and specifying a file name is that -l surrounds library with lib and .a and searches several directories.
14 sysfs屬性文件中的__ATTR宏定義
#define __ATTR(_name,_mode,_show,_store) { /
.attr = {.name = __stringify(_name), .mode = _mode }, /
.show = _show, /
.store = _store, /
}
15 linux虛擬終端中執行命令行的響應過程
首先是執行/bin/sh可執行文件來作爲終端命令行接收與處理的入口。以及創建新的進程來執行命令行傳入的可執行文件
/bin/sh作爲一個終端入口,本質也是一個運行着的程序,一般由內核啓動的第一個init進程來fork出子進程後啓動:
fork execve execve fork execve
init --> init --> /sbin/getty --> /bin/login --> /bin/login --> /bin/sh
16 write和read等linux中的系統調用都屬於glibc庫,內部採用SIG軟中斷方式來進入內核態後實現sys_write和sys_read等的系統調用。對於帶緩存的fwrite和fread函數,也是由glibc來實現的,源碼以_IO_new_fopen->_IO_file_open爲主,本質是構建一個FILE來表示系統調用open返回的fd。即fopen/fread本質只是對於系統調用的一層封裝而已。
而對於Android系統而言,一般使用自帶的Bionic libc庫來實現系統調用,生成libc.so/libc_bionic.a等等(前者屬於lib目錄要打包到system中去的,後者主要用於中間編譯使用,直接被打包進可執行文件)
(部分可能還需要使用的libc++.so的庫源碼位於android/external/libcxx目錄下)
系統調用在傳遞參數使,是將參數通過一組ebx/ecx/edx等參數作爲函數形參壓棧後再調用具體的系統調用sys_open函數,每個不同的系統調用處理函數,會有不同的形參個數,所以每次調用前這個形參入棧過程都是需要有SAVE_ALL這個宏來完成的。
17 Makefile多目標依賴關係與目標多依賴
obj0 obj1 : objxxx
在make處理時,如果obj依賴如obj1則執行objxxx的依賴關係,即每個目標依賴的是同一個事務,會被解析爲
obj0 : objxxx
obj1 : objxxx
其中命令行中出現的$@是依次從obj0 obj1這個目標列表中取值
obj:obj0
obj:obj1
是等價於obj:obj0 obj1
18 靜態庫lib.a的本質
靜態庫只是一堆object對象的集合,使用ar命令可以將編譯產生的.o文件打包成.a靜態庫。
生成靜態庫只有編譯,而沒有鏈接故可以不指定他所依賴的一些動態庫;而動態庫在生成的時候時既有編譯的動作也有鏈接的動作。靜態庫在被別的程序(可執行程序或是動態庫)鏈接的時候,鏈接器會將程序中使用到函數的代碼從靜態庫文件中拷貝到應用程序中的。
靜態庫生成時是沒有鏈接的,所以生成它的時候不需要指定它所依賴的外部庫;動態庫生成時是有鏈接動作的,那當然就要指定它依賴哪些外部庫了.
鏈接只在生成可執行文件和動態庫時會做ld相關的操作
19 make處理makefile的基本流序,類似gcc編譯源文件一樣
當執行make命令時,會讀取對應的makefile文件,然後按照順序進行預處理:包括include其他的makefile文件,各種變量的賦值處理,各種隱式編譯規則的生成處理,直到最後全部預處理完成纔會真正開始執行目標文件的編譯輸出。其中目標所依賴文件的編譯規則輸出可以定義在makefile的各種位置,不需要一定定義在前面目標執行規則的前面,不具有前後關聯性。
20 在Makefile文件中define自定義的函數不僅可以處理變量參數,還可以定義相關的目標依賴編譯規則:
2198 define copy-one-file
2199 $(2): $(1) | $(ACP)
2200 @echo "Copy: $$@"
2201 $$(copy-file-to-target)
2202 endef
21 linux shell輸出重定向,將命令輸出到新的文件或者設備節點
格式:
command-line1 [1-n] > file或文件操作符或設備文件
上面命令意思是:將一條命令執行結果(標準輸出,或者錯誤輸出,本來都要打印到屏幕上面的) 重定向其它輸出設備(文件,打開文件操作符,或打印機等等)1,2分別是標準輸出,0表示錯誤輸出。
其中對文件而言>>添加在文件尾部,>會清空文件後將命令輸出寫入到新的文件之中。
22 makefile中的變量申明/賦值以及取值引用
變量申明:
A := foo
變量引用$是取變量所代表的值:
B := $(A)
$(B)則爲foo
變量的嵌套
假設foo := foo.o
$($(A))=$(foo)=foo.o
foo := $(A).o則foo變量賦值爲foo.o
23 Makefile中的foreach函數
foreach 函數和別的函數非常的不一樣。因爲這個函數是用來做循環用的,Makefile中的foreach函數幾乎是仿照於Unix標準Shell (/bin/sh)中的for語句,或是C-Shell(/bin/csh)中的foreach語句而構建的。它的語法是:
$(foreach <var>,<list>,<text>)
這個函數的意思是,把參數<list>;中的單詞逐一取出放到參數<var>;所指定的變量中,然後再執行< text>;所包含的表達式。每一次<text>;會返回一個字符串,循環過程中,<text>;的所返回的每個字符串會 以空格分隔,最後當整個循環結束時,<text>;所返回的每個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。
所以,<var>;最好是一個變量名,<list>;可以是一個表達式,而<text>;中一般會使用<var>;這個參數來依次枚舉<list>;中的單詞。舉個例子:
names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的單詞會被挨個取出,並存到變量“n”中,“$(n).o”每次根據“$(n)”計算出一個值,這些值以空格分隔,最後作爲foreach函數的返回,所以$(files)的值是“a.o b.o c.o d.o”。
注意,foreach中的<var>;參數是一個臨時的局部變量,foreach函數執行完後,參數<var>;的變量將不在作用,其作用域只在
24 makefile中的sort函數遇到重複字符是隻保留一個
$(sort, a b a c )輸出爲a b c
25 Makefile中的subst和patsubst區別
兩者都有字符替換的能力,後者在匹配字符時當沒有出現通配符合%時,只有當TEXT完全匹配pattern纔會被replace中替換。而subst具備替換TEXT中部分字符的能力,patsubst在非通配%模式下不具備部分替換。
25 Makefile中的ifdef/endif宏
ifdef用來檢測當前變量是否爲空值還是已經被賦值,而不是C語言的ifdef是否存在該宏,當檢測的變量爲空值時,直接else處理
26 使用export導入環境變量時等號兩邊是不能有空格的
即export PATH=xxxx:xxxxx
否則會報錯:export `=' not a valid identifier的一般原因
27 Makefile中添加調試信息打印時一是通過自帶的info,error,warning函數來實現,二是定義target通過echo來實現
28 Makefile中的CURDIR變量值, 表示當前make執行makefile時所處的工作目錄,可通過make -C切換,默認不指定時工作目錄爲當前執行make操作時所在的目錄
當執行make -C xxx -f $(CURDIR)/Makeflie操作時,會讀入xxx所在路徑下的Makefile文件,文件名可以通過-f制定,無指定時默認讀入Makefile文件。CURDIR在讀入-C xxx時自動由make工具生成,即-C指定的目錄絕對路徑xxx所在,供當前Makefile中作爲變量來使用。
29當執行可以執行bin文件出現bin:
整個環境變量下的確無該bin可執行文件存在報command not found
bash bin: No such file or directory
一方面還可能是該文件在執行時找不到程序runtime時所需要的so動態庫,報No such file or directory的錯誤,另外就是無法定位到可執行文件elf中定義的ld-linux.so程序加載器so庫所在絕對路徑,即內核無法加載ld-linux.so來爲程序運行做準備。
在gcc中使用ld鏈接選項時,需要在選項前面加上前綴-Wl,-rpath, xxxx1 -Wl,-rpath, xxxx2
30 Linux下elf文件的動態鏈接器是ld-linux.so,區別於gcc所使用的靜態鏈接器ld. 對於可執行文件查找路徑先PATH下後當前目錄下
每個ELF格式的可執行文件都可以配備ld-linux.so,該文件在程序運行時被加載,但必須要通過可執行文件告知其絕對路徑所在,該文件是不會依賴其他庫文件。
從上一小節中發現有一個專門的節區.interp存放有動態鏈接器,但是這個節區爲什麼叫做.interp(interpeter)呢?因爲當shell解釋器或者其他父進程通過exec啓動我們的程序時,系統會先爲ld-linux創建內存映像,然後把控制權交給ld-linux,之後ld-linux負責爲可執行程序提供運行環境,負責解釋程序的運行,因此ld-linux也叫做dynamic loader(或intepreter)(關於程序的加載過程請參考資料
31 Makefile中所有以$打頭的單詞都會被解釋成Makefile中的變量。如果你需要調用shell中的變量(或者正則表達式中錨定句位$),都需要加兩個$符號($$)來表示shell的變量
PATH="/data/"
all:
echo ${PATH}
echo $$PATH
例子中的第一個${PATH}引用的是Makefile中的變量,而不是shell中的PATH環境變量,後者引用的事Shell中的PATH環境變量
32 linux shell腳本以及各種可執行文件運行環境是繼承至運行它的進程環境。
對於Linux而言,應用程序的默認工作目錄就不同了,它是默認是繼承啓動它的進程的工作目錄的,也就是說,如果進程是在其它目錄下啓動,那應用程序的工作目錄默認就在其它的目錄下。這樣的話使用相對路徑訪問文件就有很大的不確定性:我們永遠也不能保證,用戶一定是從應用程序所在的目錄啓動!
33 Makefile VPATH變量的作用:
make在查找依賴文件時先是在當前工作目錄下查找,然後再去VPATH定義的絕對路徑下去繼續查找依賴文件,最終找到依賴文件後根據是否有VPATH參與將依賴文件的絕對路徑賦值給$<變量,一般$<值爲相對當前工作目錄的路徑所在。
34 gcc -E/-S/-c
-E: 預處理輸出.i文件
-S: 編譯,輸出爲.s文件
-c: 彙編,包括預處理和編譯,將.s彙編後變爲2進制機器碼,默認輸出爲.o目標文件,無鏈接
默認不指定時都會經歷以上過程並加入鏈接操作
gcc a.c -o a.bin
gcc a.c//輸出a.out
以上兩種方式都會一次預處理/編譯/彙編/鏈接等4個步驟的操作,直到輸出可執行文件爲止。