【工具类】make

1.一些概念

构建

  • 将源代码文件和资源文件转换为应用程序的过程。包含预处理,编译,汇编,连接,打包部署过程。

为什么需要构建工具

  • 项目小则直接使用编译命令进行手动编译来完成构建。而大型项目包含大量的源码文件,头文件,库文件(供链接的目标模块),且依赖关系复杂,构建是一个复杂过程,因而需要使用自动化编译工具来完成构建。常用的构建工具:apach ant,maven,bazel,make,cmake,gradle,webpack,rollup,esbuild等。

手动执行编译命令完成构建工作

# C/C++
gcc source.c -o executable

# Java
javac  source.java

make

  • make最初用于C/C++编译构建,但也是一个通用构建工具。make根据makefile文件来执行构建操作。

makefile

  • makefile由规则构成,每条规则由target,prerequisite,action构成。target是要生成的文件,prerequisite是生成target所依赖的文件,action指示如何使用prerequisite生成target。
  • make通过target和prerequisite的修改时间戳决定是否执行操作(target修改时间戳 < prerequisite修改时间戳:执行操作;否则跳过)。
  • target没有prerequisite文件,则make查看target文件是否存在,存在则认为target是最新的,跳过执行;target不存在则执行操作。
  • 注意,action行以一个tab开头,不能是空格,否则格式错误。
  • 实际项目中,更为规范的做法是将编译和链接分成开来写。

2. 例子

2.1 makefile基本写法

# directory tree
make-learning
├── greeting.c
├── greeting.h
├── main.c
└── makefile

# makefile
hello: main.c greeting.c
        gcc main.c greeting.c -o hello

# 执行构建
cd make-learning
make  # 将在当前目录下找makefile执行

2.2 将编译和链接分开

# makefile
hello: main.o greeting.o
    gcc main.o greeting.o -o hello

hello.o: main.c
    gcc -c main.c -o main.o

greeting.o: greeting.c
    gcc -c greeting.c -o greeting.o

# 执行构建
cd make-learning
make  # 找到当前目录构建所有target

3. 伪目标

为什么需要伪目标

  • 在构建中需要执行一些不生成文件的操作(如删除临时文件,产生文档,打包等)。

3.1 例子

3.1.1 伪目标:clean

没有将clean声明为伪target的情形
# makefile
hello: main.o greeting.o
    gcc main.o greeting.o -o hello

hello.o: main.c
    gcc -c main.c -o main.o

greeting.o: greeting.c
    gcc -c greeting.c -o greeting.o

clean:
    rm -f *.o hello

# 没有clean文件的情况
make clean
# out: rm -f *.o hello
 
# 有clean文件的情况,clean目标的执行失效
touch clean
make clean
# out: make: `clean' is up to date.

make将clean当做文件处理,如果本地有clean文件,则make认为clean文件是最新的而不予执行。可以提前声明clean为伪目标来避免执行clean target被本地的clean文件影响。

将clean声明为伪target的情形
# makefile
.PHONY: clean

hello: main.o greeting.o
    gcc main.o greeting.o -o hello

hello.o: main.c
    gcc -c main.c -o main.o

greeting.o: greeting.c
    gcc -c greeting.c -o greeting.o

clean:
    rm -f *.o hello

# 没有clean文件的情况
make clean
# out: rm -f *.o hello

# 有clean文件的情况,clean目标的执行失效
touch clean
make clean
# out: rm -f *.o hello

3.1.2 伪目标: all

可以通过命令行参数指定要make的target,也可以通过all这个伪target来make多个target。

# makefile
.PHONY: clean all
all: hello world
    echo 'all done!!'

hello: main.o greeting.o
    gcc main.o greeting.o -o hello

world: main.o greeting.o
    gcc main.o greeting.o -o hello

hello.o: main.c
    gcc -c main.c -o main.o

greeting.o: greeting.c
    gcc -c greeting.c -o greeting.o

clean:
    rm -f *.o hello


# 执行伪target all
make all

<< EOF out: 
cc  -I/opt/homebrew/opt/llvm/include  -c -o main.o main.c
gcc -c greeting.c -o greeting.o
gcc main.o greeting.o -o hello
gcc main.o greeting.o -o world
echo 'all done!!'
all done!!
EOF

hello和world两个target规则一样,可以放到一个规则中写,只需用空格隔开两个target名即可。其中使用自动变量$@来表示两个target中的每一个。

hello world: main.o greeting.o
    gcc main.o greeting.o -o $@

不打印伪目标 all 的action:在action前加@

.PHONY: clean all
all: hello world
    @echo 'all done!!'

hello.o和greeting.o规则一样,可以放在一个规则中写,需要使用通配符号和自动变量。
自动变量:$@ 表示目标文件, $< 表示第一个依赖文件, $^表示所有依赖文件
# before
hello.o: main.c
    gcc $(CFLAGS) -c $< -o $@

greeting.o: greeting.c
    gcc $(CFLAGS) -c $< -o $@

# after
%.o: %.c
    gcc $(CFLAGS) -c $< -o $@

3.2 完整的例子

# makefile
.PHONY: clean all
CFLAGS = -Wall -g -O2
targets = hello world
sources = hello.o: main.c
objects = main.o greeting.o

all: $(targets)
    @echo 'all done!!'

$(targets): $(objects)
    gcc $(CFLAGS) $(objects) -o $@

%.o: %.c
    gcc $(CFLAGS) -c $< -o $@

clean:
    rm -f *.o hello world

# 执行
make all
<< EOF
gcc -Wall -g -O2 -c main.c -o main.o
gcc -Wall -g -O2 -c greeting.c -o greeting.o
gcc -Wall -g -O2 main.o greeting.o -o hello
gcc -Wall -g -O2 main.o greeting.o -o world
all done!!
EOF

ps:

  • touch一个已经存在的文件,将更新该文件的时间戳 。
  • -f参数指定make的规则文件。make能自动识别规则文件makefile,如果规则文件makefile改成其他名字,则需要通过-f参数指定规则文件。
  • -C参数指定make执行的目录。项目有多个子模块,每个子模块下有自己的makefile,在项目根目录的makefile中调用子模块的makefile。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值