程序编译

编译程序 一:linux程序编译过程(二)-makfile

2019-11-25 23:49:06 admin 681

(一)为什么要编写Makefile

我们自己平常在linux下编译源文件时,当然可以使用gcc -Wall -g main.c -o main这样的命令一个一个编译,但是一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,我们一个个编译是极其花费时间的,也是不可取的。

makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

(二)Makefile的基本规则
Mackfile基本规则
Target ...: Dependencies ...
Command ...
说明:
1)目标(TARGET):即最终想要产生的文件,如:可执行文件,目标文件或中间文件等;目标也可以是要执行的动作,如clean,也称为伪目标(用.PHONY指定伪目标)。
2)依赖(DEPENDENCIES):为了产生目标文件而依赖的文件列表,一个目标通常依赖于多个文件。
3)命令(COMMAND):是make执行的动作(shell命令或是可在shell下执行的程序,如echo)。注意:每个命令行的起始字符必须为TAB字符!
如果DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心的内容。
(三)简单Makefile的编写





上面例子直接链接一个中间目标文件,显得比较简单,当遇到源文件需要链接多个中间目标文件时会是怎么个样子呢?

比如 分别创建一个加法的add.c 和 add.h ,一个减法 sub.c和 sub.h 最后main.c 来调用add 和 sub实现加减法。此时Makefile 会像这样

图片关键词
main: main.o add.o sub.o
main.o: main.c
gcc -c main.c -o main.o
add.o: add.c
gcc -c add.c -o add.o#加-c 指定生成为可重链接.o文件sub.o: sub.c
gcc -c sub.c -o sub.o.PHONY:clean
clean:
-rm -rf *.o

使用看看

图片关键词
图片关键词

从上面注意几个地方

  当最终目标文件依赖多个.o时,将依赖的多个.o  一起写到main: 后面。然后依次以  目标:依赖文件  gcc...   的格式,罗列所有依赖关系

  由于在上面的过程中生成了多个中间.o文件(实际工程中肯定是比较多的),所以每次编译完成,后续基本还需要进行一定的清理工作,这时候就用上一个 "clean" (后面细说一下)来清理。

  ③ .PHONY意思表示clean是一个“伪目标”。也即是无论clean是否最新,一定执行它。rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但并不理睬。当然,clean的规则不要放在文件的开头,否则这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”

 

 

关于clean:  

   它只不过是一个动作名字,有点像c语言中的lable一样,其冒号后什么也没有,那么,make就不会自动去找它的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令(不仅用于clean,其他lable同样适用),就要在make命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个Makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。

 

 

到这,大致可以了解了makefile,以及大致怎么实现makefile.好, 那么make又是怎么用makefile进行执行的呢?






1.单级目录下的Makefile编写(接)

我们只需要使用vi Makefile命令创建一个新的Makefile文件,等我们编写好后,只需要使用make 命令就可执行编译操作。这里我们创建两个.c文件,使用他们生成目标文件:

[cpp]view plaincopy

.PHONY:clean

OBJECTS=01.o02.o

main:$(OBJECTS)

gcc-Wall-g$^-o$@

01.o:01.c

gcc-Wall-g-c$02.o:02.c
gcc-Wall-g-c$clean:
rm-fmain$(OBJECTS)上面是相对简练的写法,我们一个个来解释:
1.使用变量来代替01.o 02.o ,方便后文使用。
2.使用自动化变量简化一些操作
$@ 规则的目标文件名
$< 规则的第一个依赖文件名
$^ 规则的所有依赖文件列表
3.使用make clean 命令即可执行删除操作
2.多级(二级)目录生成可执行文件的Makefile的编写
01 02 文件夹下分别有01.c 02.c ,并且和文件夹同级目录的有03.c,main是由这三个.c文件共同生成的,如何编写?
[cpp]view plaincopy

.PHONY:cleanall

CC=gcc

CFLAGS=-Wall-g

BIN=main

SUBDIR=$(shellls-d*/)

ROOTSRC=$(wildcard*.c)

SUBSRC=$(shellfind$(SUBDIR)-name'*.c')

SUBOBJ=$(SUBSRC:%.c=%.o)

$(BIN):$(ROOTOBJ)$(SUBOBJ)

$(CC)$(CFLAGS)$(ROOTOBJ)$(SUBOBJ)-o$(BIN)

.c.o:

$(CC)$(CFLAGS)-c$clean:
rm-f*.o$(BIN)$(ROOTOBJ)$(SUBOBJ)1.SUBDIR=$(shell ls -d */) 使用shell命令,将当前目录下所有的子目录赋给SUBDIR
2.ROOTSRC=$(wildcard *.c) ROOTSRC代表当前目录下符合匹配模式的所有文件
3.SUBOBJ=$(SUBSRC:%.c=%.o) 生成.c对应的.o文件
以上就是这三个内嵌函数的使用方式。
3.多级(二级)目录下生成多个可执行文件
紧接上例,01文件下生成01可执行文件,02文件夹下生成02可执行文件,要求使用Makefile一个make命令完成。
这就需要我们在每个文件夹下编写自己的Makefile文件,最后使用文件夹目录的Makefile完成操作。
[cpp]view plaincopy

01文件夹下的Makefile

CC=gcc

BIN=01

OBJS=01.o

.PHONY:allcleanprint

all:print$(BIN)

print:

@echo"----makeallin$(PWD)-----"

#$(BIN):$(OBJS)

#$(CC)$(OBJS)-o$@

%.o:%.c

$(CC)-c$clean:
@echo"----makecleanin$(PWD)---"

rm-f$(BIN)$(OBJS)[cpp]view plaincopy

02文件夹下的Makefile

(这里02文件夹下为.cpp文件)

CXX=g++

BIN=02

OBJS=02.o

CPPFLAGS=-Wall-g

.PHONY:allcleanprint

all:print$(BIN)

print:

@echo"-----makeallin$(PWD)----"

$(BIN):$(OBJS)

$(CXX)$(CPPFLAGS)$(OBJS)-o$@

%.o:%.cpp

$(CXX)-c$clean:
@echo"----makecleanin$(PWD)----"

rm-f$(BIN)$(OBJS)[cpp]view plaincopy

文件夹同级目录下的Makefile文件

SUBDIRS=0102

.PHONY:defaultallclean$(SUBDIRS)

default:all

allclean:

$(MAKE)$(SUBDIRS)TARGET=$@

$(SUBDIRS):

$(MAKE)-C$@$(TARGET)

上面两个很好理解,最后的这个Makefile文件中,$(MAKE)代表make命令,TARGET默认是第一个即all,$(MAKE)-C(大写)代表进入到0102的Makefile中,执行参数为TARGET的操作。


当我们执行makeclean时,TARGET即为clean


首页
资源&收费
集群
成果
问答