0%

编写Makefile

编写Makefile


    Makefile编写的好可以在工程项目编译链接的过程中省去很多麻烦,平时在练习的过程中也是能方便高效的学习。

  • 整理知识,学习笔记
  • 发布日记,杂文,所见所想
  • 撰写发布技术文稿(代码支持)
  • 撰写发布学术论文(LaTeX 公式支持)

cmd-markdown-logo

一、Makefile相关知识点

    需要掌握的一些Makefile相关的基础知识。

1. 忽略出错的命令。

    如果不希望某条命令因为出错了而导致整个make执行被终止,可以在命令前面加上“-”,表示不管该命令出不出错,后面的命令都将继续执行下去。如:
    mkdir lpyuan
    如果不加“-”并且dir已经存在,则这条命令就会出错,并将导致整个make执行被终止。要想不被终止,则需要在前加上’-‘符号。
    -mkdir dir

2. 显示命令。

    一般默认make会把命令原样显示出来后再去执行命令,如果我们不需要原样显示命令,则可以在命令前面加一个“@”, 如
    @m -rf lpyuan
    则是不会输出命令。

3. 特殊符号。

    $@ 表示目标文件
    $^ 表示所有的依赖文件
    $< 表示第一个依赖文件
    $? 表示比目标还要新的依赖文件列表

如一个目录下有如下文件:
    hello.c  hi.c  main.c  Makefile
按照 Makefile 规则规规矩矩的写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
main: main.o hello.o hi.o
gcc -o main main.o hello.o hi.o
main.o: main.c
cc -c main.c
hello.o: hello.c
cc -c hello.c
hi.o: hi.c
cc -c hi.c
clean:
rm *.o
rm main

改为用上述符号进行替代:

main: main.o hello.o hi.o
gcc -o $@ $^
main.o: main.c
cc -c $<
hello.o: hello.c
cc -c $<
hi.o: hi.c
cc -c $<
clean:
rm *.o
rm main

4. Makefile中的常用函数。

4.1 函数名称 :反过滤函数—filter-out。

格式:$(filter-out PATTERN…,TEXT)
函数功能 :和“filter”函数实现的功能相反。过滤掉字串“TEXT”中所有符合“PATTERN”的单词,保留所有不符合的单词。可以多个模式。存在多模式时,模式表达式之间使用空格分割。
返回值 :空格分割的“TEXT”字串中所有不符合模式“PATTERN”的字串。
函数说明: “filter-out”函数也可以用来去除一个变量中的某些字符串(实现和“filter”函数相反)。
下面有个例子:

1
2
3
4
objects=main1.o foo.o main2.o bar.o 
mains=main1.o main2.o
$(filter-out$(mains),$(objects))
实现了去除变量"objects""mains"定义的字串(文件名)功能。它的返回值为"foo.o bar.o"

5 调试Makefile变量

5.1 如何打印Makefile变量名

有时间我们的项目包含多个makefile文件,需要调试某个变量时候,make没有直接的调试器,这样就会使得我们定位为题很不好操作。

但是我们也有以下方法对进行调试。makefile展开所有变量之后才会进行执行编译,所以利用这个特性,我们可以创建一个vars.mk的makefile文件用于调试makefile文件中变量。

比如要打印SRC变量make -f Makefile -f vars.mk SRC

1
2
3
4
5
6
# vars.mk
print-%:
@echo '$*=$($*)'
@echo "origin=$(origin $*)"
@echo "value=$(value $*)"
@echo "flavor=$(flavor $*)"

5.2 查看make执行的具体命令

有时候以下命令由于设置了一些选项,导致有些命令被隐藏了,需要知道具体执行的命令时候我们有以下方法可以实现。

make -n命令展开make执行的命令,但是不会真正执行编译任务。

make V=1命令可以将编译过程的详细信息打印出来。

6 编译器中的一些知识点

6.1 目录说明

C_INCLUDE_PATH 编译C程序时候用于查找头文件的环境变量。

CPLUS_INCLUDE_PATH 编译C++时候查找头文件使用的环境变量。

LIBRARY_PATH 程序链接阶段用户查找库文件路径使用的环境变量。

LD_LIBRARY_PATH 程序运行时,查找动态库路径使用的环境变量。

OBJ_INCLUDE_PATH编译Obj-C程序时候使用的环境变量用于查找头文件。

CPATH编译C/C++时程序使用的环境变量,用于查找头文件。

二、Makefile通用模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
TARGET=server
CC=g++
CFLAG=-c -g -static
#所有的.c文件
SRCS:=$(wildcard ../*.c)
FILTERS=../hello.c
#从SRCS中除了hello.c文件 filter函数可以选择满足条件的
SRCS:=$(filter-out $(FILTERS), $(SRCS))
OBJS:=$(patsubst %.c, %.o, $(SRCS))
CURRENT_PATH=$(PWD)
CPPFLAGS= -I../include -I../util
LIBS_PATH=-L../lib64
LIBS=-lmylib

#判断是哪个系统32bit编译还是在64bit编译。
ARCH:=$(shell uname -m)
ifeq ($(ARCH), x86_64)
VERSION:=X86_64
else
VERSION:=i686
endif

$(TARGET):$(OBJS)
$(CC) $(DEBUG) $(SRCS) $(LIBS_PATH) $(LIBS) $(CPPFLAGS) -o $(TARGET)

$(OBJS):%.o:%.c
$(CC) $(CFLAG) $< -o $@

.PHONY:clean
clean:
rm -rf *~ *.bak $(TARGET)

【顶层Makefile编写】
all: all_client all_server
rm -rf *~ *.bak
all_client:
$(MAKE) -C client
all_server:
$(MAKE) -C server

clean: clean_client clean_server
rm -rf *~ *.bak
clean_client:
$(MAKE) -C client clean
clean_server:
$(MAKE) -C server clean

感谢您花费时间阅读这篇文章,书中有错误的地方或者有什么建议都可以留言,或者通过邮件祝您在这里记录、阅读、分享愉快!

作 者: lpyuan
Email: lpyuan21@outlook.com
2020年02月28日 02:52:00

小主,路过打个赏再走呗~