极简make和makefile教程

GNU make

GNU Make 就是用来控制生成可执行文件的这么一个工具,它的目的就是把一个已经写好的源文件生成为可执行的程序。想要完成这个任务,Make需要一个makefile的文件来记录如何生成我们想要的程序,这里面包含了要生成的目标对象信息,已经生成这个目标对象所需要依赖的其他文件,生成目标对象的过程指令等。如果,你已经写好了一个程序,你可以为其写一个 makefile,然后使用Make去编译和安装,总之,make并非编译语言的特权,作为一个工具,make实现了一套半自动化的工作流程,你可以用这个流程来做任何东西。

make 的功能

  1. Make 让终端用户在不需要知道细节情况下,编译和安装我们写好的程序——具体的细节都保存在 makefile 文件中;
  2. Make 根据那些源文件被修改过,可以自动完成对相应源文件的更新,同时,也可以自动确定更新源文件恰当顺序,除非一个非源文件依赖于另一个非源文件;
  3. Make 不限制于任何特定的语言。对于程序任何的非源文件,makefile 通过 shell 命令去生成对应的可执行程序。这些_shell_命令可以执行编译命令生成可执行文件,执行连接命令生成可执行文件,ar 命令去更新库,或者 TexMakeinfo 命令完成文档的格式;
  4. Make不限于用于完成安装包的编译。你还可以使用Make去控制安装/卸载安装包、为其生成标记表,或者其他你认为用Make去完成是又价值的事情。

make 规则

Makefile由一组规则(Rule)组成,每条规则的格式

目标 : 条件

目标和条件之间的关系是:欲更新目标,必须先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个Tab开头,注意不能用空格代替这个Tab,Makefile的格式不像C语言的缩进那么随意。对于Makefile中的每个以Tab开头的命令,make会启动一个Shell进程去执行它。

make 判断是否需要更新是根据文件的修改时间来判断的,如果目标文件的修改时间相较于源文件是更新的,那就不会对目标文件进行更新,如果源代码文件比目标文件新,那么就会对目标文件进行更新,而且是仅仅更新那一部分,而不是全部都重新编译一遍。

注意事项:
make是一个半自动化工具,不涉及编译等任何功能实现,通过调用编译器等底层工具来完成工作。
规则语句前面是制表符TAB,写成空格会出错!
赋值符号:=基本赋值,:=覆盖之前的指,?=如果没有值则赋值,+=继续添加后面的值。
$@ 表示目标文件。 $^ 表示所有依赖项。 $< 表示第一个依赖文件

tutorial

A Makefile consists of a set of rules. A rule generally looks like this:

targets: prerequisites
	command
	command
	command

实践

以下实践例子来自于仕琪副教授发布于B站教学视频,链接在此
以下编写了一个Makefile文件,对包含四个源文件文件的demo项目进行半自动化编译,从Version1到Version4,从简陋到专业。

## Version 1
# disadvantage: too many file, if there is one file that updated, make will rebuild all file, this would waste much time.
hello: main.cpp printhello.cpp factorial.cpp
	g++ -o hello main.cpp printhello.cpp factorial.cpp


## Version 2
# more pros
# disadvantage: this version have finish the basic function as a tool,but if we want change the compile flag, it cannot do it.
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o
$(TARGET): $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

## Version 3

CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o
CXXFLAGS = -c -Wall
# it means show all of the warning

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^
	# "$@" means the target file,"$^" means all the dependent file
	$(info all: $^)
	$(info target: $@)
	
%.o:%.cpp
	$(CXX) $(CXXFLAGS) $< -o $@
	# "$<" means the first dependent file
	$(info first: $<)


.PHONY: clean
# this line mean that .PHONY dependent on clean ,so the clean will be executed,the purpose of this line is to prevent clean would not be executed when there is a file which named clean in the dir
clean:
	rm -f *.o $(TARGET)

## Version 4

CXX = g++
TARGET = hello
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -c -Wall

$(TARGET):$(OBJ)
	$(CXX) -o $@ $^

%.o:%.cpp
	$(CXX) $(CXXFLAGS) $< -o $@
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值