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.chellofunc.cprerequesites。第二行将使用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)


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Cisco_coco  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示