第24课

1.问题:如果我们正在进行的项目需要使用第三方库,那么前几节的makefile能胜任吗?

  答案:是否定的。

2.经验假设

本节我们研究第三方库的使用。使makefile支持第三方库。

经验假设:

  • 第三方库通过函数调用的方式提供库中的功能

  • 库文件发布时都附带了声明库函数原型头文件

  • 编译阶段使用头文件链接阶段使用库文件

第三方库在项目中的位置:

    

  libs第三方库一般和其他模块是并列的关系。因此,libs文件夹和commommodule等文件夹是同等地位的。动态链接库静态链接库都有对应的头文件

3.第三方库编译阶段支持

    

注意事项:

    

  实际工程先将第三方库拷贝到编译文件夹再进行链接,libs文件夹和其他模块地位等同,把它当做源文件夹使用,拷贝的结果当做编译结果。

4.第三方库的链接阶段支持

链接阶段:

    

第三方库必须当做最后一个依赖,这是为了处理一种极端的情况:我们的一个子模块和库文件的名字相同。

在这种情况下,我们优先使用自己的模块而不是第三方库模块。

5.代码架构

代码结构:

      

libs/lib下的内容:

      

顶层makefile:

1 include pro-cfg.mk
2 include cmd-cfg.mk
3 include pro-rule.mk

cmd-cfg.mk:

复制代码
 1 AR := ar
 2 ARFLAGS := crs
 3 
 4 CC := gcc
 5 LFLAGS := 
 6 CFLAGS := -I$(DIR_INC) -I$(DIR_COMMON_INC) -I$(DIR_LIBS_INC)
 7 
 8 ifeq ($(DEBUG),true)
 9 CFLAGS += -g
10 endif
11 
12 MKDIR := mkdir
13 RM := rm -fr
14 CP := cp
复制代码

 第六行加上了第三方库相关的支持。

pro-cfg.mk:

复制代码
 1 MODULES := common 
 2            module 
 3            main
 4            
 5 MOD_CFG := mod-cfg.mk
 6 MOD_RULE := mod-rule.mk
 7 CMD_CFG := cmd-cfg.mk
 8 
 9 DIR_BUILD := build
10 DIR_COMMON_INC := common/inc
11 DIR_LIBS_INC := libs/inc
12 DIR_LIBS_LIB := libs/lib
13 
14 APP := app.out
复制代码

 第11、12行新增了第三方库相关的变量。

pro-rule.mk:

