Makefile是Linux平台大型工程中必不可少的一部分。其重要性不言而喻,详细的概念这里就不再累赘,直接进入主题。
本文给出三个Makefile样例,分别是生成
执行文件、生成
静态库和生成
动态库的Makefile。三者主要是生成的命令不一样,其他规则相同。
代码拿到后,只需做很简单的修改即可融入现有工程中。主要配置源码路径、编译工具链、编译参数、链接参数。
需要说明的是,该Makefile模板的优点在于,添加或删除文件时,不需要修改Makefile,并且整个工程只有一个Makefile文件。修改头文件时,也不需要从头make clean,这在大型项目中可以节省很多编译时间。只有在增加新的目录时,才需要修改Makefile。支持多平台编译,根据传进来的参数选择不同的编译工具。有优点就有缺点,
最大的缺点在于不可以选择性编译,也就是所有在工程中的源文件和库文件,都会编译进来。
先来看看生成执行文件的Makefile:
概念快速扫盲:$@ 表示目标文件;$^
表示所有的依赖文件;$<
表示第一个依赖文件
命令执行必要条件是,文件比依赖新时,也就是文件有修改时才会去执行。
-
# DEBUG
-
# 调试选项, 如需开启,请传入DEBUG = DEBUG_GDB
-
# 根据不同的平台传入不同的编译选项,直接make表示编译X86平台。
-
# 如需要编译海思平台:make PLATFORM=HI_V510 即可
-
###########目标文件的名称##########
-
RELEASE_DIR:=release
-
OBJ_DIR :=.objects/
-
-
EXEC_FILE:=$(RELEASE_DIR)/app
-
-
#############编译平台##########
-
ifeq ($(PLATFORM), HI_X200)
-
COMPILER_PREFIX:=arm-himix200-linux-
-
else ifeq ($(PLATFORM), HI_V510)
-
COMPILER_PREFIX:=arm-hisiv510-linux-
-
else ifeq ($(PLATFORM), ARAGO)
-
COMPILER_PREFIX:=arm-arago-linux-gnueabi-
-
else
-
#X86 PLATFORM
-
CROSS_COMPILER:=
-
endif
-
-
CC := $(COMPILER_PREFIX)gcc
-
CXX := $(COMPILER_PREFIX)g++
-
AR := $(COMPILER_PREFIX)ar
-
LD := $(COMPILER_PREFIX)ld
-
-
-
######指定源文件所在目录
-
SRC_DIR := ./ \
-
./sub \
-
./sub/more \
-
./staticLib \
-
./dynamicLib
-
-
######指定头文件所在目录
-
INCLUDE_DIR := $(SRC_DIR)
-
INCLUDE_DIR += ./include
-
#INCLUDE_DIR += ./sub/more/include
-
-
-
#####指定所依赖的静态库文件
-
STATIC_LIBS := ./staticLib/libstatic.a
-
-
#####指定所依赖的动态库文件如:libtest.so, -L后面带依赖库的路径
-
LDFLAGS+= -L./dynamicLib -ldynamic
-
-
#####指定编译选项
-
USERCPPFLAGS := -ffunction-sections -fdata-sections
-
#USERCPPFLAGS += -mcpu=cortex-a53 -mfloat-abi=hard -mfpu=vfpv3-d16
-
VPATH := $(SRC_DIR)
-
-
CSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.c))
-
CppSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.cpp))
-
-
Objects := $(addprefix $(OBJ_DIR), $(addsuffix .o,$(notdir $(basename $(CSrcs) $(CppSrcs)))))
-
-
CDeps:= $(addsuffix .cdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CSrcs)))))
-
CppDeps := $(addsuffix .cppdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CppSrcs)))))
-
-
CPPFLAGS := -Werror -W $(USERCPPFLAGS)
-
CPPFLAGS += $(addprefix -I,$(INCLUDE_DIR))
-
LDFLAGS += -lpthread -ldl -lrt -lm
-
-
$(EXEC_FILE): $(Objects) $(STATIC_LIBS)
-
$(CXX) $^ -o $@ $(LDFLAGS)
-
@if [ "$(DEBUG)" = "" ];then echo '$(COMPILER_PREFIX)strip $(EXEC_FILE)';$(COMPILER_PREFIX)strip $(EXEC_FILE);fi
-
ifneq ($(MAKECMDGOALS),clean)
-
ifneq ($(MAKECMDGOALS),cleandep)
-
-include $(CDeps)
-
-include $(CppDeps)
-
endif
-
endif
-
-
$(OBJ_DIR)%.cdep: %.c
-
$(create_dep_file)
-
-
$(OBJ_DIR)%.cppdep: %.cpp
-
$(create_dep_file)
-
-
$(OBJ_DIR)%.o:%.c
-
$(CC) $(CPPFLAGS) -c -o $@ $<
-
-
$(OBJ_DIR)%.o:%.cpp
-
$(CXX) $(CPPFLAGS) -c -o $@ $<
-
-
define create_dep_file
-
@if [ ! -e "$(RELEASE_DIR)" ];then mkdir "$(RELEASE_DIR)";fi
-
@if [ ! -e "$(OBJ_DIR)" ];then mkdir "$(OBJ_DIR)"; fi
-
@echo Updating dependance ====\> $@;\
-
rm -f $@; \
-
$(CXX) $(CPPFLAGS) -MM $< | sed 's,$(*F).o:,$(OBJ_DIR)$*.o $@:,g' > $@;
-
endef
-
-
.PHONY: clean
-
clean:
-
-rm $(OBJ_DIR) $(RELEASE_DIR)/* -rf
源码分析:
53行之前都是参数配置,比较简单,主要分析下Makefile中重点部分。
53行-59行:
将SRC_DIR路径的下源文件提取出;如利用main.c构造出带前缀的main.o/main.cdep等字符串。
CSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.c))
CppSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.cpp))
Objects := $(addprefix $(OBJ_DIR), $(addsuffix .o,$(notdir $(basename $(CSrcs) $(CppSrcs)))))
CDeps:= $(addsuffix .cdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CSrcs)))))
CppDeps := $(addsuffix .cppdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CppSrcs)))))
61行:CPPFLAGS指定编译选项,如优化等级。
62行:LDFLAGS指定链接选项
65-66行:生成执行文件命令。
67行:执行strip命令条件判断,strip可以压缩执行文件的大小。
68-73行:将依赖包含进工程。
75-85行,将.c文件生成.o目标文件和.cdeps依赖文件,
92行:$(CXX) $(CPPFLAGS)
-MM $< | sed 's,$(*F).o:,$(OBJ_DIR)$*.o $@:,g' > $@;
利用
-MM 生成依赖;
----------------------------------------分割线-------------------------------
生成动态库的Makefile
动态库的生成主要是编译选项不同,需加上
-fPIC -shared,其他都一样的。
CPPFLAGS := -O2 -Werror -fPIC -shared $(USERCPPFLAGS)
生成静态库的Makefile
静态库则是压缩方式不一样,和我们平时是执行文件并没有本质的区别,所以改一下生成命令即可
$(EXEC_FILE): $(Objects) $(STATIC_LIBS)
@$(AR) rcs $@ $(Objects)
源码中包含了实际应用中绝大部分场景,仅供参考。源码目录如下:
├── Makefile
│ ├── dynamicLib
│ │ ├── dynamic.h
│ │ └── libdynamic.so
│ ├── include
│ │ └── test.h
│ ├── main.cpp
│ ├── Makefile
│ ├── release
│ │ └── app
│ ├── staticLib
│ │ ├── libstatic.a
│ │ └── static.h
│ ├── sub
│ │ ├── more
│ │ │ ├── more.c
│ │ │ └── more.h
│ │ ├── sub.cpp
│ │ └── sub.h
│ └── test.cpp
├── makefile_so
│ ├── comm
│ │ ├── comm.cpp
│ │ └── comm.h
│ ├── dynamic.c
│ ├── include
│ │ └── dynamic.h
│ ├── Makefile
│ └── release
│ └── libdynamic.so
└── makefile_static
├── comm
│ ├── comm.cpp
│ └── comm.h
├── include
│ └── static.h
├── Makefile
├── release
│ └── libstatic.a
└── static.cpp
Makefile目录是生成执行文件的,样例包含了动态库和静态库。
makefile_so是生成动态库的工程。
makefile_static是生成静态库的工程
工程源码下载地址:
GitHub:
百度云: 提取码w69s
阅读(12647) | 评论(0) | 转发(0) |