Chinaunix首页 | 论坛 | 博客
  • 博客访问: 675650
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 95
  • 用 户 组: 普通用户
  • 注册时间: 2019-03-06 14:11
个人简介

我,并不比别人差。

文章分类
文章存档

2021年(1)

2020年(2)

2019年(3)

我的朋友

分类: LINUX

2020-03-29 18:17:31

  Makefile是Linux平台大型工程中必不可少的一部分。其重要性不言而喻,详细的概念这里就不再累赘,直接进入主题。

  本文给出三个Makefile样例,分别是生成执行文件、生成静态库和生成动态库的Makefile。三者主要是生成的命令不一样,其他规则相同。

  代码拿到后,只需做很简单的修改即可融入现有工程中。主要配置源码路径、编译工具链、编译参数、链接参数。

  需要说明的是,该Makefile模板的优点在于,添加或删除文件时,不需要修改Makefile,并且整个工程只有一个Makefile文件。修改头文件时,也不需要从头make clean,这在大型项目中可以节省很多编译时间。只有在增加新的目录时,才需要修改Makefile。支持多平台编译,根据传进来的参数选择不同的编译工具。有优点就有缺点,最大的缺点在于不可以选择性编译,也就是所有在工程中的源文件和库文件,都会编译进来。

  先来看看生成执行文件的Makefile:
概念快速扫盲:$@ 表示目标文件;$^ 表示所有的依赖文件;$< 表示第一个依赖文件
命令执行必要条件是,文件比依赖新时,也就是文件有修改时才会去执行。

点击(此处)折叠或打开

  1. # DEBUG
  2. #    调试选项, 如需开启,请传入DEBUG = DEBUG_GDB
  3. # 根据不同的平台传入不同的编译选项,直接make表示编译X86平台。
  4. # 如需要编译海思平台:make PLATFORM=HI_V510 即可
  5. ###########目标文件的名称##########
  6. RELEASE_DIR:=release
  7. OBJ_DIR :=.objects/

  8. EXEC_FILE:=$(RELEASE_DIR)/app

  9. #############编译平台##########
  10. ifeq ($(PLATFORM), HI_X200)
  11.     COMPILER_PREFIX:=arm-himix200-linux-
  12. else ifeq ($(PLATFORM), HI_V510)
  13.     COMPILER_PREFIX:=arm-hisiv510-linux-
  14. else ifeq ($(PLATFORM), ARAGO)
  15.     COMPILER_PREFIX:=arm-arago-linux-gnueabi-
  16. else
  17.     #X86 PLATFORM
  18.     CROSS_COMPILER:=
  19. endif

  20. CC := $(COMPILER_PREFIX)gcc
  21. CXX := $(COMPILER_PREFIX)g++
  22. AR := $(COMPILER_PREFIX)ar
  23. LD := $(COMPILER_PREFIX)ld


  24. ######指定源文件所在目录
  25. SRC_DIR := ./ \
  26.           ./sub \
  27.           ./sub/more \
  28.      ./staticLib \
  29.      ./dynamicLib

  30. ######指定头文件所在目录
  31. INCLUDE_DIR := $(SRC_DIR)
  32. INCLUDE_DIR += ./include
  33. #INCLUDE_DIR += ./sub/more/include


  34. #####指定所依赖的静态库文件
  35. STATIC_LIBS := ./staticLib/libstatic.a

  36. #####指定所依赖的动态库文件如:libtest.so, -L后面带依赖库的路径
  37. LDFLAGS+= -L./dynamicLib -ldynamic

  38. #####指定编译选项
  39. USERCPPFLAGS := -ffunction-sections -fdata-sections
  40. #USERCPPFLAGS += -mcpu=cortex-a53 -mfloat-abi=hard -mfpu=vfpv3-d16
  41. VPATH := $(SRC_DIR)

  42. CSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.c))
  43. CppSrcs := $(foreach CurDir,$(SRC_DIR),$(wildcard $(CurDir)/*.cpp))

  44. Objects := $(addprefix $(OBJ_DIR), $(addsuffix .o,$(notdir $(basename $(CSrcs) $(CppSrcs)))))

  45. CDeps:= $(addsuffix .cdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CSrcs)))))
  46. CppDeps := $(addsuffix .cppdep, $(addprefix $(OBJ_DIR), $(basename $(notdir $(CppSrcs)))))

  47. CPPFLAGS := -Werror -W $(USERCPPFLAGS)
  48. CPPFLAGS += $(addprefix -I,$(INCLUDE_DIR))
  49. LDFLAGS += -lpthread -ldl -lrt -lm

  50. $(EXEC_FILE): $(Objects) $(STATIC_LIBS)
  51.     $(CXX) $^ -o $@ $(LDFLAGS)
  52.     @if [ "$(DEBUG)" = "" ];then echo '$(COMPILER_PREFIX)strip $(EXEC_FILE)';$(COMPILER_PREFIX)strip $(EXEC_FILE);fi
  53. ifneq ($(MAKECMDGOALS),clean)
  54. ifneq ($(MAKECMDGOALS),cleandep)
  55. -include $(CDeps)
  56. -include $(CppDeps)
  57. endif
  58. endif

  59. $(OBJ_DIR)%.cdep: %.c
  60.     $(create_dep_file)

  61. $(OBJ_DIR)%.cppdep: %.cpp
  62.     $(create_dep_file)

  63. $(OBJ_DIR)%.o:%.c
  64.     $(CC) $(CPPFLAGS) -c -o $@ $<

  65. $(OBJ_DIR)%.o:%.cpp
  66.     $(CXX) $(CPPFLAGS) -c -o $@ $<

  67. define create_dep_file
  68.     @if [ ! -e "$(RELEASE_DIR)" ];then mkdir "$(RELEASE_DIR)";fi
  69.     @if [ ! -e "$(OBJ_DIR)" ];then mkdir "$(OBJ_DIR)"; fi
  70.     @echo Updating dependance ====\> $@;\
  71.     rm -f $@; \
  72.     $(CXX) $(CPPFLAGS) -MM $< | sed 's,$(*F).o:,$(OBJ_DIR)$*.o $@:,g' > $@;
  73. endef

  74. .PHONY: clean
  75. clean:
  76.     -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) |
给主人留下些什么吧!~~