第21课 - 打造专业的编译环境(中)

21.打造专业的编译环境_链接

21.1.第二阶段任务

  • 完成整个工程的makefile文件

  • 调用makefile编译生成静态库文件

  • 链接所有模块的静态库文件,得到最终的可执行程序

    makefile(08)_打造专业的编译环境

 

21.2.关键的实现要点

  • 如何自动创建build文件夹及其子文件夹?

  • 如何进入每一个模块文件夹进行编译

  • 编译成功后如何链接所有模块静态库

 

21.3.开发中的经验假设

  项目中的各个模块在设计阶段就已经基本确定,因此,在之后的开发过程中模块不会频繁的增加或减少

 

21.4.解决方案设计

  • 1.定义变量保存模块名列表模块名变量

  • 2.利用shell中的for循环遍历模块名变量

  • 3.在for循环进入模块文件夹进行编译

  • 4.循环结束后连接所有的模块静态库文件

21.4.1.Makefile中嵌入shell的for循环

      makefile(08)_打造专业的编译环境

 

21.4.2. 注意事项

  Makefile中嵌入shell代码时,如果需要使用shell变量的值必须在变量前面加$$譬如$$dir,用于区分该变量是shell变量而非Makefile中定义的变量


21.4.3. shell中for循环实验

编程实验:

compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
    @echo "Begin to compile ..."
    @set -e; \
    for dir in $(MODULES); \
    do \
        cd $$dir && $(MAKE) all DEBUG:=$(DEBUG) && cd .. ; \
    done
    @echo "Compile Success!"

 

运行结果:

 

 

工程makefile中的关键构成:编译 + 链接
      makefile(08)_打造专业的编译环境
编译makefile:

.PHONY : all compile

MODULES := common \
           module \
           main

MKDIR := mkdir
RM := rm -fr

DIR_PROJECT := $(realpath .)
DIR_BUILD := build
DIR_BUILD_SUB := $(addprefix $(DIR_BUILD)/, $(MODULES))
MODULE_LIB := $(addsuffix .a, $(MODULES))

compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
    @echo "Begin to compile ..."
    @set -e; \
    for dir in $(MODULES); \
    do \
        cd $$dir && $(MAKE) all DEBUG:=$(DEBUG) && cd .. ; \
    done
    @echo "Compile Success!"

$(DIR_BUILD) $(DIR_BUILD_SUB) : 
    $(MKDIR) $@

输出结果:
    makefile(08)_打造专业的编译环境
    编译成功,在build文件夹下生成了各个模块的打包文件。

 

21.5. 链接时的注意事项

(1)gcc 在进行静态库连接时,必须遵守严格的依赖关系

  • gcc -o app.out x.a y.a

其中的依赖关必须为:x.a -> y.a , y.a -> z.a。默认情况下遵循自左向右的依赖关系。

 

(2)如果不清楚库间的依赖,可以使用-Xlinker自动确定依赖关系

  • gcc -o app.out -Xlinker “-(”z.a y.a x.a -Xlinker”-)”

link $(APP) : $(MODULE_LIB) @echo "Begin to link ..." $(CC) -o $(APP) -Xlinker "-(" $^ -Xlinker "-)" $(LFLAGS) @echo "Link Success!"

 

21.6. 最终方案

.PHONY : all compile link clean rebuild

MODULES := common \
           module \
           main

MKDIR := mkdir
RM := rm -fr

CC := gcc
LFLAGS := 

DIR_PROJECT := $(realpath .)
DIR_BUILD := build
DIR_BUILD_SUB := $(addprefix $(DIR_BUILD)/, $(MODULES))
MODULE_LIB := $(addsuffix .a, $(MODULES))
MODULE_LIB := $(addprefix $(DIR_BUILD)/, $(MODULE_LIB))

APP := app.out
APP := $(addprefix $(DIR_BUILD)/, $(APP))

all : compile $(APP)
    @echo "Success! Target ==> $(APP)"

compile : $(DIR_BUILD) $(DIR_BUILD_SUB)
    @echo "Begin to compile ..."
    @set -e; \
    for dir in $(MODULES); \
    do \
        cd $$dir && $(MAKE) all DEBUG:=$(DEBUG) && cd .. ; \
    done
    @echo "Compile Success!"

link $(APP) : $(MODULE_LIB)
    @echo "Begin to link ..."
    $(CC) -o $(APP) -Xlinker "-(" $^ -Xlinker "-)" $(LFLAGS)
    @echo "Link Success!"

$(DIR_BUILD) $(DIR_BUILD_SUB) : 
    $(MKDIR) $@

clean : 
    @echo "Begin to clean ..."
    $(RM) $(DIR_BUILD)
    @echo "Clean Success!"

rebuild : clean all

运行结果:

 

 

思考:
  当前整个项目的makefile是否存在潜在的问题?是否需要重构

 

posted @ 2019-01-21 23:42  梦心之魂  阅读(202)  评论(0编辑  收藏  举报