入门级Makefile

现在开发服务器端的程序写的文件越来越多,linux系统并没有windows那样的集成工具(IDE)开始写代码直接用 gcc就可以编译成功了,可是文件越来越多,编译起来是一件很痛苦是的事,是时候写Makefile让机器自动编译了。

Makefile的语言规则一般是这样的。

目标:依赖(依赖项可有可无)

       命令

注意命令的输入必须要有tab键要不然是不行的。

第一个最简单的Makefile:

main:main.o add.o sub.o
	gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
	gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
	gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
	gcc -Wall -g -c sub.c -o sub.o

解释一下:

第一组代码:

main:main.o add.o sub.o
	gcc -Wall -g main.o add.o sub.o -o main

main是要生成的目标,main.o add.o sub.o是依赖项。gcc -Wall -g main.o add.o sub.o -o main 是命令。完全是按照Makefile文件格式来的。

但是并没有main.o add.o sub.o 所以需要在下面找。

第二组代码:

main.o:main.c
	gcc -Wall -g -c main.c -o main.o

main.o是目标,main.c 是依赖项。    gcc -Wall -g -c main.c -o main.o 是命令。语法符合Makefile的语法。

同理第三组,第四组代码都是这么来的。

再上升一个层次:

伪目标:

clean:
	rm -f main main.o add.o sub.o

这一组命令是伪目标。

作用是可以清除不需要的中间文件。

输入 make clean 就可清除main main.o add.o sub.o这些文件。假如不想删除main文件,不要在命令中写就行了。

这就是执行伪目标的效果。

假如你修改了 main.c 文件只需要重新编译main.o文件即可不想都重新编译一次。只要输入命令 make main.o 即可; 

但是这样做会遇到一个问题那就是,假如文件夹下有个clean的文件那么make clean就出错了,怎么办那?

只要在开头声明一下就可以了。

.PHONY:clean

 加上这句话的意思就是clean为伪目标

再执行make clean就没什么问题了。

最终的代码就这这样的就行了。

.PHONY:clean
main:main.o add.o sub.o
	gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
	gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
	gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
	gcc -Wall -g -c sub.c -o sub.o
clean:
	rm -f main.o add.o sub.o

当然,这只是一个最简单的,不是很专业。下面介绍专业的Makefile的写法,首先介绍一下Makefile的自动化变量:

选项名 作用
$@ 规则的目标文件名
$< 规则的第一个依赖文件名
$^ 规则的所有依赖文件列表
.PHONY:clean
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
	gcc -Wall -g $^ -o $@
main.o:main.c
	gcc -Wall -g -c $< -o $@
add.o:add.c add.h
	gcc -Wall -g -c $< -o $@
sub.o:sub.c sub.h
	gcc -Wall -g -c $< -o $@
clean:
	rm -f $(OBJECTS)

解释一下:

其实这个Makefile和上面的Makefile没什么区别,只是一些文件用变量代替了。比如main.o add.o sub.o用OBJECTS 代替。以下有关main.o add.o sub.o的都可以用$(OBJECTS)代替。

$^是规则依赖的文件列表,$@是目标名,$<规则的第一个依赖文件。

假如文件夹下有两个Makefile文件 可是使用make -f Makefile1  来指定执行的Makefile文件

Makefile编译多个可执行文件:

模式规则

%.o:%.c

后缀规则

.c.o:

先来个最简单的Makefile

.PYONY:clean
BIN=01test 02test
all:$(BIN)
clean:
    rm -f $(BIN)

解释一下,这个就是让编译器自己推导,让同名.c文件生成同名可执行文件

正常的Makefile

.PYONY:clean
BIN=01test 02test
all:$(BIN)
%.o:%.c
	gcc -Wall -g -c $< -o $@
01test:01test.o
	gcc -Wall -g $^ -o $@
02test:02test.o	
	gcc -Wall -g $^ -o $@
clean:
	rm -f $(BIN) *.o

解释一下:

%.o:%.c

这个的意思是把.c文件生成同名的.o文件。也可以使用.c.o:代替;

当然也可以写的更加专业一点:

.PYONY:clean
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test
all:$(BIN)
%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
	$(CC) $(CFLAGS) $^ -o $@
