makefile使用

linux make手冊:http://www.gnu.org/software/make/manual/make.htmlphp

一篇文章:css

假設咱們有一個程序由5個文件組成,源代碼以下:
/*main.c*/
#include "mytool1.h"
#include "mytool2.h"
int main()
{
         mytool1_print("hello mytool1!");
         mytool2_print("hello mytool2!");
        return 0;
}
  
/*mytool1.c*/
#include "mytool1.h"
#include stdio.h>
void mytool1_print(char *print_str)
{
         printf("This is mytool1 print : %s ",print_str);
}
/*mytool1.h*/
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
        void mytool1_print(char *print_str);
#endif
/*mytool2.c*/
#include "mytool2.h"
#include stdio.h>
void mytool2_print(char *print_str)
{
         printf("This is mytool2 print : %s ",print_str);
}
/*mytool2.h*/
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
        void mytool2_print(char *print_str);
#endif
    首先了解一下make和Makefile。GNU make是一個工程管理器,它能夠管理較多的文件。我所使用的RedHat
9.0的make版本爲GNU Make version
3.79.1。使用make的最大好處就是實現了「自動化編譯」。若是有一個上百個文件的代碼構成的項目,其中一個或者幾個文件進行了修改,make就能
夠自動識別更新了的文件代碼,不須要輸入冗長的命令行就能夠完成最後的編譯工做。make執行時,自動尋找Makefile(makefile)文件,然
後執行編譯工做。因此咱們須要編寫Makefile文件,這樣能夠提升實際項目的工做效率。
    在一個Makefile中一般包含下面內容:
一、須要由make工具建立的目標體(target),一般是目標文件或可執行文件。
二、要建立的目標體所依賴的文件(dependency_file)。
三、建立每一個目標體時須要運行的命令(command)。
格式以下:

target:dependency_files

TAB>command
target:規則的目標。一般是程序中間或者最後須要生成的文件名,能夠是.o文件、也能夠是最後的可執行程序的文件名。另外,目標也能夠是一個make執行的動做的名稱,如目標「clean」,這樣的目標稱爲「僞目標」。
dependency_files:規則的依賴。生成規則目標所須要的文件名列表。一般一個目標依賴於一個或者多個文件。
command:規則的命令行。是make程序全部執行的動做(任意的shell命令或者可在shell下執行的程序)。一個規則能夠有多
個命令行,每一條命令佔一行。注意:每個命令行必須以[Tab]字符開始,[Tab]字符告訴make此行是一個命令行。make按照命令完成相應的動
做。這也是書寫Makefile中容易產生,並且比較隱蔽的錯誤。命令就是在任何一個目標的依賴文件發生變化後重建目標的動做描述。一個目標能夠沒有依賴
而只有動做(指定的命令)。好比Makefile中的目標「clean」,此目標沒有依賴,只有命令。它所指定的命令用來刪除make過程產生的中間文件
(清理工做)。
在Makefile中「規則」就是描述在什麼狀況下、如何重建規則的目標文件,一般規則中包括了目標的依賴關係(目標的依賴文件)和重建目
標的命令。make執行重建目標的命令,來建立或者重建規則的目標(此目標文件也能夠是觸發這個規則的上一個規則中的依賴文件)。規則包含了目標和依賴的
關係以及更新目標所要求的命令。
Makefile中能夠包含除規則之外的部分。一個最簡單的Makefile可能只包含規則描述。規則在有些Makefile中可能看起來很是複雜,可是不管規則的書寫是多麼的複雜,它都符合規則的基本格式。
下面就能夠寫出第一個Makefile了。

main:main.o mytool1.o mytool2.o

         gcc -o main main.o mytool1.o mytool2.o

main.o:main.c mytool1.h mytool2.h

         gcc -c main.c

mytool1.o:mytool1.c mytool1.h

         gcc -c mytool1.c

mytool2.o:mytool2.c mytool2.h

         gcc -c mytool2.c


clean:

         rm -f *.o main
在shell提示符下輸入make,執行顯示:

gcc -c main.c

gcc -c mytool1.c

gcc -c mytool2.c

gcc -o main main.o mytool1.o mytool2.o
執行結果以下:

[armlinux@lqm makefile-easy]$ ./main

This is mytool1 print : hello mytool1!

This is mytool2 print : hello mytool2!
這只是最爲初級的Makefile,如今來對這個Makefile進行改進。
改進一:使用變量
通常在書寫Makefile時,各部分變量引用的格式以下:
1. make變量(Makefile中定義的或者是make的環境變量)的引用使用「$(VAR)」格式,不管「VAR」是單字符變量名仍是多字符變量名。
2. 出如今規則命令行中shell變量(通常爲執行命令過程當中的臨時變量,它不屬於Makefile變量,而是一個shell變量)引用使用shell的「$tmp」格式。
3. 對出如今命令行中的make變量一樣使用「$(CMDVAR)」 格式來引用。

OBJ=main.o mytool1.o mytool2.o


make:$(OBJ)

         gcc -o main $(OBJ)

main.o:main.c mytool1.h mytool2.h

         gcc -c main.c

mytool1.o:mytool1.c mytool1.h

         gcc -c mytool1.c

mytool2.o:mytool2.c mytool2.h

         gcc -c mytool2.c


clean:

         rm -f main $(OBJ)
改進二:使用自動推導
讓make自動推導,只要make看到一個.o文件,它就會自動的把對應的.c文件加到依賴文件中,且gcc -c .c也會被推導出來,因此Makefile就簡化了。

CC = gcc

OBJ = main.o mytool1.o mytool2.o


make: $(OBJ)

         $(CC) -o main $(OBJ)


main.o: mytool1.h mytool2.h

mytool1.o: mytool1.h

mytool2.o: mytool2.h


.PHONY: clean

clean:

         rm -f main $(OBJ)html

 

若是執行make clean出現這個錯誤:mysql

E:\Linux\gcc\example>make clean
rm -f main main.o mytool1.o mytool2.o
0 [main] rm 6296 stdio_init: couldn't make stderr distinct from stdoutlinux

我是在cmd.exe出現這個錯誤的,用cygwin 自帶的terminal執行就沒有這個錯誤了程序員


