根据前面所运行结果,main.o 被正确地生成了,但在链接时因为找不到 foo() 函数的实现而出现错误。由于 foo() 函数的实现是放在 libfoo.a 库中的,而 Makefile 中并没有告诉编译器在生成 huge.exe 时需要与 libfoo.a 库链接在一起
huge / build / make.rule
.PHONY : all clean
NKDIR = mkdir
RM = rm
RMFLAG = -rf
CC = gcc
AR = ar
ARFLAG = crs
DIR_OBJS = objs
DIR_EXES = $(ROOT)/build/exes
DIR_DEPS = deps
DIR_LIBS = $(ROOT)/build/libs
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) $(DIR_LIBS)
RMS = $(DIR_OBJS) $(DIR_DEPS)
ifneq("$(EXE)", "")
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
RMS += $(EXE)
endif
ifneq("$(LIB)", "")
LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
RMS += $(LIB)
endif
SRCS = $(wildcard *.c)
OBJS = $(SRCS :.c = .o)
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS :.c = .dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
ifeq("$(wildcard $(DIR_OBJS))", "")
DEP_DIR_OBJS := $(DIR_OBJS)
endif
ifeq("$(wildcard $(DIR_EXES))", "")
DEP_DIR_EXES := $(DIR_EXES)
endif
ifeq("$(wildcard $(DIR_DEPS))", "")
DEP_DIR_DEPS := $(DIR_DEPS)
endif
ifeq("$(wildcard $(DIR_LIBS))", "")
DEP_DIR_LIBS := $(DIR_LIBS)
endif
all : $(EXE) $(LIB)
ifneq($MAKECMDGOALS, clean)
include $(DEPS)
endif
ifneq($(INCLUDE_DIRS), "")
INCLUDE_DIRS := $(strips $(INCLUDE_DIRS))
INCLUDE_DIRS := $(addprefix -I, $(INCLUDE_DIRS))
endif
ifneq($(LINK_LIBS), "")
LINK_LIBS := $(strip $(LINK_LIBS))
LINK_LIBS := $(addprefix -l, $(LINK_LIBS))
endif
$(DIRS) :
$(MKDIR) $@
$(EXE) : $(DEP_DIR_EXE) $(OBJS)
$(CC) -L$(DIR_LIBS) -o $@ $(filter %.o, $^)
$(LIB) : $(DEP_DIR_LIB) $(OBJS)
$(AR) $(ARFLAG) $@ $(filter %.o, $^)
$(DIR_OBJS) / %.o : $(DEP_DIR_OBJS) %.c
$(CC) $(INCLUDE_DIRS) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS) / %.dep : $(DEP_DIR_DEPS) %.c
@echo "Creating $@ ..."
@set -e;\
$(RM) $(RMFLAG) $@.tmp;\
$(CC) $(INCLUDE_DIRS) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[ :]*,objs/\1.o $@: ,g' < $@.tmp > $@;\
$(RM) $(RMFLAG) $@.tmp
clean :
$(RM) $(RMFLAG) $(RMS)
huge / code / foo / src / Makefile
EXE =
LIB = libfoo.a
INCLUDE_DIRS = $(ROOT)/code/foo/inc
LINK_LIBS =
include $(ROOT)/build/make.rule
huge / code / huge / src / Makefile
EXE = huge.exe
LIB =
INCLUDE_DIRS = $(ROOT)/code/foo/inc
LINK_LIBS = foo
include $(ROOT)/build/make.rule
其中改动如下:
- 增加 LINK_LIBS 变量, 用于存放可执行程序在链接时所需的所有库
- 将 $(DIR_LIBS) 通过 gcc 的 -L 选项加入到编译器的库搜索目录列表中。在 huge 项目中,将所有的库文件都放到 DIR_LIBS 目录下,简化了 Makefile 的实现
- 在各模块的 src 目录下的 Makefile 中增加了 LINK_LIBS 变量的定义, 且在 code / huge / src / Makefile 中对 LINK_LIBS 赋值为 foo。
运行结果:
$ make
/Makefile/huge/build/make.rule:43: deps / foo.dep:No such file or directory
mkdir deps
Creating deps / foo.dep
mkdir objs
gcc -I/Makefile/huge/code/foo/libs/inc -o objs/foo.o -c foo.c
gcc -L/Makefile/huge/build/libs -o /Makefile/huge/build/exes/huge.exe objs/main.o -lfoo
$ $ROOT/build/exes/huge.exe
This is foo ()!
现在,往 huge 项目中增加一个 bar 模块,这个模块将生成 libbar.a 静态库
huge / code / bar / inc / bar.h
#ifndef __BAR_H
#define __BAR_H
void bar();
#endif
huge / code / bar / inc / bar.c
#include <stdio.h>
#include "bar.h"
void bar()
{
printf("This is bar ()!\n");
}
huge / code / bar / src / Makefile
EXE =
LIB = libbar.a
INCLUDE_DIRS = $(ROOT)/code/bar/inc
LINK_LIBS =
include $(ROOT)/build/make.rule
新增目录结构:
为了构建 libbar.a,需要进入 code / bar / src 目录并运行 make 命令
$ make
/Makefile/huge/build/make.rule:43: deps / bar.dep:No such file or directory
mkdir deps
Creating deps / bar.dep
mkdir objs
gcc -I/Makefile/huge/code/bar/libs/inc -o objs/bar.o -c bar.c
ar crs /Makefile/huge/build/libs/libbar.a objs/bar.o
$ ls $ROOT/build/libs
libfoo.a libbar.a
在前面 code / huge / src / Makefile 的基础上,作以下改动:
huge / code / huge / src / main.c
#include "foo.h"
#include "bar.h"
int main()
{
foo();
bar();
return 0;
}
huge / code / huge / src / Makefile
EXE = huge.exe
LIB =
INCLUDE_DIRS = $(ROOT)/code/foo/inc \
$(ROOT)/code/foo/inc
LINK_LIBS = foo bar
incldue $(ROOT)/build/make.rule
运行结果:
/Makefile/huge/code/huge/src
$ make
Creating deps / main.dep ...
gcc -I/Makefile/huge/code/foo/inc -I/Makefile/huge/code/bar/inc -o objs/main.o -c main.c
gcc -L/Makefile/huge/build/libs -o /Makefile/huge/build/exes/huge.exe objs/main.o -lfoo -lbar
$ $ROOT/build/exes/huge.exe
This is foo ()!
This is bar()!
参考文献:《专业嵌入式软件开发》李云·著
2016年7月5日,星期二