02test:02test.o	
	$(CC) $(CFLAGS) $^ -o $@
clean:
	rm -f $(BIN) *.o

make常用内嵌函数

函数调用

$(function arguments)

$(wildcard PATTERN)

当前目录下匹配模式的文件

例如:src=$(patsubst %.c,%.o,$src)

等价于$(src:.c=.o)

shell函数

执行shell命令

例如:$(shell ls -d */)  意思是讲目录下所有的文件夹显示出来。  

举个栗子:

cc = gcc
CFLAGS = -Wall -g
BIN = main
SUBDIR = $(shell ls -d */)
ROOTSRC = $(wildcard *.c)
ROOTOBJ = $(ROOTSRC:%.c=%.o)
SUBSRC = $(shell find $(SUBDIR) -name '*.c')
SUBOBJ = $(SUBSRC:%.c=%.o)

$(BIN):$(ROOTOBJ) $(SUBOBJ)
		$(cc) $(CFLAGS) -o $(BIN) $(ROOTOBJ)
 $(SUBOBJ).c.o:
	 $(cc) $(CFLAGS) -c $< -o $@

clean:
	  rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

第一行代码:cc = gcc 定义变量gcc为变量cc 引用的时候需要使用$(cc)即可

第二行代码:CFLAGS = -Wall -g 定义变量 CFLAGS

第三行代码:BIN = main 定义变量main为变量BIN 这个是生成的目标文件。

第四行代码:SUBDIR = $(shell ls -d */) 这行代码的意思是把当前目录下的所有文件夹的名字赋值到SUBDIR中

第五行代码:ROOTSRC = $(wildcard *.c)这行代码的意思是匹配文件夹下的所有.c文件。

第六行代码:ROOTOBJ = $(ROOTSRC:%.c=%.o)这行代码的意思是把匹配到的.c文件换成.o 文件,是和第五行代码连用的

第七行代码:SUBSRC = $(shell find $(SUBDIR) -name '*.c')这行代码是寻找在当前文件夹下所有文件夹下的.c文件赋值给SUBSRCT

第八行代码:SUBOBJ = $(SUBSRC:%.c=%.o)这行代码的意思是把第七行找到的.c 文件转化成.o文件。

第十行代码:$(BIN):$(ROOTOBJ) $(SUBOBJ)
                                     $(cc) $(CFLAGS) -o $(BIN) $(ROOTOBJ)

                        这一组代码的意思是编译上边的.o文件,编译成目标文件

第十三行代码:.c.o:  

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

                   这一组代码的意思是。把所有.c 文件编译成.o文件。

第十五行代码:

clean:
      rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

              这一组代码的意思是伪目标,用来清除中间文件的。

Makefile编辑多个可执行文件

SUBDIRS = test1 test2
.PHONY:default all clean $(SUBDIRS)
default:all

all clean:
    $(MAKE) $(SUBDIRS) TARGET=$(@)
$(SUBDIRS):
    $(MAKE) -C $@ $(TARGET)
CC = gcc
BIN = test1
OBJS = ts1.o
.PHONY: all clean print
all:print $(BIN)
print:
    @echo "-----------make all in $(PWD) ------------"
$(BIN):$(OBJS)
    $(CC) $(OBJS) -o $@
%.o:%.c
    $(CC) -c $<
clean:
    @clean "----------make clean in $(PWD)------------"
    rm -f $(BIN) $(OBJS)
CXX = g++
BIN = test2
OBJS = test2.o
CPPFLAGS = -Wall -g
.PHONY:all clean print
all:print $(BIN)
print:
    @echo "-----------make all in $(PWD)-------------"
$(BIN):$(OBJS)
    $(CXX) $(OBJS) -o $@
.o:%.cpp
    (CXX) -c $<
clean:
    @echo "-------------make clean in $(PWD)------------ "
    rm -f $(BIN) $(OBJS)

解释一下假如有两个文件需要编译时需要写三个Makefile的一个是总的Makefile的另外两个是在文件下的,大体就是一个Makefile编译两个Makefile。

猜你喜欢

转载自blog.csdn.net/m0_38036750/article/details/85318715