复制代码
 1 .PHONY : all compile link clean rebuild $(MODULES)
 2 
 3 DIR_PROJECT := $(realpath .)
 4 DIR_BUILD_SUB := $(addprefix $(DIR_BUILD)/, $(MODULES))
 5 MODULE_LIB := $(addsuffix .a, $(MODULES))
 6 MODULE_LIB := $(addprefix $(DIR_BUILD)/, $(MODULE_LIB))
 7 EXTERNAL_LIB := $(wildcard $(DIR_LIBS_LIB)/*)
 8 EXTERNAL_LIB := $(patsubst $(DIR_LIBS_LIB)/%, $(DIR_BUILD)/%, $(EXTERNAL_LIB))
 9 
10 APP := $(addprefix $(DIR_BUILD)/, $(APP))
11 
12 define makemodule
13     cd $(1) && 
14     $(MAKE) all 
15             DEBUG:=$(DEBUG) 
16             DIR_BUILD:=$(addprefix $(DIR_PROJECT)/, $(DIR_BUILD)) 
17             DIR_COMMON_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_COMMON_INC)) 
18             DIR_LIBS_INC:=$(addprefix $(DIR_PROJECT)/, $(DIR_LIBS_INC)) 
19             CMD_CFG:=$(addprefix $(DIR_PROJECT)/, $(CMD_CFG)) 
20             MOD_CFG:=$(addprefix $(DIR_PROJECT)/, $(MOD_CFG)) 
21             MOD_RULE:=$(addprefix $(DIR_PROJECT)/, $(MOD_RULE)) && 
22     cd .. ; 
23 endef
24 
25 all : compile $(APP)
26     @echo "Success! Target ==> $(APP)"
27 
28 compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
29     @echo "Begin to compile ..."
30     @set -e; 
31     for dir in $(MODULES); 
32     do 
33         $(call makemodule, $$dir) 
34     done
35     @echo "Compile Success!"
36     
37 link $(APP) : $(MODULE_LIB) $(EXTERNAL_LIB)
38     @echo "Begin to link ..."
39     $(CC) -o $(APP) -Xlinker "-(" $^ -Xlinker "-)" $(LFLAGS)
40     @echo "Link Success!"
41     
42 $(DIR_BUILD)/% : $(DIR_LIBS_LIB)/%
43     $(CP) $^ $@
44     
45 $(DIR_BUILD) $(DIR_BUILD_SUB) : 
46     $(MKDIR) $@
47     
48 clean : 
49     @echo "Begin to clean ..."
50     $(RM) $(DIR_BUILD)
51     @echo "Clean Success!"
52     
53 rebuild : clean all
54 
55 $(MODULES) : $(DIR_BUILD) $(DIR_BUILD)/$(MAKECMDGOALS)
56     @echo "Begin to compile $@"
57     @set -e; 
58     $(call makemodule, $@)
59     
复制代码

 第7、8行新增了第三方库文件列表,第18行将第三方库相关的变量传到模块的makefile。第45、46行是库文件的拷贝操作。

mod-cfg.mk:

复制代码
1 DIR_SRC := src
2 DIR_INC := inc
3 
4 TYPE_INC := .h
5 TYPE_SRC := .c
6 TYPE_OBJ := .o
7 TYPE_DEP := .dep
复制代码

mod-rule.mk:

复制代码
 1 .PHONY : all
 2 
 3 MODULE := $(realpath .)
 4 MODULE := $(notdir $(MODULE))
 5 DIR_OUTPUT := $(addprefix $(DIR_BUILD)/, $(MODULE))
 6 
 7 OUTPUT := $(MODULE).a
 8 OUTPUT := $(addprefix $(DIR_BUILD)/, $(OUTPUT))
 9 
10 SRCS := $(wildcard $(DIR_SRC)/*$(TYPE_SRC))
11 OBJS := $(SRCS:$(TYPE_SRC)=$(TYPE_OBJ))
12 OBJS := $(patsubst $(DIR_SRC)/%, $(DIR_OUTPUT)/%, $(OBJS))
13 DEPS := $(SRCS:$(TYPE_SRC)=$(TYPE_DEP))
14 DEPS := $(patsubst $(DIR_SRC)/%, $(DIR_OUTPUT)/%, $(DEPS))
15 
16 vpath %$(TYPE_INC) $(DIR_INC)
17 vpath %$(TYPE_INC) $(DIR_COMMON_INC)
18 vpath %$(TYPE_INC) $(DIR_LIBS_INC)
19 vpath %$(TYPE_SRC) $(DIR_SRC)
20 
21 -include $(DEPS)
22 
23 all : $(OUTPUT)
24     @echo "Success! Target ==> $(OUTPUT)"
25     
26 $(OUTPUT) : $(OBJS)
27     $(AR) $(ARFLAGS) $@ $^
28     
29 $(DIR_OUTPUT)/%$(TYPE_OBJ) : %$(TYPE_SRC)
30     $(CC) $(CFLAGS) -o $@ -c $(filter %$(TYPE_SRC), $^)
31     
32     
33 $(DIR_OUTPUT)/%$(TYPE_DEP) : %$(TYPE_SRC)
34     @echo "Creating $@ ..."
35     @set -e; 
36     $(CC) $(CFLAGS) -MM -E $(filter %$(TYPE_SRC), $^) | sed 's,(.*).o[ :]*,$(DIR_OUTPUT)/1$(TYPE_OBJ) $@ : ,g' > $@
复制代码

common文件夹下的makefile:

复制代码
 1 include $(MOD_CFG)
 2 
 3 # Custmization Begin
 4 # 
 5 # DIR_SRC := src
 6 # DIR_INC := inc
 7 #
 8 # TYPE_INC := .h
 9 # TYPE_SRC := .c
10 # TYPE_OBJ := .o
11 # TYPE_DEP := .dep
12 #
13 # Custmization End
14 
15 include $(CMD_CFG)
16 
17 include $(MOD_RULE)
复制代码

main文件夹下的makefile:

复制代码
 1 include $(MOD_CFG)
 2 
 3 # Custmization Begin
 4 # 
 5 # DIR_SRC := src
 6 # DIR_INC := inc
 7 #
 8 # TYPE_INC := .h
 9 # TYPE_SRC := .c
10 # TYPE_OBJ := .o
11 # TYPE_DEP := .dep
12 #
13 # Custmization End
14 
15 include $(CMD_CFG)
16 
17 include $(MOD_RULE)
复制代码

module文件夹下的makefile:

复制代码
 1 include $(MOD_CFG)
 2 
 3 # Custmization Begin
 4 # 
 5 # DIR_SRC := src
 6 # DIR_INC := inc
 7 #
 8 # TYPE_INC := .h
 9 # TYPE_SRC := .c
10 # TYPE_OBJ := .o
11 # TYPE_DEP := .dep
12 #
13 # Custmization End
14 
15 include $(CMD_CFG)
16 
17 include $(MOD_RULE)
复制代码

如果我们突然不使用第三方库了,则只需删掉libs文件夹下的内容即可,而makefile无需改动。

6.小结:

  • 编译环境必须支持第三方库的使用(静态库或动态库

  • 工程开发中一般会使用特殊的文件夹存放第三方库

  • 第三方库所附带的头文件用于声明库文件(编译阶段需要

  • 链接阶段先将库文件拷贝到build文件夹,在进行链接链接阶段需要

原文地址:https://www.cnblogs.com/hoiday/p/10306649.html