Linux下的Makefile文件编写

时间:2022-08-22 03:56:59

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 optionCC = g++CC_FLAG = -D_NOMNG -D_FILELINE#static library use 'ar' command AR = ar#set your inc and libINC = LIB = -lpthread -L./ -lsvrtool#make target lib and relevant obj PRG = libsvrtool.aOBJ = Log.o#all targetall:$(PRG)$(PRG):$(OBJ)${AR} rv ${PRG} $?.SUFFIXES: .c .o .cpp.cpp.o:$(CC) $(CC_FLAG) $(INC) -c $*.cpp -o $*.o.PRONY:cleanclean:@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)