1. C
linux下常見的C語言項目相關(guān)的文件如下圖所示。
1.1 編譯C
通常使用GCC來編譯C文件。編譯過程為源文件.c文件 -> 預(yù)編譯成.i文件 -> 編譯成匯編語言.s -> 匯編成.o文件 -> 鏈接成可執(zhí)行文件。編譯命令為gcc -參數(shù) .c -o 輸出文件名稱
- 預(yù)處理:將頭文件拷貝進(jìn).c文件內(nèi)容中,執(zhí)行預(yù)編譯命令。采用gcc -E命令
gcc -E [.c源文件] -o [輸出文件名.i]
- 編譯成匯編:將c語言代碼編譯為對應(yīng)的匯編指令。采用gcc -S命令
gcc -S [.c源文件] -o [輸出文件名.s]
- 編譯成目標(biāo)文件:二進(jìn)制文件
gcc -c [.c源文件] [.c源文件] [...] -o [文件名]
- 編譯成可執(zhí)行文件:
gcc [.c源文件] [.c源文件] [...] -o [輸出文件名]
gcc [.c源文件] [.c源文件] [...] -o [輸出文件名] -l[庫名] -L[庫所在路徑]
1.2 創(chuàng)建靜態(tài)庫
程序庫是已寫好的、供使用的可復(fù)用代碼,每個程序都要依賴很多基礎(chǔ)的底層庫。從本質(zhì)上,庫是一種可執(zhí)行代碼的二進(jìn)制形式。靜態(tài)庫可以在編譯c項目時,將引用的庫一起鏈接到可執(zhí)行文件中,可執(zhí)行文件在運(yùn)行時不再需要庫的支持,但可執(zhí)行文件會變大。
- 將庫的.c源文件編譯成.o目標(biāo)文件
gcc -c [.c] -o [自定義文件名]
gcc -c [.c] [.c] ...
- 將.o目標(biāo)文件編譯成靜態(tài)庫
ar -r [lib自定義庫名.a] [.o] [.o] ...
- 將C程序和靜態(tài)庫鏈接,編譯成可執(zhí)行文件。庫名為lib***.a的***。
gcc [.c] -o [輸出文件名] -l[庫名] -L[庫所在路徑]
1.3 創(chuàng)建動態(tài)庫
動態(tài)庫在程序編譯時不會鏈接到目標(biāo)代碼中,而是在程序運(yùn)行時才被調(diào)用,可執(zhí)行文件比靜態(tài)鏈接的可執(zhí)行文件要小。不同的程序可以共享相同的動態(tài)庫。
- 將庫的.c源文件編譯成.o目標(biāo)文件(要加入-fpic選項)
gcc -c -fpic [.c/.cpp][.c/.cpp]...
- 將.o目標(biāo)文件編譯成動態(tài)庫
gcc -shared [.o][.o]... -o [lib自定義庫名.so]
#將1和2合并為一步
gcc -fpic -shared [.c源文件] [.c源文件] [...] -o lib[庫名].so
- 將C程序和動態(tài)庫鏈接,編譯成可執(zhí)行文件。庫名為lib***.so的***。
gcc [.c/.cpp] -o [自定義可執(zhí)行文件名] -l[庫名] -L[庫路徑] -Wl,-rpath=[庫路徑]
2. C++
編譯C++的流程與編譯C幾乎一致,只不過用的時g++命令。將上述編譯.c的gcc改為g++即可編譯cpp文件。靜態(tài)庫與動態(tài)庫同理。
3. Makefile
makefile是自動化編譯的一款工具。實際中C/C++工程項目可能十分龐大,直接用手一條一條的敲gcc/g++效率極低。在makefile文件中編寫編譯流程可以簡化編譯工作。
- make 會在當(dāng)前目錄下找到一個名字叫 Makefile 或 makefile 的文件
- 如果找到,它會找文件中第一個目標(biāo)文件(target),并把這個文件作為最終的目標(biāo)文件
- 如果 target 文件不存在,或是 target 文件依賴的 .o 文件(prerequities)的文件修改時間要比 target 這個文件新,就會執(zhí)行后面所定義的命令 command 來生成 target 這個文件
- 如果 target 依賴的 .o 文件(prerequisties)也存在,make 會在當(dāng)前文件中找到 target 為 .o 文件的依賴性,如果找到,再根據(jù)那個規(guī)則生成 .o 文件
#makefile格式
targets : prerequisties
[tab鍵]command
targets為生成的目標(biāo)文件;
prerequisties為為了生成targets目標(biāo)而所需的依賴目標(biāo)文件;
conmmand為需要運(yùn)行的命令
為了避免 target 和 Makefile 同級目錄下 文件/文件夾 重名的這種情況,我們可以使用一個特殊的標(biāo)記 .PHONY 來顯式地指明一個目標(biāo)是 “偽目標(biāo)”,如下例中的clean
.PHONY : clean
3.1 變量
- 變量定義用:=
cpp := src/main.cpp
obj := objs/main.o
- 使用變量()或{}
cpp := src/main.cpp
obj := objs/main.o
$(obj) : ${cpp} #cpp中的字符串代表的依賴文件,obj為生成的目標(biāo)文件
@g++ -c $(cpp) -o $(obj)
#等價于g++ -c src/main.cpp -o objs/main.o
compile : $(obj) #compile為偽目標(biāo),可執(zhí)行make compile命令
- 預(yù)定義變量:
$@: 目標(biāo)(target)的完整名稱
$<: 第一個依賴文件(prerequisties)的名稱
$^: 所有的依賴文件(prerequisties),以空格分開,不包含重復(fù)的依賴文件
cpp := src/main.cpp
obj := objs/main.o
$(obj) : ${cpp}
@g++ -c $< -o $@
#等價于g++ -c src/main.cpp -o objs/main.o
@echo $^
#執(zhí)行shell命令echo,打印出cpp的內(nèi)容
compile : $(obj)
.PHONY : compile
- 特殊符號:\為續(xù)行符,*通配符(匹配任意字符串,可用與目錄名和文件名中),%通配符(匹配任意字符串,并將匹配到的字符串作為變量使用)
3.2 常用函數(shù)
函數(shù)執(zhí)行格式通常為$(fn, arguments) or ${fn, arguments}
- shell:調(diào)用shell命令,返回shell命令執(zhí)行結(jié)果,使用格式為
$(shell <command> <arguments>)
# shell 指令,src 文件夾下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp")
# shell 指令, 獲取計算機(jī)架構(gòu)
HOST_ARCH := $(shell uname -m)
- subst:把字串 <text> 中的 <from> 字符串替換成 <to>,使用格式為
$(subst <from>,<to>,<text>)
cpp_srcs := $(shell find src -name "*.cpp")
cpp_objs := $(subst src/,objs/,$(cpp_objs))
- patsubst:從 text 中取出 patttern(其中%為通配符), 替換成 replacement,使用格式為 $(patsubst <pattern>,<replacement>,<text>)
cpp_srcs := $(shell find src -name "*.cpp") #shell指令,src文件夾下找到.cpp文件
cpp_objs := $(patsubst %.cpp,%.o,$(cpp_srcs)) #cpp_srcs變量下cpp文件替換成 .o文件
- foreach:把字串<list>中的元素逐一取出來,執(zhí)行<text>包含的表達(dá)式,使用格式為 $(foreach <var>,<list>,<text>)
library_paths := /lib \
/usr/local/lib64
#每一個元素前面加上-I
I_flag := $(foreach item,$(library_paths),-I$(item))
#等價于
I_flag := $(include_paths:%=-I%)
- dir:從文件路徑+文件名字符串序列中取出目錄部分,使用格式為
$(dir <names…>)
$(dir src/foo.c hacks) # 返回值是“src/ ./”。
- notdir:與dir函數(shù)相反,去除目錄部分,只保留文件名
#嵌套使用,先用shell中的find命令尋找lib開頭的文件,然后去掉這些文件的目錄前綴
libs := $(notdir $(shell find /usr/lib -name lib*))
- filter:從字符串序列中,過濾出滿足條件的
libs := $(notdir $(shell find /usr/lib -name lib*))
a_libs := $(filter %.a,$(libs)) #過濾出靜態(tài)庫
so_libs := $(filter %.so,$(libs)) #過濾出動態(tài)庫
- basename:去掉文件名后綴
libs := $(notdir $(shell find /usr/lib -name lib*))
#去掉后綴和lib前綴,得到庫名
a_libs := $(subst lib,,$(basename $(filter %.a,$(libs))))
so_libs := $(subst lib,,$(basename $(filter %.so,$(libs))))
- filter-out:去除不要的字符串
objs := objs/add.o objs/minus.o objs/main.o
cpp_objs := $(filter-out objs/main.o, $(objs))
3.3 makefile編譯文件
編譯選項:
-m64: 指定編譯為 64 位應(yīng)用程序
-std=: 指定編譯標(biāo)準(zhǔn),例如:-std=c++11、-std=c++14
-g: 包含調(diào)試信息
-w: 不顯示警告
-O: 優(yōu)化等級,通常使用:-O3
-I: 加在頭文件路徑前
fPIC: (Position-Independent Code), 產(chǎn)生的沒有絕對地址,全部使用相對地址,代碼可以被加載到內(nèi)存的任意位置,且可以正確的執(zhí)行。這正是共享庫所要求的,共享庫被加載時,在內(nèi)存的位置不是固定的文章來源:http://www.zghlxwxcb.cn/news/detail-776537.html
鏈接選項:
-l: 加在庫名前面
-L: 加在庫路徑前面
-Wl,<選項>: 將逗號分隔的 <選項> 傳遞給鏈接器
-rpath=: “運(yùn)行” 的時候,去找的目錄。運(yùn)行的時候,要找 .so 文件,會從這個選項里指定的地方去找文章來源地址http://www.zghlxwxcb.cn/news/detail-776537.html
cpp_srcs := $(shell find src -name *.cpp)
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))
include_dirs :=/home/include
I_options := $(include_dirs:%=-I%)
compile_options := -g -O3 -w $(I_options)
lib_dirs := /home/lib #庫路徑
link_libs := xxx #庫名
L_options := $(lib_dirs:%=-L%)
l_options := $(link_libs:%=-l%)
link_options := $(l_options) $(L_options) $(I_options)
#每個.cpp生成一個對應(yīng)的目標(biāo)文件
objs/%.o : src/%.cpp
#創(chuàng)建文件夾,@表示make的時候不打印make信息
@mkdir -p $(dir $@)
@g++ -c $^ -o $@ $(compile_options)
workspace/exec : $(cpp_objs)
@mkdir workspace/exec
@g++ $^ -o $@ $(link_options)
# 輸入make run即可生成run偽目標(biāo)
run : workspace
@./$<
# 輸入make clean即可生成clean偽目標(biāo)
clean :
@rm -rf objs workspace/exec
debug :
@echo $(as_files)
.PHONY : debug run clean
到了這里,關(guān)于Makefile——Linux下C/C++編譯方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!