本篇用來記錄Makefile的一些重點筆記,不是教學只有來快速查閱筆記能快速看懂別人的Makefile
#----------------------------------------------------
Makefile的基本組成:
:= 會覆蓋變數之前的值
?= 變數為空時才給值,不然則維持之前的值
+= 將值附加到變數的後面
#---------------------------------------------
自動化變數
$@ 工作目標檔名
$< 第一個必要條件的檔名.
$^ 所有必要條件的檔名, 並以空格隔開這些檔名. (這份清單已經拿掉重複的檔名)
$* 工作目標的主檔名.
makefile 中所用的萬用字元是 % ,代表所有可能的字串,前後可以接指定的字串來表示某些固定樣式的字串。例如%.c 表示結尾是 .c 的所有字串。
AS = as
CC = cc
CXX = g++
RM = rm -f
ARFLAGS = rv
CFLAGS =
CXXFLAGS =
命令參數變數
• ARFLAGS 函式庫打包程式AR命令的參數。預設值是“rv”
• ASFLAGS 組合語言編譯器參數。(當明顯地調用“.s”或“.S”檔案 時)
• CFLAGS C語言編譯器參數。
• CXXFLAGS C++語言編譯器參數。
• COFLAGS RCS命令參數。
• CPPFLAGS C預處理器參數。( C 和 Fortran 編譯器也會用 到)。
• FFLAGS Fortran語言編譯器參數。
• GFLAGS SCCS “get”程式參數。
• LDFLAGS 鏈結器參數。(如:“ld”)
• LFLAGS Lex文法分析器參數。
• PFLAGS Pascal語言編譯器參數。
• RFLAGS Ratfor 程式的Fortran 編譯器參數。
• YFLAGS Yacc文法分析器參數。
Makefile hacks: print the value of any variable
print-%:
@echo '$*=$($*)'
print-%:
@echo '$*=$($*)'
@echo ' origin = $(origin $*)'
@echo ' flavor = $(flavor $*)'
@echo ' value = $(value $*)
或者
在Makefile新增 print-%: ; @echo $*=$($*) then 執行 make print-變數名
#-----------------------------
引用http://maxubuntu.blogspot.tw/2010/02/makefile.html
http://changhoward.blogspot.tw/2009/02/using-gcc-to-create-static-and-shared.html
靜態、共享與動態鏈結函式庫
我們已經知道:輪子不必重複發明 -- 人家寫好的方法我們可以直接拿來用。不過很多時候,這些方法可能因為某些因素,希望提供給別人使用卻又不希望公佈原始碼,這時候編譯成libraries是最好的選擇。
- 靜態函式(static libraries)
- 靜態函式其實就是將一系列.o檔打包起來,因此她可以直接視為一個巨大的.o檔。打造出一個靜態函式的方法很簡單:
gcc operator.c -c
或者
ar crsv liboperator.a operator.ogcc -static operator.c -loperator
兩種方法皆能產生liboperator.a。假設這個靜態函式在/usr/local/foo/lib/裡,編譯時要與靜態函式作鏈結也很容易:gcc main.c /usr/local/foo/lib/liboperator.a -o main
把靜態函式當成一般的.o檔一起納入binary,也可以像這樣:gcc main.c -L /usr/local/foo/lib -loperator -o main
靜態函式將所有的功能全部打包在一起,因此binary會變得很巨大,但是執行這個程式的所有功能都已滿足,不會再有libraries相依性的問題。但是缺點在於當某些libraries的功能有所更新時,這個程式就必須重新編譯,無法享受到即時更新的優點。通常商業軟體以及嵌入式系統等功能異動較少的程式,會傾向使用靜態函式。 - 共享函式(shared libraries)
- 共享函式跟靜態函式的觀念剛好相反,程式在執行時必須能夠找到相依的函式,否則執行時會出現錯誤訊息。製作一個共享函式的方法也很簡單:
gcc -shared operator.c -o liboperator.so
或是先編譯出目的檔再進行鏈結:gcc -c operator.c
產生出liboperator.so。假設這個共享函式在/usr/local/foo/lib/裡,使用共享函式進行鏈結也很容易:
gcc -shared operator.o -o liboperator.sogcc main.c /usr/local/foo/lib/liboperator.so -o main
也可以像這樣:gcc main.c -L /usr/local/foo/lib -loperator -o main
共享函式在程式啟動時期會檢查是否存在。以一個分別鏈結了靜態函式與共享函式的binary而言,執行的結果大有差別。以靜態函式鏈結的main程式可以順利執行,但是假設系統預設尋找函式庫的路徑裡找不到liboperator.so,以共享函式鏈結的main程式則會出現錯誤訊息:
./main: error while loading shared libraries: liboperator.so: cannot open shared object file: No such file or directory
這時解決的方法有四種:- 把liboperator.so複製或是作一個連結到/usr/lib裡。
- 修改/etc/ld.so.conf,把/usr/local/foo/lib加進系統libraries的搜尋範圍內。
- 設定LD_LIBRARY_PATH變數,累加該路徑進來:
- 如果你不是系統管理員,前兩個方法根本沒辦法執行。我們只好自己加到~/.profile裡:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/foo/lib
- 改用靜態函式進行鏈結。
- 動態函式(dynamic libraries)
- 動態函式跟共享函式非常類似,唯一的差別在於程式執行時期並不會去檢查該函式是否存在,而是程式執行到某功能時才進行檢查。這種動態載入的技術最常用在瀏覽器或是大型程式的外掛程式,當有需要用到這個功能時才載入進來。
製作一個動態函式比較麻煩。gcc -c -fPIC operator.c
其中的-fPIC是產生position-independent code,也可以用-fpic。詳細的用法已經超過筆者的理解範圍,撰寫呼叫動態函式的程式碼也需要傳入相關參數。關於更多dynamic libraries的用法請參考這裡。
gcc -shared operator.o -o liboperator.so