close

本篇用來記錄Makefile的一些重點筆記,不是教學只有來快速查閱筆記能快速看懂別人的Makefile

#----------------------------------------------------
Makefile的基本組成:

target1: dependencies 
<TAB>command;
target2: dependencies 
<TAB>command;
clean:
<TAB>rm -rf *.o  
#--------------------------------------------------------------
一個簡單的範例:
 
由原始資料:
     gcc main.c foo.c clean.c -I /usr/foo/include -lpthread -L /usr/foo/lib -O3 -ansi -o main
變成Makefile撰寫
 
CC = gcc                            #欲使用的C compiler
CFLAGS = -O3 -ansi         #欲使用的參數
INC = -/usr/foo/include   #include headers的位置
LIB = -/usr/foo/lib            #include libraries的位置
       
main: main.o foo1.o                    
    ${CC} main.o foo1.${CFLAGS} ${INC} ${LIB} -o main
main.o: main.c target.h                    
    ${CC} main.${CFLAGS} ${INC} ${LIB} -lpthread -c  
foo1.o: foo1.c target.h                    
    ${CC} foo1.${CFLAGS} ${INC} ${LIB} -c        
clean:                             
    @rm -rf *.o
#--------------------------------------------------------
如何定義變數 
 
= 是最基本的賦值
:= 會覆蓋變數之前的值
?= 變數為空時才給值,不然則維持之前的值
+= 將值附加到變數的後面

#---------------------------------------------

自動化變數

$@  工作目標檔名
$<    第一個必要條件的檔名.
$^    所有必要條件的檔名, 並以空格隔開這些檔名. (這份清單已經拿掉重複的檔名)
$*    工作目標的主檔名.

#--------------------------------------------
萬用字元(wildcard)

makefile 中所用的萬用字元是 % ,代表所有可能的字串,前後可以接指定的字串來表示某些固定樣式的字串。例如%.c 表示結尾是 .c 的所有字串。
 
#-------------------------------------
內建變數和規則(Implicit Variables and Rules)
 
AR = ar
AS = as
CC = cc
CXX = g++
RM = rm -f
ARFLAGS = rv
CFLAGS =
CXXFLAGS =
 
命令的變數
#-----------------------------------------
• AR 函式庫打包程式。預設命令是“ar”。
• AS 組合語言編譯程序。預設命令是“as”。
• CC C語言編譯程序。預設命令是“cc”。
• CXX C++語言編譯程序。預設命令是“g++”。
• CO 從 RCS檔中擴充檔程式。預設命令是“co”。
• CPP C程式的預處理器(輸出是標準輸出設備)。預設命令是“$(CC) –E”。
• FC Fortran 和 Ratfor 的編譯器和預處理程式。預設命令是“f77”。
• GET 從SCCS檔中擴充檔的程式。預設命令是“get”。
• LEX Lex方法分析器程式(針對於C或Ratfor)。預設命令是“lex”。
• PC Pascal語言編譯程序。預設命令是“pc”。
• YACC Yacc文法分析器(針對於C程式)。預設命令是“yacc”。
• YACCR Yacc文法分析器(針對於Ratfor程式)。預設命令是“yacc –r”。
• MAKEINFO 轉換Texinfo原始檔案(.texi)到Info檔程式。預設命令是“makeinfo”。
• TEX 從TeX原始檔案建立TeX DVI檔的程式。預設命令是“tex”。
• TEXI2DVI 從Texinfo原始檔案建立軍TeX DVI 檔的程式。預設命令是“texi2dvi”。
• WEAVE 轉換Web到TeX的程式。預設命令是“weave”。
• CWEAVE 轉換C Web 到 TeX的程式。預設命令是“cweave”。
• TANGLE 轉換Web到Pascal語言的程式。預設命令是“tangle”。
• CTANGLE 轉換C Web 到 C。預設命令是“ctangle”。
• RM 刪除檔命令。預設命令是“rm –f”。
 

命令參數變數

• 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是最好的選擇。

  1. 靜態函式(static libraries)
  2. 靜態函式其實就是將一系列.o檔打包起來,因此她可以直接視為一個巨大的.o檔。打造出一個靜態函式的方法很簡單:
    gcc operator.c -c
    ar crsv liboperator.a operator.o
    或者
    gcc -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的功能有所更新時,這個程式就必須重新編譯,無法享受到即時更新的優點。通常商業軟體以及嵌入式系統等功能異動較少的程式,會傾向使用靜態函式。




  3.  
  4.  
  5. 共享函式(shared libraries)
  6. 共享函式跟靜態函式的觀念剛好相反,程式在執行時必須能夠找到相依的函式,否則執行時會出現錯誤訊息。製作一個共享函式的方法也很簡單:
    gcc -shared operator.c -o liboperator.so
    或是先編譯出目的檔再進行鏈結:
    gcc -c operator.c
    gcc -shared operator.o -o liboperator.so
    產生出liboperator.so。假設這個共享函式在/usr/local/foo/lib/裡,使用共享函式進行鏈結也很容易:
    gcc 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
    這時解決的方法有四種:
    1. 把liboperator.so複製或是作一個連結到/usr/lib裡。
    2. 修改/etc/ld.so.conf,把/usr/local/foo/lib加進系統libraries的搜尋範圍內。
    3. 設定LD_LIBRARY_PATH變數,累加該路徑進來:
    4. 如果你不是系統管理員,前兩個方法根本沒辦法執行。我們只好自己加到~/.profile裡:
      export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/foo/lib
    5. 改用靜態函式進行鏈結。
    共享函式經常出現在開放原始碼的linux世界裡,由於使用所有函式皆是共享的,因此許多程式都可以重複利用既有的功能;有新功能或是bug也能簡單的替換掉該函式,所有程式都可以即時享受到這樣的改變,也是最為常見的函式型態。




  7.  
  8.  
  9. 動態函式(dynamic libraries)
  10. 動態函式跟共享函式非常類似,唯一的差別在於程式執行時期並不會去檢查該函式是否存在,而是程式執行到某功能時才進行檢查。這種動態載入的技術最常用在瀏覽器或是大型程式的外掛程式,當有需要用到這個功能時才載入進來。
    製作一個動態函式比較麻煩。
    gcc -c -fPIC operator.c
    gcc -shared operator.o -o liboperator.so
    其中的-fPIC是產生position-independent code,也可以用-fpic。詳細的用法已經超過筆者的理解範圍,撰寫呼叫動態函式的程式碼也需要傳入相關參數。關於更多dynamic libraries的用法請參考這裡
 
參考資料:

                       

 

arrow
arrow
    全站熱搜

    stanley 發表在 痞客邦 留言(0) 人氣()