嵌入式Linux入门10:编译管理Makefile

2019-07-12 14:58发布

在Linux开发中,Makefile占有比较重要的一席之地。几乎所有的开源项目都会带有Makefile——或脚本产生,或自带。前面的文章也有介绍过,linux环境编译程序有三个步骤:./configure、make和make install。在此过程,configure脚本就会产生Makefile。 另外有些项目是自带Makefile的,比如busybox和kernel。当然,现在也有很多项目为了跨平台编译而使用cmake,比如opencv。 在实际开发中,笔者比较喜欢使用自己编写的Makefile模板,包括应用层和驱动层。本文主要说说应用层的Makefile模板。这个模板的好处是在使用时,只需要修改编译器名称(比如交叉编译情况)、目标名称、头文件、库文件路径即可,其它无需修改。可适用于静态库、动态库、二进制程序的编译。 为了方便介绍,下面分段说说Makefile内容。如使用Makefile模板,请到文后github下载。另外要注意的是Makefile的规则后是使用Tab键的,不能使用空格。 1、编译器、链接器配置。如需交叉编译,则在这里指定交叉编译器。 # !!!=== cross compile... CROSS_COMPILE ?= CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ AR = $(CROSS_COMPILE)ar ARFLAGS = -cr RM = -rm -rf MAKE = make 2、这里指定目标文件,可以是静态库.a文件,动态库.so文件,其它则为二进制文件。后面会根据此目标名称做判断,执行相应的动作。 # !!!=== # target executable file or .a or .so target = a.out
3、这里指定的是编译选项CFLAGS。默认开启所有警告,并且遇到第一个编译错误时就停止,不再继续编译。这样做的目的是方便大家排查编译错误。 # !!!=== # compile flags CFLAGS += -Wall -Wfatal-errors
4、这里指定的是debug版本还是release版本,两者由不同的编译选项来确定。默认是debug版本。 #**************************************************************************** # debug can be set to y to include debugging info, or n otherwise debug = y #**************************************************************************** ifeq ($(debug), y) CFLAGS += -ggdb -rdynamic else CFLAGS += -O2 -s endif
5、这里是额外的编译选项,包括头文件路径、库路径、宏定义等。 # !!!=== DEFS += -DJIMKENT CFLAGS += $(DEFS) CXXFLAGS = $(CFLAGS) LIBS += LDFLAGS += $(LIBS) # !!!=== INC1 = ./ INC2 = ./inc INC3 = INCDIRS := -I$(INC1) -I$(INC2) # !!!=== CFLAGS += $(INCDIRS) CXXFLAGS += # !!!=== LDFLAGS += -lpthread -lrt DYNC_FLAGS += -fpic -shared 6、这里是源码目录名称。如果是工程源码与Makefile在同一级目录,则使用下面的即可(默认是“.”,表示当前目录)。 # !!!=== # source file(s), including c file(s) or cpp file(s) # you can also use $(wildcard *.c), etc. SRC_DIR = . SRC_DIR1 = SRC_DIR2 = SRC_DIR3 =
7、这里是输出详细编译信息的开关,可以make V=1开启,默认关闭。在观察编译过程使用哪些路径或编译选项时,可以使用这个功能。 ifeq ($(V),1) Q= NQ=true else Q=@ NQ=echo endif
8、这里是目标文件生成规则,根据不同目标,或使用g++,或使用ar。 $(target): $(OBJ) ifeq ($(suffix $(target)), .so) @$(NQ) "Generating dynamic lib file..." $(notdir $(target)) $(Q)$(CXX) $(CXXFLAGS) $^ -o $(target) $(LDFLAGS) $(DYNC_FLAGS) else ifeq ($(suffix $(target)), .a) @$(NQ) "Generating static lib file..." $(notdir $(target)) $(Q)$(AR) $(ARFLAGS) -o $(target) $^ else @$(NQ) "Generating executable file..." $(notdir $(target)) $(Q)$(CXX) $(CXXFLAGS) $^ -o $(target) $(LDFLAGS) endif
9、这里是编译规则,根据.c和.cpp文件调用不同的命令进行编译。 # make all .c or .cpp %.o: %.c @$(NQ) "Compiling: " $(addsuffix .c, $(basename $(notdir $@))) $(Q)$(CC) $(CFLAGS) -c $< -o $@ %.o: %.cpp @$(NQ) "Compiling: " $(addsuffix .cpp, $(basename $(notdir $@))) $(Q)$(CXX) $(CXXFLAGS) -c $< -o $@
10、这里是清除命令,主要是清除生成的临时文件和目标文件。值得一提的是下面的find语句,如果生成的.o文件体积十分大并且又不需要修改,则可以将其排除在删除之列。比如onvif开发的soapC.o文件,就不需要删除,这样就能加快编译速度了。 clean: @$(NQ) "Cleaning..." $(Q)$(RM) $(target) # use 'grep -v soapC.o' to skip the file @find . -iname '*.o' -o -iname '*.bak' -o -iname '*.d' | xargs rm -f Makefile模板的git仓库地址:https://github.com/latelee/Makefile_templet 这个仓库作者会不定时更新。欢迎大家使用并提出宝贵意见。
李迟 2017.9.3 夜