改進三:自動變量($^ $

CC = gcc

OBJ = main.o mytool1.o mytool2.o


main: $(OBJ)

         $(CC) -o $@ $^


main.o: main.c mytool1.h mytool2.h

         $(CC) -c $

mytool1.o: mytool1.c mytool1.h

         $(CC) -c $

mytool2.o: mytool2.c mytool2.h

         $(CC) -c $


.PHONY: clean

clean:

         rm -f main $(OBJ)
     這些是最爲初級的知識,如今至少能夠減小編譯時的工做量。細節方面的東西還須要在之後的工做和學習中不斷的總結,不斷的深化理解。能夠 參考GNU Make手冊,這裏講解的比較全面。
                
            

本文來自ChinaUnix博客,若是查看原文請點:http://blog.chinaunix.net/u2/81377/showart_1287410.htmlsql

 

 

轉:跟我一塊兒寫 Makefileshell

  什麼是makefile?或許不少Winodws的程序員都不知道這個東西,由於那些Windows的IDE都爲你作了這個工做,但我以爲要做一個好的和professional的程序員,makefile仍是要懂。這就好像如今有這麼多的HTML的編輯器,但若是你想成爲一個專業人士,你仍是要了解HTML的標識的含義。特別在Unix下的軟件編譯,你就不能不本身寫makefile了,會不會寫makefile,從一個側面說明了一我的是否具有完成大型工程的能力。由於,makefile關係到了整個工程的編譯規則。一個工程中的源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,makefile定義了一系列的規則來指定,哪些文件須要先編譯,哪些文件須要後編譯,哪些文件須要從新編譯,甚至於進行更復雜的功能操做,由於makefile就像一個Shell腳本同樣,其中也能夠執行操做系統的命令。makefile帶來的好處就是——「自動化編譯」,一旦寫好,只須要一個make命令,整個工程徹底自動編譯,極大的提升了軟件開發的效率。make是一個命令工具,是一個解釋makefile中指令的命令工具,通常來講,大多數的IDE都有這個命令,好比:Delphi的make,Visual C++的nmake,Linux下GNU的make。可見,makefile都成爲了一種在工程方面的編譯方法。編程

      如今講述如何寫makefile的文章比較少,這是我想寫這篇文章的緣由。固然,不一樣產商的make各不相同,也有不一樣的語法,但其本質都是在「文件依賴性」上作文章,這裏,我僅對GNU的make進行講述,個人環境是RedHat Linux 8.0,make的版本是3.80。必竟,這個make是應用最爲普遍的,也是用得最多的。並且其仍是最遵循於IEEE 1003.2-1992 標準的(POSIX.2)。ubuntu

    在這篇文檔中,將以C/C++的源碼做爲咱們基礎,因此必然涉及一些關於C/C++的編譯的知識,相關於這方面的內容,還請各位查看相關的編譯器的文檔。這裏所默認的編譯器是UNIX下的GCC和CC。

0.1 關於程序的編譯和連接

   在此,我想多說關於程序編譯的一些規範和方法,通常來講,不管是C、C++、仍是pas,首先要把源文件編譯成中間代碼文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,這個動做叫作編譯(compile)。而後再把大量的Object File合成執行文件,這個動做叫做連接(link)。   
     
       編譯時,編譯器須要的是語法的正確,函數與變量的聲明的正確。對於後者,一般是你須要告訴編譯器頭文件的所在位置(頭文件中應該只是聲明,而定義應該放在C/C++文件中),只要全部的語法正確,編譯器就能夠編譯出中間目標文件。通常來講,每一個源文件都應該對應於一箇中間目標文件(O文件或是OBJ文件)。 
       連接時,主要是連接函數和全局變量,因此,咱們可使用這些中間目標文件(O文件或是OBJ文件)來連接咱們的應用程序。連接器並無論函數所在的源文件,只管函數的中間目標文件(Object File),在大多數時候,因爲源文件太多,編譯生成的中間目標文件太多,而在連接時須要明顯地指出中間目標文件名,這對於編譯很不方便,因此,咱們要給中間目標文件打個包,在Windows下這種包叫「庫文件」(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件

      總結一下,源文件首先會生成中間目標文件,再由中間目標文件生成執行文件。在編譯時,編譯器只檢測程序語法,和函數、變量是否被聲明。若是函數未被聲明,編譯器會給出一個警告,但能夠生成Object File。而在連接程序時,連接器會在全部的Object File中找尋函數的實現,若是找不到,那到就會報連接錯誤碼(Linker Error),在VC下,這種錯誤通常是:Link 2001錯誤,意思說是說,連接器未能找到函數的實現。你須要指定函數的ObjectFile.
       
       好,言歸正傳,GNU的make有許多的內容,閒言少敘,仍是讓咱們開始吧。

1 Makefile 介紹

 

      make命令執行時,須要一個 Makefile 文件,以告訴make命令須要怎麼樣的去編譯和連接程序。

      首先,咱們用一個示例來講明Makefile的書寫規則。以便給你們一個感興認識。這個示例來源於GNU的make使用手冊,在這個示例中,咱們的工程有8個C文件,和3個頭文件,咱們要寫一個Makefile來告訴make命令如何編譯和連接這幾個文件。咱們的規則是:

          
            1.若是這個工程沒有編譯過,那麼咱們的全部C文件都要編譯並被連接。

            2.若是這個工程的某幾個C文件被修改,那麼咱們只編譯被修改的C文件,並連接目標程序。

            3.若是這個工程的頭文件被改變了,那麼咱們須要編譯引用了這幾個頭文件的C文件,並連接目標程序。

      只要咱們的Makefile寫得夠好,全部的這一切,咱們只用一個make命令就能夠完成,make命令會自動智能地根據當前的文件修改的狀況來肯定哪些文件須要重編譯,從而本身編譯所須要的文件和連接目標程序。

1.1 Makefile的規則

   在講述這個Makefile以前,仍是讓咱們先來粗略地看一看Makefile的規則。

          target... : prerequisites ...

          command

          ...

          ...
         -------------------------------------------------------------------------------

 

   target也就是一個目標文件,能夠是Object File,也能夠是執行文件。還能夠是一個標籤(Label),對於標籤這種特性,在後續的「僞目標」章節中會有敘述。

       prerequisites就是,要生成那個target所須要的文件或是目標。

       command也就是make須要執行的命令。(任意的Shell命令)

       這是一個文件的依賴關係,也就是說,target這一個或多個的目標文件依賴於prerequisites中的文件,其生成規則定義在command中。說白一點就是說,prerequisites中若是有一個以上的文件比target文件要新的話,command所定義的命令就會被執行。這就是Makefile的規則。也就是Makefile中最核心的內容。

       說到底,Makefile的東西就是這樣一點,好像個人這篇文檔也該結束了。呵呵。還不盡然,這是Makefile的主線和核心,但要寫好一個Makefile還不夠,我會之後面一點一點地結合個人工做經驗給你慢慢到來。內容還多着呢。:)

1.2 一個示例

正如前面所說的,若是一個工程有3個頭文件,和8個C文件,咱們爲了完成前面所述的那三個規則,咱們的Makefile應該是下面的這個樣子的。

   edit : main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit main.o kbd.o command.o display.o /
               insert.o search.o files.o utils.o

 

 

   反斜槓(\)是換行符的意思。這樣比較便於Makefile的易讀。咱們能夠把這個內容保存在文件爲「Makefile」或「makefile」的文件中,而後在該目錄下直接輸入命令「make」就能夠生成執行文件edit。若是要刪除執行文件和全部的中間目標文件,那麼,只要簡單地執行一下「make clean」就能夠了。

 

        在這個makefile中,目標文件(target)包含:執行文件edit和中間目標文件(*.o),依賴文件(prerequisites)就是冒號後面的那些 .c 文件和 .h文件。每個 .o 文件都有一組依賴文件,而這些 .o 文件又是執行文件 edit 的依賴文件。依賴關係的實質上就是說明了目標文件是由哪些文件生成的,換言之,目標文件是哪些文件更新的。

 

        在定義好依賴關係後,後續的那一行定義瞭如何生成目標文件的操做系統命令,必定要以一個Tab鍵做爲開頭。記住,make並無論命令是怎麼工做的,他只管執行所定義的命令。make會比較targets文件和prerequisites文件的修改日期,若是prerequisites文件的日期要比targets文件的日期要新,或者target不存在的話,那麼,make就會執行後續定義的命令。

 

        這裏要說明一點的是,clean不是一個文件,它只不過是一個動做名字,有點像C語言中的lable同樣,其冒號後什麼也沒有,那麼,make就不會自動去找文件的依賴性,也就不會自動執行其後所定義的命令。要執行其後的命令,就要在make命令後明顯得指出這個lable的名字。這樣的方法很是有用,咱們能夠在一個makefile中定義不用的編譯或是和編譯無關的命令,好比程序的打包,程序的備份,等等。

 

1.3 make是如何工做的

 

在默認的方式下,也就是咱們只輸入make命令。那麼,

 

 

 

  1.   make會在當前目錄下找名字叫「Makefile」或「makefile」的文件。
  2.   若是找到,它會找文件中的第一個目標文件(target),在上面的例子中,他會找到「edit」這個文件,並把這個文件做爲最終的目標文件。
  3.   若是edit文件不存在,或是edit所依賴的後面的 .o 文件的文件修改時間要比edit這個文件新,那麼,他就會執行後面所定義的命令來生成edit這個文件。
  4.   若是edit所依賴的.o文件也存在,那麼make會在當前文件中找目標爲.o文件的依賴性,若是找到則再根據那一個規則生成.o文件。(這有點像一個堆棧的過程)
  5.   固然,你的C文件和H文件是存在的啦,因而make會生成 .o 文件,而後再用 .o 文件聲明make的終極任務,也就是執行文件edit了。

 

 

 

    這就是整個make的依賴性,make會一層又一層地去找文件的依賴關係,直到最終編譯出第一個目標文件。在找尋的過程當中,若是出現錯誤,好比最後被依賴的文件找不到,那麼make就會直接退出,並報錯,而對於所定義的命令的錯誤,或是編譯不成功,make根本不理。make只管文件的依賴性,即,若是在我找了依賴關係以後,冒號後面的文件仍是不在,那麼對不起,我就不工做啦。

 

        經過上述分析,咱們知道,像clean這種,沒有被第一個目標文件直接或間接關聯,那麼它後面所定義的命令將不會被自動執行,不過,咱們能夠顯示要make執行。即命令——「make clean」,以此來清除全部的目標文件,以便重編譯

 

      因而在咱們編程中,若是這個工程已被編譯過了,當咱們修改了其中一個源文件,好比file.c,那麼根據咱們的依賴性,咱們的目標file.o會被重編譯(也就是在這個依性關係後面所定義的命令),因而file.o的文件也是最新的啦,因而file.o的文件修改時間要比edit要新,因此edit也會被從新連接了(詳見edit目標文件後定義的命令)。

 

而若是咱們改變了「command.h」,那麼,kdb.o、command.o和files.o都會被重編譯,而且,edit會被重連接。

 

1.4 makefile中使用變量

在上面的例子中,先讓咱們看看edit的規則:

     edit : main.o kbd.o command.o display.o \

                 insert.o search.o files.o utils.o

           cc -o edit main.o kbd.o command.o display.o \

                      insert.o search.o files.o utils.o

    咱們能夠看到[.o]文件的字符串被重複了兩次,若是咱們的工程須要加入一個新的[.o]文件,那麼咱們須要在兩個地方加(應該是三個地方,還有一個地方在clean中)。固然,咱們的makefile並不複雜,因此在兩個地方加也不累,但若是makefile變得複雜,那麼咱們就有可能會忘掉一個須要加入的地方,而致使編譯失敗。因此,爲了makefile的易維護,在makefile中咱們可使用變量。makefile的變量也就是一個字符串,理解成C語言中的宏可能會更好。

好比,咱們聲明一個變量,叫objects, OBJECTS, objs, OBJS, obj, 或是 OBJ,反正無論什麼啦,只要可以表示obj文件就好了。咱們在makefile一開始就這樣定義:

    objects = main.o kbd.o command.o display.o \

             insert.o search.o files.o utils.o

因而,咱們就能夠很方便地在咱們的makefile中以「$(objects)」的方式來使用這個變量了,因而咱們的改良版makefile就變成下面這個樣子:

   objects = main.o kbd.o command.o display.o \
             insert.osearch.o files.o utils.o 
   edit : $(objects)
           cc -o edit $(objects)
   main.o : main.c defs.h
           cc -c main.c
   kbd.o : kbd.c defs.h command.h
           cc -c kbd.c
   command.o : command.c defs.h command.h
           cc -c command.c
   display.o : display.c defs.h buffer.h
           cc -c display.c
   insert.o : insert.c defs.h buffer.h
           cc -c insert.c
   search.o : search.c defs.h buffer.h
           cc -c search.c
   files.o : files.c defs.h buffer.h command.h
           cc -c files.c
   utils.o : utils.c defs.h
           cc -c utils.c
   clean :
           rm edit $(objects)

因而若是有新的 .o 文件加入,咱們只需簡單地修改一下 objects 變量就能夠了。

關於變量更多的話題,我會在後續給你一一道來。

1.5 讓make自動推導

GNU的make很強大,它能夠自動推導文件以及文件依賴關係後面的命令,因而咱們就不必去在每個[.o]文件後都寫上相似的命令,由於,咱們的make會自動識別,並本身推導命令。

    只要make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關係中,若是make找到一個whatever.o,那麼whatever.c,就會是whatever.o的依賴文件。而且 cc -c whatever.c 也會被推導出來,因而,咱們的makefile不再用寫得這麼複雜。咱們的是新的makefile又出爐了。

   objects = main.o kbd.o command.o display.o \
             insert.o search.o files.o utils.o
 
   edit : $(objects)
           cc -o edit $(objects)
 
   main.o : defs.h
   kbd.o : defs.h command.h
   command.o : defs.h command.h
   display.o : defs.h buffer.h
   insert.o : defs.h buffer.h
   search.o : defs.h buffer.h
   files.o : defs.h buffer.h command.h
   utils.o : defs.h
 
   .PHONY : clean
   clean :
           rm edit $(objects)

這種方法,也就是make的「隱晦規則」。上面文件內容中,「.PHONY」表示,clean是個僞目標文件。

關於更爲詳細的「隱晦規則」和「僞目標文件」,我會在後續給你一一道來。

1.6 另類風格的makefile

    即然咱們的make能夠自動推導命令,那麼我看到那堆[.o]和[.h]的依賴就有點不爽,那麼多的重複的[.h],能不能把其收攏起來,好吧,沒有問題,這個對於make來講很容易,誰叫它提供了自動推導命令和文件的功能呢?來看看最新風格的makefile吧。

   objects = main.o kbd.o command.o display.o \
             insert.o search.o files.o utils.o
 
   edit : $(objects)
           cc -o edit $(objects)
 
   $(objects) : defs.h
   kbd.o command.o files.o : command.h
   display.o insert.o search.o files.o : buffer.h
 
   .PHONY : clean
   clean :
           rm edit $(objects)

這種風格,讓咱們的makefile變得很簡單,但咱們的文件依賴關係就顯得有點凌亂了。魚和熊掌不可兼得。還看你的喜愛了。我是不喜歡這種風格的,一是文件的依賴關係看不清楚,二是若是文件一多,要加入幾個新的.o文件,那就理不清楚了。

 

1.7 清空目標文件的規則

      每一個Makefile中都應該寫一個清空目標文件(.o和執行文件)的規則,這不只便於重編譯,也很利於保持文件的清潔。這是一個「修養」(呵呵,還記得個人《編程修養》嗎)。通常的風格都是:

       clean:

           rm edit $(objects)

更爲穩健的作法是:

       .PHONY : clean

       clean :

               -rm edit $(objects)

前面說過,.PHONY意思表示clean是一個「僞目標」,。而在rm命令前面加了一個小減號的意思就是,也許某些文件出現問題,但不要管,繼續作後面的事。當然,clean的規則不要放在文件的開頭,否則,這就會變成make的默認目標,相信誰也不肯意這樣。不成文的規矩是——「clean歷來都是放在文件的最後」。

上面就是一個makefile的概貌,也是makefile的基礎,下面還有不少makefile的相關細節,準備好了嗎?準備好了就來。

 

2 Makefile 總述

2.1 Makefile裏有什麼?

Makefile裏主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和註釋

 

  1. 顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令。
  2. 隱晦規則。因爲咱們的make有自動推導的功能,因此隱晦的規則可讓咱們比較粗糙地簡略地書寫Makefile,這是由make所支持的。
  3. 變量的定義。在Makefile中咱們要定義一系列的變量,變量通常都是字符串,這個有點你C語言中的宏,當Makefile被執行時,其中的變量都會被擴展到相應的引用位置上。
  4. 文件指示。其包括了三個部分,一個是在一個Makefile中引用另外一個Makefile,就像C語言中的include同樣;另外一個是指根據某些狀況指定Makefile中的有效部分,就像C語言中的預編譯#if同樣;還有就是定義一個多行的命令。有關這一部分的內容,我會在後續的部分中講述。
  5.  註釋。Makefile中只有行註釋,和UNIX的Shell腳本同樣,其註釋是用「#」字符,這個就像C/C++中的「//」同樣。若是你要在你的Makefile中使用「#」字符,能夠用反斜框進行轉義,如:「\#」。

 

最後,還值得一提的是,在Makefile中的命令,必需要以[Tab]鍵開始。

2.2Makefile的文件名

        默認的狀況下,make命令會在當前目錄下按順序找尋文件名爲「GNUmakefile」、「makefile」、「Makefile」的文件,找到了解釋這個文件。在這三個文件名中,最好使用「Makefile」這個文件名,由於,這個文件名第一個字符爲大寫,這樣有一種顯目的感受。最好不要用「GNUmakefile」,這個文件是GNU的make識別的。有另一些make只對全小寫的「makefile」文件名敏感,可是基本上來講,大多數的make都支持「makefile」和「Makefile」這兩種默認文件名。

     固然,你可使用別的文件名來書寫Makefile,好比:「Make.Linux」,「Make.Solaris」,「Make.AIX」等,若是指定特定的Makefile,你可使用make的「-f」和「--file」參數,如:make -f Make.Linux或make --file Make.AIX。

2.3 引用其它的Makefile

    在Makefile使用include關鍵字能夠把別的Makefile包含進來,這很像C語言的#include,被包含的文件會原模原樣的放在當前文件的包含位置。include的語法是:

    include<filename>filename能夠是當前操做系統Shell的文件模式(能夠保含路徑和通配符)

在include前面能夠有一些空字符,可是毫不能是[Tab]鍵開始。include和能夠用一個或多個空格隔開。舉個例子,你有這樣幾個Makefile:a.mk、b.mk、c.mk,還有一個文件叫foo.make,以及一個變量$(bar),其包含了e.mk和f.mk,那麼,下面的語句:

   include foo.make *.mk $(bar)

等價於:

   include foo.make a.mk b.mk c.mk e.mk f.mk

make命令開始時,會把找尋include所指出的其它Makefile,並把其內容安置在當前的位置。就好像C/C++的#include指令同樣。若是文件都沒有指定絕對路徑或是相對路徑的話,make會在當前目錄下首先尋找,若是當前目錄下沒有找到,那麼,make還會在下面的幾個目錄下找:

1.若是make執行時,有「-I」或「--include-dir」參數,那麼make就會在這個參數所指定的目錄下去尋找。
2.若是目錄/include(通常是:/usr/local/bin或/usr/include)存在的話,make也會去找。


      若是有文件沒有找到的話,make會生成一條警告信息,但不會立刻出現致命錯誤。它會繼續載入其它的文件,一旦完成makefile的讀取,make會再重試這些沒有找到,或是不能讀取的文件,若是仍是不行,make纔會出現一條致命信息。若是你想讓make不理那些沒法讀取的文件,而繼續執行,你能夠在include前加一個減號「-」。如:

-include<filename>

其表示,不管include過程當中出現什麼錯誤,都不要報錯繼續執行。和其它版本make兼容的相關命令是sinclude,其做用和這一個是同樣的。

2.4 環境變量 MAKEFILES

若是你的當前環境中定義了環境變量MAKEFILES,那麼,make會把這個變量中的值作一個相似於include的動做。這個變量中的值是其它的Makefile,用空格分隔。只是,它和include不一樣的是,從這個環境變中引入的Makefile的「目標」不會起做用,若是環境變量中定義的文件發現錯誤,make也會不理。

可是在這裏我仍是建議不要使用這個環境變量,由於只要這個變量一被定義,那麼當你使用make時,全部的Makefile都會受到它的影響,這毫不是你想看到的。在這裏提這個事,只是爲了告訴你們,也許有時候你的Makefile出現了怪事,那麼你能夠看看當前環境中有沒有定義這個變量。

2.5 make的工做方式

GNU的make工做時的執行步驟入下:(想來其它的make也是相似)

1.        讀入全部的Makefile。

2.        讀入被include的其它Makefile。

3.        初始化文件中的變量。

4.        推導隱晦規則,並分析全部規則。

5.        爲全部的目標文件建立依賴關係鏈。

6.        根據依賴關係,決定哪些目標要從新生成。

7.        執行生成命令。

1-5步爲第一個階段,6-7爲第二個階段。第一個階段中,若是定義的變量被使用了,那麼,make會把其展開在使用的位置。但make並不會徹底立刻展開,make使用的是拖延戰術,若是變量出如今依賴關係的規則中,那麼僅當這條依賴被決定要使用了,變量纔會在其內部展開。

固然,這個工做方式你不必定要清楚,可是知道這個方式你也會對make更爲熟悉。有了這個基礎,後續部分也就容易看懂了。

3 Makefile書寫規則

 規則包含兩個部分,一個是依賴關係,一個是生成目標的方法

在Makefile中,規則的順序是很重要的,由於,Makefile中只應該有一個最終目標,其它的目標都是被這個目標所連帶出來的,因此必定要讓make知道你的最終目標是什麼。通常來講,定義在Makefile中的目標可能會有不少,可是第一條規則中的目標將被確立爲最終的目標。若是第一條規則中的目標有不少個,那麼,第一個目標會成爲最終的目標。make所完成的也就是這個目標。

好了,仍是讓咱們來看一看如何書寫規則。

3.1 規則舉例

 foo.o: foo.c defs.h       # foo模塊

           cc -c -g foo.c

看到這個例子,各位應該不是很陌生了,前面也已說過,foo.o是咱們的目標,foo.c和defs.h是目標所依賴的源文件,而只有一個命令「cc -c -g foo.c」(以Tab鍵開頭)。這個規則告訴咱們兩件事:

1.        文件的依賴關係,foo.o依賴於foo.c和defs.h的文件,若是foo.c和defs.h的文件日期要比foo.o文件日期要新,或是foo.o不存在,那麼依賴關係發生。

2.        若是生成(或更新)foo.o文件。也就是那個cc命令,其說明了,如何生成foo.o這個文件。(固然foo.c文件include了defs.h文件)

3.2 規則的語法

     targets : prerequisites

       command

       ...

或是這樣:

     targets : prerequisites ; command

           command

           ...

targets是文件名,以空格分開,可使用通配符。通常來講,咱們的目標基本上是一個文件,但也有多是多個文件。

command是命令行,若是其不與「target:prerequisites」在一行,那麼,必須以[Tab鍵]開頭,若是和prerequisites在一行,那麼能夠用分號作爲分隔。(見上)

prerequisites也就是目標所依賴的文件(或依賴目標)。若是其中的某個文件要比目標文件要新,那麼,目標就被認爲是「過期的」,被認爲是須要重生成的。這個在前面已經講過了。

若是命令太長,你可使用反斜框(‘\’)做爲換行符。make對一行上有多少個字符沒有限制。規則告訴make兩件事,文件的依賴關係和如何成成目標文件。

通常來講,make會以UNIX的標準Shell,也就是/bin/sh來執行命令。

3.3 在規則中使用通配符

     若是咱們想定義一系列比較相似的文件,咱們很天然地就想起使用通配符。make支持三各通配符:「*」,「?」和「[...]」。這是和Unix的B-Shell是相同的。

"~"

波浪號(「~」)字符在文件名中也有比較特殊的用途。若是是「~/test」,這就表示當前用戶的$HOME目錄下的test目錄。而「~hchen/test」則表示用戶hchen的宿主目錄下的test目錄。(這些都是Unix下的小知識了,make也支持)而在Windows或是MS-DOS下,用戶沒有宿主目錄,那麼波浪號所指的目錄則根據環境變量「HOME」而定。

"*"
通配符代替了你一系列的文件,如「*.c」表示因此後綴爲c的文件。一個須要咱們注意的是,若是咱們的文件名中有通配符,如:「*」,那麼能夠用轉義字符「\」,如「\*」來表示真實的「*」字符,而不是任意長度的字符串。

好吧,仍是先來看幾個例子吧:

   clean:

        rm -f *.o

上面這個例子我不很少說了,這是操做系統Shell所支持的通配符。這是在命令中的通配符。

   print: *.c

        lpr -p $?

        touch print

上面這個例子說明了通配符也能夠在咱們的規則中,目標print依賴於全部的[.c]文件。其中的「$?」是一個自動化變量,我會在後面給你講述。

   objects = *.o

上面這個例子,表示了,通符一樣能夠用在變量中。並非說[*.o]會展開,不!objects的值就是「*.o」。Makefile中的變量其實就是C/C++中的宏。若是你要讓通配符在變量中展開,也就是讓objects的值是全部[.o]的文件名的集合,那麼,你能夠這樣:

   objects := $(wildcard *.o)

這種用法由關鍵字「wildcard」指出,關於Makefile的關鍵字,咱們將在後面討論。

3.4 文件搜尋

     在一些大的工程中,有大量的源文件,咱們一般的作法是把這許多的源文件分類,並存放在不一樣的目錄中。因此,當make須要去找尋文件的依賴關係時,你能夠在文件前加上路徑,但最好的方法是把一個路徑告訴make,讓make在自動去找。

Makefile文件中的特殊變量「VPATH」就是完成這個功能的,若是沒有指明這個變量,make只會在當前的目錄中去找尋依賴文件和目標文件。若是定義了這個變量,那麼,make就會在噹噹前目錄找不到的狀況下,到所指定的目錄中去找尋文件了

   VPATH = src:../headers

上面的的定義指定兩個目錄,「src」和「../headers」,make會按照這個順序進行搜索。目錄由「冒號」分隔。(固然,當前目錄永遠是最高優先搜索的地方)

另外一個設置文件搜索路徑的方法是使用make的「vpath」關鍵字(注意,它是全小寫的),這不是變量,這是一個make的關鍵字,這和上面提到的那個VPATH變量很相似,可是它更爲靈活。它能夠指定不一樣的文件在不一樣的搜索目錄中。這是一個很靈活的功能。它的使用方法有三種:

1.        vpath < pattern> < directories>    爲符合模式< pattern>的文件指定搜索目錄<directories>。

2.        vpath < pattern>                              清除符合模式< pattern>的文件的搜索目錄。

3.        vpath                                                 清除全部已被設置好了的文件搜索目錄。

vapth使用方法中的< pattern>須要包含「%」字符。「%」的意思是匹配零或若干字符,例如,「%.h」表示全部以「.h」結尾的文件。< pattern>指定了要搜索的文件集,而< directories>則指定了的文件集的搜索的目錄。例如:

   vpath %.h ../headers

該語句表示,要求make在「../headers」目錄下搜索全部以「.h」結尾的文件。(若是某文件在當前目錄沒有找到的話)

咱們能夠連續地使用vpath語句,以指定不一樣搜索策略。若是連續的vpath語句中出現了相同的< pattern>,或是被重複了的< pattern>,那麼,make會按照vpath語句的前後順序來執行搜索。如:

   vpath %.c foo

   vpath %   blish

   vpath %.c bar

其表示「.c」結尾的文件,先在「foo」目錄,而後是「blish」,最後是「bar」目錄。

   vpath %.c foo:bar

   vpath %   blish

而上面的語句則表示「.c」結尾的文件,先在「foo」目錄,而後是「bar」目錄,最後纔是「blish」目錄。

 

(個人:

example:

  main.c

      a--

    mytool1.h

    mytool2.h

    mytool1.c

    mytool2.c

CC=gcc
OBJ=main.o mytool1.o mytool2.o
VPATH=./a

main:$(OBJ)
    $(CC) -o main $(OBJ)
    
 

main.o: main.c mytool1.h mytool2.h
    gcc -c $^ (若是不加main.c會報錯:main.o no such file or direcotry

mytool1.o:mytool1.h

mytool2.o:mytool2.h

.PHONY:clean


clean:
    rm   -f main $(OBJ)
    

Administrator@s  /cygdrive/e/linux/gcc/example
$ make
gcc -c main.c ./a/mytool1.h ./a/mytool2.h
gcc -o main main.o mytool1.o mytool2.o

 

注意main.c 文件以下:

#include "a/mytool1.h"
#include "a/mytool2.h"

是包含a/mytool1.h,若是直接寫mytool1.h會提示找不到文件。

參考:http://blog.csdn.net/lastsweetop/article/details/5659244

http://blog.csdn.net/changli_90/article/details/7881905

 

 靜態模式

    靜態模式能夠更加容易地定義多目標的規則,讓規則變得更加的有彈性和靈活。

    <targets ...>: <target-pattern>: <prereq-patterns ...>

    <commands>

    ...

    targets定義了一系列的目標文件,能夠有通配符,是目標的一個集合。

    target-parrtern是指明瞭targets的模式,也就是目標集模式。

    prereq-parrterns是目標的依賴模式,它對target-parrtern造成的模式再進行一次依賴目標的定義。

    這樣描述這三個東西,可能還沒說清楚,仍是舉個例子來講明一下吧。若是咱們的<targets-parrtern>定義成「%.o」,意思是咱們的<targets>集合中都是以「.o」結尾的,而若是咱們的<prereq-patterns>定義成「%.c」,意思是對<target-parrtern>所造成的目標集進行二次定義,計算方法是取模式中的「%」(也就是去掉了[.o]這個結尾),併爲其加上[.c]這個結尾,造成的新集合。

    因此,「目標模式」或是「依賴模式」中都應該有「%」這個字符,若是你的文件名中有「%」那麼你可使用反斜槓「\」進行轉義,來標明真實的「%」字符。

    看一個例子:

    objects = foo.o bar.o

    all: $(objects)

    $(objects): %.o: %.c

        $(CC) -c $(CFLAGS) $< -o $@

這裏怎麼理解   $(objects): %.o: %.c ??

寫makefile,下面的依賴怎麼理解,爲何倆冒號?百度知道的一個問題:
例子
$(C_OBJS):$(P_OouDIR)/%.o:%.c
。。。。。(commands)
其中 C_OBJS變量爲帶路徑的.o文件名如 .bin/test.o,P_OouDIR爲./bin目
這就是makefile的靜態模式規則。

    1. Here is the syntax of a static pattern rule:
    2.      targets ...: target-pattern: prereq-patterns ...
    3.              recipe
    4.              ...


參見gnu makefile 手冊 section 4.11

意思就是說
$(C_OBJS) 中有不少文件,假設各類各樣的都有 (實際中確定是你本身定義的,不會亂七八糟)

看看這些文件裏面,找出匹配符合 $(P_OouDIR)/%.o的。 既然P_OouDIR爲./bin目錄,那麼就是看看那些匹配模式 ./bin/%.o,顯然,通常來講按你的定義,都會匹配的。

而後,這裏面的.o都依賴各自對應的.c

也就是說
$(C_OBJS):$(P_OouDIR)/%.o:%.c

和規則
$(P_OouDIR)/%.o:%.c
徹底是等價的,在你這裏。

可是通常性而言,並不等價,好比$(C_OBJS)還定義了其它文件,好比 ./lib/xxx.o

靜態模式規則的好處,是能精肯定義,哪一個文件,依賴哪一個文件。規定了預選範圍。

%.o:%.c 則是泛泛而談,只要匹配,就是這樣。
看這邊文章:http://blog.chinaunix.net/uid-20564848-id-218435.html

 

    上面的例子中,指明瞭咱們的目標從$object中獲取,「%.o」代表要全部以「.o」結尾的目標,也就是「foo.o bar.o」,也就是變量$object集合的模式,而依賴模式「%.c」則取模式「%.o」的「%」,也就是「foo bar」,併爲其加下「.c」的後綴,因而咱們的依賴目標就是「foo.c bar.c」;而命令中的「$<」和「$@」則是自動化變量,「$<」表示全部的依賴目標集(也就是「foo.c bar.c」),「$@」表示目標集(也就是「foo.o bar.o」)。因而,上面的規則展開後等價於下面的規則:

    foo.o : foo.c

        $(CC) -c $(CFLAGS) foo.c -o foo.o

    bar.o : bar.c

        $(CC) -c $(CFLAGS) bar.c -o bar.o

    試想,若是咱們的「%.o」有幾百個,那種咱們只要用這種很簡單的「靜態模式規則」就能夠寫完一堆規則,實在是太有效率了。「靜態模式規則」的用法很靈活,若是用得好,那會一個很強大的功能。再看一個例子:

    files = foo.elc bar.o lose.o

    $(filter %.o,$(files)): %.o: %.c

        $(CC) -c $(CFLAGS) $< -o $@

    $(filter %.elc,$(files)): %.elc: %.el

        emacs -f batch-byte-compile $<

    $(filter %.o,$(files))表示調用Makefile的filter函數,過濾「$filter」集,只要其中模式爲「%.o」的內容。

 

三、自動化變量

在上述的模式規則中,目標和依賴文件都是一系例的文件,那麼咱們如何書寫一個命令來完成從不一樣的依賴文件生成相應的目標?由於在每一次的對模式規則的解析時,都會是不一樣的目標和依賴文件。

自動化變量就是完成這個功能的。在前面,咱們已經對自動化變量有所提涉,相信你看到這裏已對它有一個感性認識了。所謂自動化變量,就是這種變量會把模式中所定義的一系列的文件自動地挨個取出,直至全部的符合模式的文件都取完了。這種自動化變量只應出如今規則的命令中。

下面是全部的自動化變量及其說明:

$@
表示規則中的目標文件集。在模式規則中,若是有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合

$%
僅當目標是函數庫文件中,表示規則中的目標成員名。例如,若是一個目標是"foo.a(bar.o)",那麼,"$%"就是"bar.o","$@"就是"foo.a"。若是目標不是函數庫文件(Unix下是[.a],Windows下是[.lib]),那麼,其值爲空。

$<
依賴目標中的第一個目標名字。如果依賴目標是以模式(即"%")定義的,那麼"$<"將是符合模式的一系列的文件集。注意,其是一個一個取出來的。

$?
全部比目標新的依賴目標的集合。以空格分隔。

$^
有的依賴目標的集合。以空格分隔。若是在依賴目標中有多個重複的,那個這個變量會去除重複的依賴目標,只保留一份。


這個變量很像"$^",也是全部依賴目標的集合。只是它不去除重複的依賴目標。

$* 
這個變量表示目標模式中"%"及其以前的部 分。若是目標是"dir/a.foo.b",而且目標的模式是"a.%.b",那麼,"$*"的值就是"dir/a.foo"。這個變量對於構造有關聯的 文件名是比較有較。若是目標中沒有模式的定義,那麼"$*"也就不能被推導出,可是,若是目標文件的後綴是make所識別的,那麼"$*"就是除了後綴的 那一部分。例如:若是目標是"foo.c",由於".c"是make所能識別的後綴名,因此,"$*"的值就是"foo"。這個特性是GNU make的,頗有可能不兼容於其它版本的make,因此,你應該儘可能避免使用"$*",除非是在隱含規則或是靜態模式中。若是目標中的後綴是make所不 能識別的,那麼"$*"就是空值。

當你但願只對更新過的依賴文件進行操做時,"$?"在顯式規則中頗有用,例如,假設有一個函數庫文件叫"lib",其由其它幾個object文件更新。那麼把object文件打包的比較有效率的Makefile規則是:

lib : foo.o bar.o lose.o win.o
ar r lib $?

在上述所列出來的自動量變量中。四個變量($@、$<、$%、$*)在擴展時只會有一個 文件,而另三個的值是一個文件列表。這七個自動化變量還能夠取得文件的目錄名或是在當前目錄下的符合模式的文件名,只須要搭配上"D"或"F"字樣。這是 GNU make中老版本的特性,在新版本中,咱們使用函數"dir"或"notdir"就能夠作到了。"D"的含義就是Directory,就是目錄,"F"的 含義就是File,就是文件。

下面是對於上面的七個變量分別加上"D"或是"F"的含義:

$(@D)
表示"$@"的目錄部分(不以斜槓做爲結尾),若是"$@"值是"dir/foo.o",那麼"$(@D)"就是"dir",而若是"$@"中沒有包含斜槓的話,其值就是"."(當前目錄)。

$(@F)
表示"$@"的文件部分,若是"$@"值是"dir/foo.o",那麼"$(@F)"就是"foo.o","$(@F)"至關於函數"$(notdir $@)"。

"$(*D)"
"$(*F)"

和上面所述的同理,也是取文件的目錄部分和文件部分。對於上面的那個例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"

"$(%D)"
"$(%F)"

分別表示了函數包文件成員的目錄部分和文件部分。這對於形同"archive(member)"形式的目標中的"member"中包含了不一樣的目錄頗有用。

"$("$(
分別表示依賴文件的目錄部分和文件部分。

"$(^D)"
"$(^F)"

分別表示全部依賴文件的目錄部分和文件部分。(無相同的)

"$( D)"
"$( F)"

分別表示全部依賴文件的目錄部分和文件部分。(能夠有相同的)

"$(?D)"
"$(?F)"

分別表示被更新的依賴文件的目錄部分和文件部分。

最後想提醒一下的是,對於"$<",爲了不產生沒必要要的麻煩,咱們最好給$後面的那個特定字符都加上圓括號,好比,"$(<)"就要比"$<"要好一些。

還得要注意的是,這些變量只使用在規則的命令中,並且通常都是"顯式規則"和"靜態模式規則"(參見前面"書寫規則"一章)。其在隱含規則中並無意義。

 一篇文章:

Linux學習筆記——例說makefile 頭文件查找路徑

0.前言
    從學習C語言開始就慢慢開始接觸makefile,查閱了不少的makefile的資料但總感受沒有真正掌握makefile,若是本身動手寫一個makefile總以爲很是吃力。因此特地藉助博客總結makefile的相關知識,經過例子說明makefile的具體用法。
 
    例說makefile分爲如下幾個部分,更多內容請參考【 例說makefile索引博文
    1.只有單個C文件   
    2.含有多個C文件    
    3.須要包括頭文件路徑
    4.增長宏定義
    5.增長系統共享庫
    6.增長自定義共享庫
    7.一個實際的例子
 
 
    【代碼倉庫】—— makefile-example
    代碼倉庫位於bitbucket,可藉助TortoiseHg(GUI工具)克隆代碼或者在網頁中直接下載zip包。
 
1.三個C文件和三個頭文件
    此處的例子稍微複雜些但更接近實際狀況。
    文件結果以下:根目錄中包含test.c makefileh和文件夾test-add和文件夾test-sub。
test.c makefile
    【test-add】test-add.c test-add.h
    【test-sub】test-sub.c test-sub.h
 
    【test.c】
[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. #include <stdio.h>  
  2. #include <test-add.h>  
  3. #include <test-sub.h>  
  4. int main(void)  
  5. {  
  6.     int a = 3;  
  7.     int b = 2;  
  8.          
  9.     printf("a=%d\n", a);  
  10.     printf("b=%d\n", b);  
  11.    
  12.     printf("a+b=%d\n", add(a,b));  
  13.     printf("a-b=%d\n", sub(a,b));  
  14.     return 0;  
  15. }  
    【test-add.c】
[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. #include <test-add.h>  
  2. int add(int a, int b)  
  3. {  
  4.     return a+b;  
  5. }  
    【test-add.h】
[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. #ifndef __TEST_ADD  
  2. int add(int a, int b);  
  3. #endif  
    【test-sub.c】
[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. #include "test-sub.h"  
  2. int sub(int a, int b)  
  3. {  
  4.     return a-b;  
  5. }  
    【test-sub.h】
[cpp]  view plain copy 在CODE上查看代碼片 派生到個人代碼片
 
  1. #ifndef __TEST_SUB  
  2. int sub(int a, int b);  
  3. #endif  
 
2.複習gcc指令
    gcc指令可經過-I前綴指定頭文件路徑,特別說明./表明當前路徑,../表明上一級目錄。
 
3.編寫makefile
    請替換其中的[tab],並以代碼倉庫中的makefile文件爲主。
 
# 指令編譯器和選項
CC=gcc
CFLAGS=-Wall -std=gnu99

# 目標文件
TARGET=test
SRCS = test.c \
  ./test-add/test-add.c \
  ./test-sub/test-sub.c

INC = -I./test-add -I./test-sub

OBJS = $(SRCS:.c=.o)

$(TARGET):$(OBJS)
#    @echo TARGET:$@
#    @echo OBJECTS:$^
[tab]$(CC) -o $@ $^

clean:
[tab]rm -rf $(TARGET) $(OBJS)

%.o:%.c
[tab]$(CC) $(CFLAGS) $(INC) -o $@ -c $<

上面的makefile要好好理解:

$(SRCS:.c=.o) 表示把SRCS中.c替換成.o
Makefile變量替換引用 將.o替換成.c Makefile中替換變量結尾的字符  

    【具體說明】
    【1】相比於單個文件和多個文件的makefile,經過變量INC制定了頭文件路徑。頭文件路徑之間經過空格隔開。
    【2】編譯規則%.o:%.c中加入了頭文件參數$(CC) $(CFLAGS) $(INC) -o $@ -c $<,那麼在編譯的過程當中便會出現
    gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test.o -c test.c。和單個文件和多個文件的makefile相比增長了頭文件路徑參數。
    【3】SRCS變量中,文件較多時可經過「\」符號續行。
 
    【編譯】
    make clean && make
    【控制檯輸出】
rm -rf test test.o ./test-add/test-add.o ./test-sub/test-sub.o
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test.o -c test.c
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test-add/test-add.o -c test-add/test-add.c
gcc -Wall -std=gnu99 -I./test-add -I./test-sub -o test-sub/test-sub.o -c test-sub/test-sub.c
gcc -o test test.o test-add/test-add.o test-sub/test-sub.o
    從控制檯的輸出能夠看出,經過make clean清除上一次的可執行文件和目標文件,而後依次編譯各個C文件,在編譯的過程當中制定了頭文件路徑,最後把3個目標文件連接爲最終可執行文件。

 這個系列http://blog.csdn.net/xukai871105/article/details/37083675 很是好。

http://blog.csdn.net/shuaishuai80/article/details/6202529

更多:

http://wiki.ubuntu.org.cn/index.php?title=%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile&variant=zh-cn

http://blog.csdn.net/kesaihao862/article/details/7332528

 

makefile接受參數:

make out=test_1.c
-------------------------
file_name=$(out)
target=$(basename $(file_name))
all: $(target)
 
$(target):
gcc -o $(target) $file_name

再例:

TARGET=$(out)

all:$(TARGET)

        g++ `pkg-config opencv --libs --cflags opencv` $(TARGET)

 

以上是Makefile 文件。編譯帶opencv庫的程序,只要輸入相似 make out=hellow.c 很是方便

makefile文件之間參數傳遞:

http://blog.csdn.net/shallnet/article/details/37657597?utm_source=tuicool

條件判斷:

ifeq ($(CC),gcc)

libs=$(libs_for_gcc)

else

libs=$(normal_libs)

endif

 CFLAGS、CXXFLAGS、LDFLAGS與LIBS 

CFLAGS 表示用於 C 編譯器的選項,
CXXFLAGS 表示用於 C++ 編譯器的選項。
這兩個變量實際上涵蓋了編譯和彙編兩個步驟。

CFLAGS: 指定頭文件(.h文件)的路徑,如:CFLAGS=-I/usr/include -I/path/include。一樣地,安裝一個包時會在安裝路徑下創建一個include目錄,當安裝過程當中出現問題時,試着把之前安裝的包的include目錄加入到該變量中來。

LDFLAGS:gcc 等編譯器會用到的一些優化參數,也能夠在裏面指定庫文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安裝一個包都幾乎必定的會在安裝目錄裏創建一個lib目錄。若是明明安裝了某個包,而安裝另外一個包時,它愣是 說找不到,能夠抒那個包的lib路徑加入的LDFALGS中試一下。

LIBS:告訴連接器要連接哪些庫文件,如LIBS = -lpthread -liconv

簡單地說,LDFLAGS是告訴連接器從哪裏尋找庫文件,而LIBS是告訴連接器要連接哪些庫文件。不過使用時連接階段這兩個參數都會加上,因此你即便將這兩個的值互換,也沒有問題。

有時候LDFLAGS指定-L雖然能讓連接器找到庫進行連接,可是運行時連接器卻找不到這個庫,若是要讓軟件運行時庫文件的路徑也獲得擴展,那麼咱們須要增長這兩個庫給"-Wl,R":

LDFLAGS = -L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib

若是在執行./configure之前設置環境變量export LDFLAGS="-L/var/xxx/lib -L/opt/mysql/lib -Wl,R/var/xxx/lib -Wl,R/opt/mysql/lib" ,注意設置環境變量等號兩邊不能夠有空格,並且要加上引號(shell的用法)。那麼執行configure之後,Makefile將會設置這個選項,鏈 接時會有這個參數,編譯出來的可執行程序的庫文件搜索路徑就獲得擴展了。

參考了:http://www.cnblogs.com/ai616818/archive/2011/06/30/2094909.html

 

addprefix:

函數名稱:加前綴函數—addprefix。

函數功能:爲「NAMES…」中的每個文件名添加前綴「PREFIX」。參數「NAMES…」是空格分割的文件名序列,將「SUFFIX」添加到此序列的每個文件名以前。

返回值:以單空格分割的添加了前綴「PREFIX」的文件名序列。

函數說明:

示例:

 

$(addprefix src/,foo bar)

 

返回值爲「src/foo src/bar」。

 

$(shell pwd)和$(pwd)有什麼區別

Makefile裏面好像必須加shell,直接用$(pwd)好象不行。
我剛纔試了一下,把這幾行保存成Makefile,而後make能夠看到結果
P=$(shell pwd) # 這樣能夠輸出路徑
#P=$(pwd) # 這樣沒有輸出
all:
    echo $P

http://www.cnblogs.com/wang_yb/p/3990952.html

shell 用的是大括號, Makefile兩種都行.可是在命令裏用shell變量的是候就須要大括號.

  1. all:  
  2.     curr_dir=`pwd`; \  
  3.     echo ${curr_dir}; \  
  4.     echo $(LOGNAME); \  
  5.     echo ${LOGNAME}  

cur_dir := ${shell pwd}

long_bit = ${shell getconf LONG_BIT}

 

makefile .SUFFIXES

跟我學makefile中提到:

2.2.1       預約義隱含規則

能夠在makefile文件中重載這些隱含規則。也能夠取消預約義的隱含規則,只要不在後面寫命令就能夠了。make命令的參數‘-r’也能把缺省的後綴列表清空,從而刪除全部預約義的隱含規則。

若是預約義的隱含規則的依賴出如今後綴列表中,則該預約義的隱含規則也稱爲後綴規則。若是更改了後綴列表,那些依賴的後綴沒有出如今新後綴列表中的預約義的隱含規則將被禁止。

後綴是特殊目標.SUFFIXES的依賴名。例如:

.SUFFIXES:                          # 刪除缺省的後綴列表

.SUFFIXES:.cpp .obj          #把.cpp和.obj添加到後綴列表中。

2.2.2       隱含規則鏈

有時生成一個文件須要使用多個隱含規則組成的序列,這樣的隱含規則序列稱爲隱含規則鏈。同一條隱含規則不能在隱含規則鏈中出現兩次或兩次以上。

一般狀況下,任何在makefile文件中說起的目標和依賴都不是中間文件。可是,咱們能夠特別指定一些文件爲中間文件,只需將這些文件指定爲特殊目標.INTERMEDIATE的依賴。若是.INTERMEDIATE沒有依賴文件,它將不會發生做用。

爲了阻止自動刪除中間文件,能夠將須要保留的中間文件指定爲特殊目標.SECONDARY的依賴。.SECONDARY的依賴被處理爲中間文件,但它們永遠不能自動刪除。若是.SECONDARY沒有依賴文件,則全部的目標都將被處理爲中間文件。

也能夠將一個隱含規則的目標格式做爲特殊目標.PRECIOUS的依賴,這樣就能夠保留那些由該隱含規則建立的中間文件。

2.2.3       後綴規則

綴規則已經被格式規則代替,分爲單後綴和雙後綴規則。

雙後綴規則:                               等同於格式規則:

.c.o:                                                %.o: %.c

……                                                ……

單後綴規則:                               等同於格式規則:

.c                                                    %: %.c

……                                                ……

後綴規則不能有任何屬於它們本身的依賴,而格式規則能夠有依賴文件。例如:

%.o:%.c hello.h

……

沒有命令的後綴規則沒有意義,它們並不像沒有命令的格式規則那樣移去之前的規則。

老式風格的"後綴規則"

後綴規則是一個比較老式的定義隱含規則的方法。後綴規則會被模式規則逐步地取代。由於模式規則更強更清晰。爲了和老版本的Makefile兼容,GNU make一樣兼容於這些東西。後綴規則有兩種方式:"雙後綴"和"單後綴"。

雙後綴規則定義了一對後綴:目標文件的後綴和依賴目標(源文件)的後綴。如".c.o"至關於"%o : %c"。單後綴規則只定義一個後綴,也就是源文件的後綴。如".c"至關於"% : %.c"。

後綴規則中所定義的後綴應該是make所認識的,若是一個後綴是make所認識的,那麼這個規則就是單後綴規則,而若是兩個連在一塊兒的後綴都被 make所認識,那就是雙後綴規則。例如:".c"和".o"都是make所知道。於是,若是你定義了一個規則是".c.o"那麼其就是雙後綴規則,意義就是".c"是源文件的後綴,".o"是目標文件的後綴。以下示例:

   .c.o:
           $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

後綴規則不容許任何的依賴文件,若是有依賴文件的話,那就不是後綴規則,那些後綴通通被認爲是文件名,如:

   .c.o: foo.h
           $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

這個例子,就是說,文件".c.o"依賴於文件"foo.h",而不是咱們想要的這樣:

   %.o: %.c foo.h
           $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

後綴規則中,若是沒有命令,那是毫無心義的。由於他也不會移去內建的隱含規則。

而要讓make知道一些特定的後綴,咱們可使用僞目標".SUFFIXES"來定義或是刪除,如:

   .SUFFIXES: .hack .win

把後綴.hack和.win加入後綴列表中的末尾。

   .SUFFIXES:              # 刪除默認的後綴
   .SUFFIXES: .c .o .h   # 定義本身的後綴

先清除默認後綴,後定義本身的後綴列表。

make的參數"-r"或"-no-builtin-rules"也會使用得默認的後綴列表爲空。而變量"SUFFIXE"被用來定義默認的後綴列表,你能夠用".SUFFIXES"來改變後綴列表,但請不要改變變量"SUFFIXE"的值。

相關文章
相關標籤/搜索