Linux編程基礎——Makefile


前面我們已經介紹過了如何通過gcc編譯代碼生成文件,但是,當項目較多的時候,往往則需要一個自動化的編譯工具輔助我們完成這項操作。像Windows那樣通過Ctrl+F5即可一鍵完成項目所有編譯工作。

Makefile語法基礎

在Linux下,自動化編譯工具是通過make命令來完成的(一些工具廠商也提供了它們自己的make命令,如gmake等),make命令的基本格式如下:

    make [-f makefile] [label]

它可以通過-f參數指定輸入文件,當省略-f參數時,默認輸入文件名為Makefile,由於我們通常不用這個-f參數,往往就用默認的Makefile文件名。

Makefile是一個文本文件,它是基於一定的語法規則的,它的基本執行規則定義如下:

    target : [prerequisites]
        command

  • target    標簽,用於標志當前構建的規則,它也可以是文件。
  • prerequisites    依賴項,在構建該標簽的時候先執行的規則
  • command make需要執行的命令。(任意的Shell命令)

注意:Makefile的target是頂格寫的,而Command需要加一個Tab鍵。我這里為了排版看起來舒服點,每一行都多加了一個Tab鍵,如果要使用本文的Makefile示例,請去掉各行的第一個Tab鍵,否則make的時候報錯

例如,我們編寫一個簡單的Makefile:

    clean:
        @echo "clean"
    all:
        @echo "all"

當我們直接執行make命令的時候,輸出如下:

    tianfang > make
    clean
    tianfang > make all
    all
    tianfang > make clean
    clean

從中我們可以看到:默認情況下構建第一個標簽。可以通過在命令行參數中通過參數構建指定標簽

然后我們再來看看依賴性是如何工作的,這次我們修改一下Makefile,讓all標簽依賴於clean標簽:

    clean :
        @echo "clean"
    all : clean
        @echo "all"

再次執行make all的時候,發現會先執行clean標簽:

tianfang > make all
clean
all

用Makefile來構建項目

通過對Makefile的語法有一個簡單的了解后,下面就可以用Makefile簡化我們的構建操作了。還是針對前面的那個stack的例子吧,首先我們來實現一個最簡單的例子:

all :
gcc -o run main.c stack.c

這樣直接通過make命令就可以實現對gcc -o run main.c stack.c整條命令的執行了。

更加一步,我們想實現增量編譯,則要實現如下規則:

  1. 如果這個工程沒有編譯過,那么我們的所有C文件都要編譯並被鏈接。
  2. 如果這個工程的某幾個C文件被修改,那么我們只編譯被修改的C文件,並鏈接目標程序。

這個時候就需要前面的依賴性出馬了:

    run : stack.o main.o
        gcc -o run main.o stack.o

    stack.o : stack.c
        gcc -c stack.c

    main.o : main.c
        gcc -c main.c

這里的target都是文件,run默認依賴於stack.o和main.o,因此,當構建run的時候,就會先構建stack.o和main.o,輸出方式如下:

    tianfang > make
    gcc -c stack.c
    gcc -c main.c
    gcc -o run main.o stack.o

當我們只改了其中某個文件的時候,例如stack.c,這是由於main.c沒有變化,因此不會重新編譯main.o,只會重新構建stack.o和run,從而實現我們的增量編譯的目的。(這個其實才是make比shell或腳本語言編寫的批處理方式要強大的地方)

    tianfang > make
    gcc -c stack.c
    gcc -o run main.o stack.o

通過自動推導改進Makefile

通過上面的例子可以看到,雖然我們可以實現增量編譯,但是整個Makefile過程是非常復雜的,需要對每個.o文件編寫編譯腳本。如果項目文件較多,並且有增刪的話,則編寫Makefile文件非常麻煩。

為了改進這個問題,makefile提供了一個自動推導的功能,通過它可以簡化我們的編寫過程。例如,前面的例子可以簡化如下:

    CC = gcc
    objs = stack.o main.o

    run : $(objs)
        $(CC) -o run $(objs)

這里我們引入了兩個變量,第一個行的CC制定了編譯器為gcc(如果不指定則是默認的cc),第二行制定了我們的obj文件。

這樣,只需要執行make命令即可生產我們的程序:

    tianfang > make
    gcc -c -o stack.o stack.c
    gcc -c -o main.o main.c
    gcc -o run stack.o main.o

可可以看到,make命令會自動推導出如何根編出.o文件來。如果我們的項目文件變化了,只需要改objs變量即可,非常方便。

不過,有的時候我們可能覺得這中自動推導的方式不夠用,需要手動控制編譯選項,這個時候我們可以自己指定推導規則:

    CC = gcc
    objs = stack.o main.o

    run : $(objs)
        $(CC) -o run $(objs)


    $(objs): %.o: %.c
        $(CC) -c -g $< -o $@

Makefile的功能非常強大,對應的語法也是非常復雜的,由於網上已經有人寫得很詳細了,因此我這里並不打算系統的介紹Makefile的各種規則,如果想進一步的了解,可以參考跟我一起寫 Makefile這篇文章。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM