Make 指南
引言
- makefile的优点:自动识别编译文件生成的时间戳,实现对最后修改的文件重新编译,而其他未修改的文件无需重新编译,加速了编译的速度。
- 预备知识:熟悉GCC编译器的常见编译的参数;makefile简单语法
makefile
规则
- GNU Make 工具通过读一个名为
Makefile
的文件,根据对应的规则来执行相应的命令,生成对应的目标文件
和可执行文件
以及动态库,静态库。 - 命令规则如下:
target
:dependencies
(tab)command
(tab)command
target
:规则的目标文件,可执行文件,动态库等的变量名,如xx.o
、xx.so
dependencies
表示生成目标文件的依赖项列表,依赖项之间空格隔开;- (tab):表示
tab
键,[Tab]字符告诉make此行是一个命令行,每一个命令行必须以[Tab]字符开始。
概念
-
伪目标:指Makefile中把那些没有任何依赖只有执行动作的目标
phony targets
;- 如
clean
:是典型的伪目标,该动作用于清理make命令生成的中间文件以及目的文件,执行make clean
; - 规则为:
.PHONY:clean
#声明是伪目标clean:
(tab)
rm xx.o temp #动作执行,删除的目标文件和temp文件- 注:#表示Makefile的注释标志符
- 如
-
make变量:类似C语言的宏,是一系列字符串,即变量的值,通常表示编译的参数列表,目录列表,编译选项列表等;
- 变量名是不包括“:”、“#”、“=”、前置空白和尾空白的任何字符串;
- 变量名区分大小写,一个包含除字母、数字和下划线以外的变量的做法是不可取的
- Makefile的变量名风格是通常采用大写的方式;如编译选项CFLAGS,包含目录include_dirs
- 变量名包含很少的几个特殊的符号:自动化变量,如
$<
、$@
、$?
、$*
- 变量的引用:采用
$(VARIABLE_NAME)
或${ VARIABLE_NAME }
方式引用变量的定义; - 变量引用的展开过程是严格的文本替换过程,就是说变量值的字符串被精确的展开在此变量被引用的地方;
-
make函数:介绍两种常见的函数:
wildcard
:通配符函数:如$(wildcard *.c)
来获取工作目录下所有的.c
文件列表。patsubst
:patten substitude, 匹配替换的缩写,通常和wildcard
函数结合使用;$(patsubst %.c,%.o,$(wildcard *.c))
:使用wildcard
函数获取工作目录下的.c文件列表;之后将列表中后缀.c
替换为.o
,得到在当前目录可生成的.o
文件列表;
# 仅编译可执行程序 CC = g++ # LINK = g++ CFLAGS = -std=c++11 -fpermissive -O2 INCLUDES = -I./include -I/usr/local/include LIBS = -L./lib -Wl,-rpath=./lib -lyour_libname -lopencv_core -lopencv_highgui -lopencv_imgproc SRCS := src/main.cpp OBJS := $(SRCS:.cpp=.o) #OBJS = $(patsubst %.cpp,%.o,$(wildcard *.cpp)) # replace the *.o filename of *.cpp filename TESTDEMO = demo $(OBJS): $(SRCS) $(CC) $(CFLAGS) -c $< -o $@ $(TESTDEMO): $(OBJS) $(CC) $< -o $@ $(CFLAGS) $(INCLUDES) $(LIBS) #compile: $(SRCS) # $(LINK) $^ -o $(TESTDEMO) $(CFLAGS) $(INCLUDES) $(LIBS) .PHONY: clean clean: rm -f $(TESTDEMO) $(OBJS)
-
同时编译动态库与可执行文件
CC := g++ CFLAGS := -Wall -Wextra -O3 -fPIC -std=c++11 LDFLAGS := -shared INCS := $(wildcard include/*.h) ifeq ($(TARGET_DEVICE),aarch64) CFLAGS+= -DPLATFORM_TEGRA endif PKGS:= gstreamer-1.0 gstreamer-pbutils-1.0 CFLAGS+= -I ./include CFLAGS+= $(shell pkg-config --cflags $(PKGS)) LIBS:= $(shell pkg-config --libs $(PKGS)) LIBS+= $(shell pkg-config --libs gdk-pixbuf-2.0) LIBS+= -L./lib -lvideo_embed_api TARGET_EXEC := demo TARGET_LIB := lib/libvideo_embed_sdk.so SRC_DIR := src OBJ_DIR := obj SRCS := $(wildcard $(SRC_DIR)/*.cpp) OBJS := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRCS)) APP_SRCS := test.cpp LIB_OBJS := $(filter-out $(APP_OBJS), $(OBJS)) all: $(TARGET_LIB) $(TARGET_EXEC) $(TARGET_EXEC): $(TARGET_LIB) $(CC) -o $@ $(APP_SRCS) $(CFLAGS) -L./lib -lvideo_embed_sdk $(TARGET_LIB): $(OBJS) $(CC) $^ -o $@ $(LDFLAGS) $(CFLAGS) $(LIBS) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp @mkdir -p $(OBJ_DIR) $(CC) $(CFLAGS) -c $< -o $@ .PHONY: clean clean: rm -rf $(OBJ_DIR) $(TARGET_EXEC) $(TARGET_LIB)
- 模板3
default: all ifndef OUT_DIR # OUT_DIR := build/$(build_prefix)$(build)$(build_suffix) OUT_DIR := ./ endif CC = g++ # -std=c++11 CFLAGS = -Wall -fPIC -Wl,-soname -w -D_REENTRANT -fpermissive -O2 -std=gnu++11 CFLAGS += $(XCFLAGS) LDFLAGS = -shared INCLUDES = -I./include -I./3rdparty # --- Commands --- ifneq ($(verbose),yes) QUIET_AR = @ echo " AR $@" ; QUIET_RANLIB = @ echo " RANLIB $@" ; QUIET_CC = @ echo " CC $@" ; QUIET_CXX = @ echo " CXX $@" ; QUIET_GEN = @ echo " GEN $@" ; QUIET_LINK = @ echo " LINK $@" ; QUIET_RM = @ echo " RM $@" ; QUIET_TAGS = @ echo " TAGS $@" ; QUIET_WINDRES = @ echo " WINDRES $@" ; QUIET_OBJCOPY = @ echo " OBJCOPY $@" ; QUIET_DLLTOOL = @ echo " DLLTOOL $@" ; QUIET_GENDEF = @ echo " GENDEF $@" ; endif MKTGTDIR = mkdir -p $(dir $@) LINK_CMD = $(QUIET_LINK) $(MKTGTDIR) ; $(CC) $(LDFLAGS) -o $@ $^ $(CFLAGS) $(INCLUDES) AR_CMD = $(QUIET_AR) $(MKTGTDIR) ; $(AR) cr $@ $^ # --- Rules --- $(OUT_DIR)/%.a : $(AR_CMD) $(OUT_DIR)/%.so: $(LINK_CMD) HDD_Code_LIB = $(OUT_DIR)/libhdd_code_api.so SOURCES := $(sort $(wildcard src/*.cpp)) SOURCES += $(sort $(wildcard 3rdparty/aes/*.cpp)) SOURCES += $(sort $(wildcard 3rdparty/bch/*.c)) SOURCES += $(sort $(wildcard 3rdparty/md5/*.cpp)) $(HDD_Code_LIB) : $(SOURCES) LIBS_TO_INSTALL_IN_LIB = $(HDD_Code_LIB) DEMO = test/test_api.cpp LIBS_TO_INSTALL_IN_BIN = demoApi LIBS = -L$(OUT_DIR) -lhdd_code_api -Wl,-rpath=$(OUT_DIR) -Wl,-rpath-link=$(OUT_DIR) LIBS += $(XLIBS) $(LIBS_TO_INSTALL_IN_LIB): $(SOURCES) $(CC) -o $@ $^ $(INCLUDES) $(CFLAGS) -shared $(LIBS_TO_INSTALL_IN_BIN): $(DEMO) $(CC) -o $@ $^ $(INCLUDES) $(CFLAGS) $(LIBS) libs: $(LIBS_TO_INSTALL_IN_LIB) apps: $(LIBS_TO_INSTALL_IN_BIN) # prefix ?= build/local # bindir ?= $(prefix)/bin # libdir ?= $(prefix)/lib # incdir ?= $(prefix)/include # install: libs apps # install -d $(DESTDIR)$(incdir)/ # install -m 644 include/*.h $(DESTDIR)$(incdir)/ # ifneq ($(LIBS_TO_INSTALL_IN_LIB),) # install -d $(DESTDIR)$(libdir) # install -m 644 $(LIBS_TO_INSTALL_IN_LIB) $(DESTDIR)$(libdir) # endif # install -d $(DESTDIR)$(bindir) # install -m 755 $(LIBS_TO_INSTALL_IN_BIN) $(DESTDIR)$(bindir) all: libs apps clean: rm -f $(LIBS_TO_INSTALL_IN_LIB) rm -f $(LIBS_TO_INSTALL_IN_BIN) rebuild: clean build # Avoid conflicts with files of the same name .PHONY: all clean libs apps
-
gcc编译的头文件路径
#gcc C_INCLUDE_PATH=$C_INCLUDE_PATH:your_path export C_INCLUDE_PATH #g++ CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:your_path export CPLUS_INCLUDE_PATH
-
重启终端即可生效, 可用以下命令查看搜索路径
echo | gcc -x c -v -E - echo | gcc -x c++ -v -E -