簡簡單單學會寫makefile

一. 題外話

1.1 c/cc編譯流程

main.cpp 爲例:html

編譯過程

1.2 gcc編譯參數( 部分)

除了前面的 -E -S -c 之外node

  • -o 指定輸出的文件名;
  • -Wall 啓用全部警告;
  • -w 不產生任何警告;
  • -g 生成調試信息;
  • -I 指定頭文件路徑;
  • -l 連接共享庫,小寫的 l
  • -L 指定庫文件路徑,大寫的 L
  • -D 定義編譯時的宏;
  • -Werror 將全部的警告轉換成錯誤信息;
  • -ansi 只支持 ANSI 標準的 C 語法;
  • -fexec-charset=GBK bin 文件爲 GBK 編碼。

全部的參數可見 Option Summarylinux

1.3 靜態庫和動態庫

windows 下後綴名 .lib (靜態庫), .dll (動態庫)程序員

linux 下後綴名 .a (靜態庫), .so (動態庫)web

只介紹 linux 下的庫文件製做編程

1.3.1 靜態庫製做

命名

"lib[your_library_name].a" ,中間是靜態庫名字。windows

建立
  • 先編譯成目標文件
    • g++ -c main.cpp
  • 經過 ar 工具將目標文件打包成 .a 靜態庫文件
    • **ar -crv libstaticmain.a main.o **

nm 可查看靜態庫內容。bash

1.3.2 動態庫製做

命名

"lib[your_library_name].so" ,中間是靜態庫名字。app

建立
  • 建立與地址無關的編譯程序
    • g++ -fPIC -c main.c
  • 打包爲動態庫(共享庫)
    • gcc -shared -o libdymain.so main.o

靜態庫使用和動態庫是同樣的,可是執行的時候找不到動態庫。svg

解決辦法:

  • 拷貝到系統的庫路徑下,不推薦;
  • 修改 LD_LIBRARY_PATH 環境變量,將庫所在的路徑添加到環境變量中;
  • 添加庫路徑到 /etc/ld.so.conf ,運行 sudo ldconfig -v ( -v 可加可不加 ),該命令會重建 /etc/ld.so.cache 文件。

詳細解釋能夠參考 C++靜態庫與動態庫

二. makefile格式

<target> : <prerequisites> 
[tab]  <commands>

target 目標, prerequisites 條件, commands 命令 。

目標不能省略,條件和命令均可以省略。

2.1 目標

目標一般是文件名,代表 make 要構建的對象。目標能夠有多個,中間用空格分開。

爲了防止目標和文件名衝突,產生了僞目標( phony target )

好比:

clean:
	rm -r *.o

若是當前路徑下有個叫 clean 的文件,那麼使用 make clean 就沒法生效了。

這時添加僞目標便可解決。

.PHONY : clean

僞目標能夠有多個,中間用空格隔開。

make 沒有指定目標,默認執行第一個。

2.2 條件

前置條件一般是一組文件名,之間用空格分隔。它指定了"目標"是否從新構建的判斷標準:只要有一個前置文件不存在,或者有過更新(前置文件的 last-modification 時間戳比目標的時間戳新),"目標"就須要從新構建。

2.3 命令

命令( commands )表示如何更新目標文件,由一行或多行的Shell命令組成。它是構建"目標"的具體指令,它的運行結果一般就是生成目標文件。

三. 兩種經常使用的makefile書寫方式

3.1 編譯多文件

all : app

cc = g++
include = ../Include

.PHONY : clean all

src = $(wildcard *.cc)
obj = $(patsubst %.cc, %.o, $(src))

app : $(obj)
	$(cc) -o app -I $(include) $(obj)

%.o : %.cc
	$(cc) -c $< -I $(include) -o $@

clean:
	rm -f *.o
	rm -f app

這裏的 wildcardmakefile 的內置函數,找出全部的 .cc 文件,賦值給變量 src

patsubst 函數用於模式匹配的替換,它須要 3 個參數:第一個是一個須要匹配的式樣,第二個表示用什麼來替換它,第三個是一個須要被處理的由空格分隔的字列。

%.o : %.cc 用到了 makefile 的模式匹配

更多能夠參考 8 Functions for Transforming Text

$<$@makefile 的自動變量:

  • $@
    • $@指代當前目標,就是Make命令當前構建的那個目標。
  • $<
    • $< 指代第一個前置條件。
  • $?
    • $? 指代比目標更新的全部前置條件,之間以空格分隔。
  • $^
    • $^ 指代全部前置條件,之間以空格分隔。
  • $*
    • $* 指代匹配符 % 匹配的部分。

更多能夠參考 10.5.3 Automatic Variables

3.2 生成多個可執行文件

all : hello world

cc = g++
include = ../Include

.PHONY : all clean

hello : hello.o
	$(cc) -o hello -I $(include) hello.o

world : world.o
	$(cc) -o world -I $(include) world.o

hello.o : hello.cc
	$(cc) -c hello.cc -I $(include)

world.o : world.cc
	$(cc) -c world.cc -I $(include)

clean :
	rm -f *.o
	rm -f hello world

來個更高級點的版本:

.PHONY : all clean

cc = g++
include = ../Include

src = $(wildcard *.cc)
obj = $(patsubst %.cc, %, $(src))

all : $(obj)

% : %.cc
	gcc -o $@ $^ -g

clean:
	rm -rf $(obj)

更詳細可參考 Make 命令教程

總結

學會 makefile 對之後的編程仍是有很大幫助的,能夠大大提升本身編寫代碼的效率。

Linux 環境下的程序員若是不會使用GNU make來構建和管理本身的工程,應該不能算是一個合格的專業程序員,至少不能稱得上是 Unix程序員。

詩情畫意

青玉案·版本二
賀鑄
凌波不過橫塘路,但目送,芳塵去。
錦瑟華年誰與度?月橋花院,鎖窗朱戶,只有春知處。
碧雲冉冉蘅(héng)皋(gāo)暮,彩筆新題斷腸句。
試問閒情都幾許?一川菸草,滿城風絮,梅子黃時雨。
青玉案·版本一
賀鑄
凌波不過橫塘路,但目送,芳塵去。
錦瑟華年誰與度?月臺花榭,鎖窗朱戶,只有春知處。
碧雲冉冉蘅皋暮,彩筆新題斷腸句。
試問閒愁都幾許?一川菸草,滿城風絮,梅子黃時雨。