1、Makefile文件的介紹
答:在Linux下Makefile我們可以把理解爲工程的編譯規則。一個工程中源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,Makefile定義了一系列的規則來指定,那些文件需要先編譯,那些文件需要後編譯,那些文件需要重新編譯,甚至於進行更復雜的功能操作,因爲Makefile就像一個shell腳本一樣,其中也可執行操作系統的命令。Makefile帶來的好處就是——“自動化編譯”,一旦寫好就只需要一個make命令,整個工程完全自動編譯,極大地提高了軟件開發的效率。
在windoes系統系,C/C++程序首先編譯成.obj中間文件,然後中間文件鏈接生成.exe可執行文件;而在Linux/unix中,編譯生成的中間文件是.o文件,然後.o中間文件鏈接生成可執行文件(沒有.exe後綴)。Makefile的作用就是實現前述的生成可執行文件。
2、Makefile文件的組成
答:Makefile裏主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和註釋。
①顯式規則。顯式規則說明了,如何生成一個或多的的目標文件。這是由Makefile的書寫者明顯指出,要生成的文件,文件的依賴文件,生成的命令;
②隱晦規則。由於我們的make有自動推導的功能,所以隱晦的規則可以讓我們比較粗糙地簡略地書寫Makefile,這是由make所支持的;
③變量的定義。在Makefile中我們要定義一系列的變量,變量一般都是字符串,像C語言中的宏一樣,當Makefile被執行時其中的變量都會被擴展到相應的引用位置上;
④文件指示。其包括了三個部分,一是在一個Makefile中引用另一個Makefile,用include實現;二是指根據某些情況指定Makefile中的有效部分,就像C語言中的預編譯#if一樣;三是定義一個多行的命令;
⑤註釋。Makefile中只有行註釋,和UNIX的Shell腳本一樣,其註釋是用“#”字符,這個就像C/C++中的“//”一樣。如果你要在你的Makefile中使用“#”字符,可以用反斜框進行轉義,如:“\#”。
3、makefile的默認文件名有哪些
答:GNUmakefile、Makefile和makefile。在某路徑下執行命令:make,編譯器會自動到當前路徑下尋找與前面所說的文件名之一相同的文件。
4、makefile中的include作用
答:makefile可以包含其他的makefile文件,用include實現。
格式:include <filename>或者-include <filename>;後者多一個“-”表示不管有沒有找到該文件都不報錯。
其最典型的作用就是:對於多目錄下的makefile編寫,可以在每個目錄下寫一個makefile文件,然後在一個目錄(一般是父目錄)中寫一個總的makefile文件,這個makefile文件中包含所有的其他makefile即可。
5、makefile的文件規則
答:makefile規則如下:
target : prerequisites
(tab)<command>
(tab)<command>
①target可以是一個標籤,如start,也可以是一個或多個目標文件等;
②prerequisites是生成目標文件所需要的一個或多個依賴文件.o,冒號後面的就表示依賴文件;
③然後下面就是一系列的命令command,每個命令前都要有tan縮進;
④Makefile的入口就是第一個文件,上述就是target。
⑤target : prerequisites是表示一種依賴關係,本處具體表示目標文件的依賴關係。
⑥在第一個文件,也就是入口前面前面一般還可以定義變量。
6、makefile中定義變量
答:在makefile的開頭處定義變量,定義方式如:xx=xxx,xx後面加一個等號“=”並賦值就表示變量;
makefile中定義變量作用:對於文件中常出現並可能需要更改的關鍵字,用變量可以避免後期更改的複雜性,即只需要更改變量賦值一處即可。
變量的調用:$(xx)——就是在$後的括號中添加需要調用的變量名;
7、Makefile中常用的3個符號變量
答:分別是:$@、$^、$<;具體意義如下:
$@——目標文件,$^——所有的依賴文件,$<——第一個依賴文件。
注意,此處的目標文件和依賴文件是相對而言的,如目標文件——在第一個文件入口處目標文件生成處表示最終的目標文件如可執行文件.exe,在依賴文件生成處表示依賴文件.o;依賴文件——同理也不一定是.o,也可能是.c或.cpp。
8、一個包含變量的簡單makefile編寫例子(生成可執行文件類型的)
答:(1)其中,包含三個文件:a.h、a.cpp、main.cpp,具體內容如下:
a.h:
#ifndef AH_H
#define AH_H
void test();
#endif
a.cpp:#include<stdio.h>
void test()
{
printf("I am Xiongchao!\n");
}
main.cpp:#include<iostream>
#include"a.h"
using namespace std;
int main()
{
test();
return 0;
}
若要最終生成可執行文件mytest,那麼makefile編寫應該如下://①變量定義
CC=g++ //定義變量,表示使用g++編譯器
SRCS=main.cpp a.cpp //表示項目中所需要的源文件,有更多直接在後面添加,換行用反斜槓\
OBJS=$(SRCS:.cpp=.o) //表示目標依賴文件.o,其又依賴於SRCS中的cpp文件
EXEC=mytest //表示生成的可執行文件
CFLAGS=-Wall -O -g //配置編譯器,-Wall表示輸出警告信息,-O表示編譯優化,-g表示編譯debug版本
//②目標文件的編譯規則
$(EXEC):$(OBJS) //規則入口->目標文件:引入依賴文件,等價於mytest:main.o a.o
$(CC) $(CFLAGS) -o $(EXEC) $(OBJS) //等價於g++ -o mytest main.o a.o;注意:命令前要縮進tab
//③目標依賴文件的編譯規則
.cpp.o //缺省規則:等價於%o:%cpp,表示OBJS中所有的.o文件與SRCS中同名.cpp文件的依賴關係(OBJS中有多個.o,下面命令就需要執行多次)
$(CC) $(CFLAGS) -o $@ -c $< #等價於g++ -o main.o -c main.cpp和g++ -o a.o -c a.cpp
//④清除命令
clean: //注意:此處clean不是文件,而是一個動作
rm -rf $(OBJS) //刪除依賴文件
(2)makefile執行的入口是第一個文件位置,即$(EXEC):$(OBJS)這句話,':'前面是目標文件,':'後面是目標文件的依賴文件。首先,依賴文件及依賴文件的依賴文件都沒有被修改的話,入口下面的命令行就不執行;
(3)對於(2)具體點:對於目標文件如.exe和依賴文件.o,makefile是通過.o文件是否存在以及.cpp文件是否被修改來判斷是否需要重新編譯的。若.cpp被修改或者.o不存在,就需要對.o和目標文件重新編譯;
(4).h頭文件不屬於依賴文件,它由編譯器來管理;
(5)再次編譯前命令make clean可以清除依賴文件。
9、makefile執行過程
答:GNU的make工作時的執行步驟入下(想來其它的make也是類似):
①讀入所有的Makefile。
②讀入被include的其它Makefile。
③初始化文件中的變量。
④推導隱晦規則,並分析所有規則。
⑤爲所有的目標文件創建依賴關係鏈。
⑥根據依賴關係,決定哪些目標要重新生成。
⑦執行生成命令。
1-5步爲第一個階段,6-7爲第二個階段。
10、幾個不同類型的通用makefile模板
答:(1)編譯動態庫
#############################################################
# Makefile for shared library.
# 編譯動態鏈接庫
#############################################################
#set your own environment option
CC = g++
CC_FLAG = -D_NOMNG -D_FILELINE
#set your inc and lib
INC =
LIB = -lpthread -L./ -lsvrtool
#make target lib and relevant obj
PRG = libsvrtool.so
OBJ = Log.o
#all target
all:$(PRG)
$(PRG):$(OBJ)
$(CC) -shared -o $@ $(OBJ) $(LIB)
.SUFFIXES: .c .o .cpp
.cpp.o:
$(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o
.PRONY:clean
clean:
@echo "Removing linked and compiled files......;
rm -f $(OBJ) $(PRG)
(2)編譯靜態庫#############################################################
# Makefile for static library.
# 編譯靜態鏈接庫
#############################################################
#set your own environment option
CC = g++
CC_FLAG = -D_NOMNG -D_FILELINE
#static library use 'ar' command
AR = ar
#set your inc and lib
INC =
LIB = -lpthread -L./ -lsvrtool
#make target lib and relevant obj
PRG = libsvrtool.a
OBJ = Log.o
#all target
all:$(PRG)
$(PRG):$(OBJ)
${AR} rv ${PRG} $?
.SUFFIXES: .c .o .cpp
.cpp.o:
$(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o
.PRONY:clean
clean:
@echo "Removing linked and compiled files......"
rm -f $(OBJ) $(PRG)
(3)可執行文件
###########################################
#Makefile for simple programs
###########################################
INC=
LIB= -lpthread
CC=CC
CC_FLAG=-Wall
PRG=threadpooltest
OBJ=CThreadManage.o CThreadPool.o CThread.o CWorkerThread.o threadpooltest.o
$(PRG):$(OBJ)
$(CC) $(INC) $(LIB) -o $@ $(OBJ)
.SUFFIXES: .c .o .cpp
.cpp.o:
$(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o
.PRONY:clean
clean:
@echo "Removing linked and compiled files......"
rm -f $(OBJ) $(PRG)