目錄
四、make工具使用(makefile)
1、Makefile
人們通常利用 make 工具來自動完成編譯工作。這些工作包括:如果僅修改了某幾個源文件,則只重新編譯這幾個源文件;如果某個頭文件被修改了,則重新編譯所有包含該頭文件的源文件。利用這種自動編譯可大大簡化開發工作,避免不必要的重新編譯。
make 工具通過一個稱爲 makefile 的文件來完成並自動維護編譯工作。makefile 需要按照某種語法進行編寫,其中說明了如何編譯各個源文件並連接生成可執行文件,並定義了源文件之間的依賴關係。當修改了其中某個源文件時,如果其他源文件依賴於該文件,則也要重新編譯所有依賴該文件的源文件。 會不會寫makefile,從一個側面說明了一個人是否具備完成大型工程的能力。
2、Makefile基本規則
taget... : dependencies...
command
...
-
target(目標): 程序產生的文件,如可執行文件和目標文件;目標也可以是要執行的動作,如 " clean"。
-
dependencies(依賴):是用來產生目標的輸入文件,一個目標通常依賴於多個文件。
-
command(命令):是make執行的動作,一個可以有多個命令,每個佔一行。注意:每個命令行的起始字符必須爲TAB字符!
如果dependencies中有一個或多個文件更新的話,command就要執行,這就是Makefile最核心的內容
3、最簡單的Makefile例子
# 源文件:main.c add.c add.h sub.c sub.h
main:main.o add.o sub.o
gcc main.o add.o sub.o -o main
main.o:main.c add.h sub.h
gcc -c main.c -o main.o
add.o:add.c add.h
gcc -c add.c -o add.o
sub.o:sub.c sub.h
gcc -c sub.c -o sub.o
clean:
rm -f main main.o add.o sub.o
4、make是如何工作的
1、make會在當前目錄下找名字叫“Makefile”或“makefile”
2、如果找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到“main”這個文件,並把這個文件作爲最終的目標文件。
3、如果main文件不存在,或是main所依賴的後面的 .o 文件的文件修改時間要比main這個文件新,那麼,他就會執行後面所定義的命令來生成main這個文件。
4、如果main所依賴的.o文件也存在,那麼make會在當前文件中找目標爲.o文件的依賴性,如果找到則再根據那一個規則生成.o文件。
5、當然,你的C文件和H文件是存在的啦,於是make會生成 .o 文件,然後再用 .o 文件make的終極任務,也就是執行文件main了。
5、Makefile使用僞目標
常見的僞目標 .PHONY
-
all: target1 target2
-
target1 :
執行make all
-
install
執行make install
-
clean
執行make clean
# 源文件:main.c add.c add.h sub.c sub.h
main:main.o add.o sub.o
gcc main.o add.o sub.o -o main
main.o:main.c add.h sub.h
gcc -c main.c -o main.o
add.o:add.c add.h
gcc -c add.c -o add.o
sub.o:sub.c sub.h
gcc -c sub.c -o suntract.o
.PHONY:clean
clean:
rm -f main main.o add.o sub.o
6、makefile中使用變量
objects=main.o add.o sub.o
CC=gcc
main:$(objects)
$(CC) $(objects) -o main
main.o:main.c add.h sub.h
$(CC) -c main.c -o main.o
add.o:add.c add.h
$(CC) -c add.c -o add.o
sub.o:sub.c sub.h
$(CC) -c sub.c -o sub.o
.PHONT:clean
clean:
rm -f main main.o add.o sub.o
7、make自動推導
- GNU的make很強大,它可以自動推導文件以及文件依賴關係後面的命令,於是我們就沒必要去在每一個[.o]文件後都寫上類似的命令,因爲,我們的make會自動識別,並自己推導命令。
- 只要make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關係中,如果make找到一個whatever.o,那麼 whatever.c,就會是whatever.o的依賴文件。並且 gcc -c whatever.c 也會被推導出來
objects=main.o add.o sub.o
main:$(objects)
gcc $(objects) -o main
main.o:add.h sub.h
add.o:add.h
sub.o:sub.h
clean:
rm -f main main.o add.o sub.o
objects=main.o add.o sub.o
main:$(objects)
gcc $(objects) -o main
$(objects): #甚至這行不要也可以
.PHONY:clean
clean:
rm -f *.o main
8、Makefile中常見函數
- wildcard 函數
- 當前目錄下匹配模式的文件。
- 例如:src=$(wildcard *.c)
- notdir 函數
- 去除路徑
- 例如:$(notdir $src)
- patsubst 函數
- 模式匹配替換
- 例如:src)
- 等價於$(src:.c=.o)
- shell函數
- 執行shell命令
- 例如:$(shell ls -d */)
- 例如:$(shell find -name ‘*.c’)
選項名 | 作用 |
---|---|
$@ | 規則的目標文件名 |
$< | 規則的第一個依賴文件名 |
$^ | 規則的所有依賴文件列表 |
ELF=main
CC=gcc
src=$(wildcard *.c)
objects=$(src:.c=.o)
$(ELF):$(objects)
$(CC) $^ -o $@
$(objects):
clean:
rm -f $(objects) $(ELF)
9、多級目錄Makefile
ELF=main
CC=gcc
src=$(shell find -name '*.c')
objects=$(src:.c=.o)
$(ELF):$(objects)
$(objects):
clean:
rm -f $(objects) $(ELF)
10、最終Makefile(通用) – C/C++版本
ELF=main
CC=gcc
CPPFLAGS= #C++語言編譯器參數 例如:-g -Wall
LDFLAGS= #連接器參數 例如:-lpthread -lrt -lsqlite3
SRC=$(shell find -name '*.c')
OBJECT = $(SRC:.c=.o)
$(ELF):$(OBJECT)
$(CC) $(CPPFLAGS) $(OBJECT) -o $(ELF) $(LDFLAGS)
$(OBJECT):
clean:
rm -f $(OBJECT) $(ELF)
我在項目中用的makefile(C++版本) 如下
ELF=main
CC=g++
CPPFLAGS=-g -Wall
LDFLAGS=-lpthread -lrt -lsqlite3
SRC=$(shell find -name '*.cpp')
OBJECT = $(SRC:.cpp=.o)
$(ELF):$(OBJECT)
$(CC) $(CPPFLAGS) $(OBJECT) -o $(ELF) $(LDFLAGS)
$(OBJECT):
clean:
rm -f $(OBJECT) $(ELF)
參數 | 描述 |
---|---|
-g | 生成供 gdb 使用的調試信息。 |
-Wall | 編譯後顯示所有警告 |
-lpthread | 通過pthreads庫加入對多線程的支持,pthread是POSIX指定的標準線程庫. |
-lrt | 一般含有#include<time.h>頭文件的代碼,編譯的時候需要加上-lrt |
-lsqlite3 | sqlite3數據庫 |
專欄 《linux網絡編程》 將持續更新中…
從linux 零基礎 到 高併發服務器架構
如果我的文章能夠幫到您,可以點個贊!
您的每次 點贊、關注、收藏 都是對我最大的鼓勵!