Make basics
本博客记录一些基本的Makefile语法。
An example
reference: Makefile Tutorial, Make 命令教程
先介绍几个比较有用的自动变量。
automatic variables | meaning |
---|---|
$@ | target name |
$< | the first prerequisite |
$^ | all prerequisites |
filter
配合通配符来过滤字符串,语法可以参考下例。
obj_files = foo.result bar.o lose.o
src_files = foo.raw bar.c lose.c
all: $(obj_files)
# Note: PHONY is important here. Without it, implicit rules will try to build the executable "all", since the prereqs are ".o" files.
.PHONY: all
# The filter function can be used in Static pattern rules to match the correct files.
# In this example, I made up the .raw and .result extensions.
# Ex 1: .o files depend on .c files. Though we don't actually make the .o file.
$(filter %.o,$(obj_files)): %.o: %.c
echo "target: $@ prereq: $<"
# Ex 2: .result files depend on .raw files. Though we don't actually make the .result file.
$(filter %.result,$(obj_files)): %.result: %.raw
echo "target: $@ prereq: $<"
%.c %.raw:
touch $@
clean:
rm -f $(src_files)
hellomake
make的一个重要作用是用于c/c++的项目编译,我们现在来看一个简单的例子。
hellomake: hellomake.c hellofunc.c
gcc -o hellomake hellomake.c hellofunc.c
clean:
rm -f *.o hellomake
在上述例子中,hellomake
为一个命令,也是编译的target
,后面跟着的hellomake.c
和hellofunc.c
为prerequesites
。第二行将使用gcc
工具生成hellomake
文件。clean
同样是一个命令,它执行删除文件的任务。
你可以执行make
来生成hellomake
文件,也可以在稍后执行make clean
来删除它。
现在我们已经看到,Makefile文件由一系列规则(rules)构成。每条规则的形式如下。
<target> : <prerequisites>
[tab] <commands>
接下来我们看一个复杂一点的例子。
CC=gcc
CFLAGS=-I.
hellomake: hellomake.o hellofunc.o
$(CC) -o hellomake hellomake.o hellofunc.o $(CFLAGS)
clean:
rm -f *.o hellomake
在上述例子中,CC
变量指定了编译器为gcc
,我们使用$(CC)
的方式来调用这个变量。
最后我们把Makefile写得漂亮一点
CC=gcc
CFLAGS=-I.
DEPS=hellomake.h
OBJ := hellomake.o
OBJ += hellofunc.o
# Compiles each of the object files as separate targets
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
# -o $@ -> Tells make to put the output in a file named after the target
# $^ -> all of the file names in $(OBJ) separated by a space
hellomake: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
.PHONY: clean
# Target to clean files created during compilation
clean:
rm -f *.o hellomake
为C/C++项目撰写Makefile
在实际的C/C++项目中,通常源文件不在同一目录下,为此需要把上述的例子稍微改造一下。
假设我们有如下文件树,其中*.cpp
文件在src
文件夹,*.h
文件在include
文件夹。
.
├── build
├── include
└── src
针对上述问题,可以用下面的Makefile语法解决。
all: demo
BUILD_DIRS := ./build
SRC_DIRS := ./src
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp')
demo: ${SRCS} | build
g++ -o ${BUILD_DIRS}/$@ $^
# $@指代当前目标, $< 指代第一个前置条件, $^ 指代所有前置条件
build:
mkdir -p build
.PHONY: clean
clean:
rm -rf build
Template
reference: Makefile Tutorial
# This is a template for c/c++ Makefile, you can use it for any project with a ./src directory
# Thanks to Job Vranish (https://spin.atomicobject.com/2016/08/26/makefile-c-projects/)
TARGET_EXEC := final_program
BUILD_DIR := ./build
SRC_DIRS := ./src
# Find all the C and C++ files we want to compile
# Note the single quotes around the * expressions. Make will incorrectly expand these otherwise.
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
# String substitution for every C/C++ file.
# As an example, hello.cpp turns into ./build/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
# String substitution (suffix version without %).
# As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d
DEPS := $(OBJS:.o=.d)
# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the output.
CPPFLAGS := $(INC_FLAGS) -MMD -MP
# The final build step.
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CXX) $(OBJS) -o $@ $(LDFLAGS)
# Build step for C source
$(BUILD_DIR)/%.c.o: %.c
mkdir -p $(dir $@)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
# Build step for C++ source
$(BUILD_DIR)/%.cpp.o: %.cpp
mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up.
-include $(DEPS)
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律