Makefile 编译所有 src 并生成静态库

Posted

技术标签:

【中文标题】Makefile 编译所有 src 并生成静态库【英文标题】:Makefile to compile all src and generate static library 【发布时间】:2020-03-08 18:21:20 【问题描述】:

我有一个大型 C 项目,我想使用我的 include/ 路径中的包含以及我的 RTOS 的其他一些包含,从 src/ 文件中的所有源生成一个静态库。

我在行命令中有一组工作步骤:

gcc src/drivers/* src/packets/* (...more files) -c -I ./include -I ../SatelliteSim/Source/include/ -I ../SatelliteSim/Project/ -I ../SatelliteSim/Source/portable/GCC/POSIX/ -m32 -DDEBUG=1 -g -UUSE_STDIO -D__GCC_POSIX__=1 -pthread

那么,ar -rsc telecommands.a *.o

我目前对 Makefile 的尝试如下所示:

CXXFLAGS := -I./include -I../SatelliteSim/Source/include/ -I../SatelliteSim/Project/ -I../SatelliteSim/Source/portable/GCC/POSIX/ -m32 -DDEBUG=1 -g -UUSE_STDIO -D__GCC_POSIX__=1 -pthread


MODULES := commands/commands \
    driver_toolkit/driver_toolkit \
    (... more 'modules')

SOURCES := src/$(MODULES).c
OBJS := bin/$(MODULES).o

all: telecommands.a

telecommands.a: $(OBJS)
    ar -rsc $@ $^

$(OBJS): $(SOURCES)
    $(CXX) $(CXXFLAGS) -c $^ -o $@

但是我在编译步骤中遇到了我的包含文件的问题。

希望有人能指出我做错了什么:)

提前致谢!

【问题讨论】:

【参考方案1】:

你至少有两个主要问题。

首先是你的SOURCESOBJS 变量赋值错误。 Make 在扩展变量时会直接进行文本替换。所以:

MODULES := foo bar biz

SOURCES := src/$(MODULES).c
OBJS := bin/$(MODULES).o

扩展为:

SOURCES := src/foo bar biz.c
OBJS := bin/foo bar biz.o

这显然是不对的。如果您愿意使用 GNU make-specific 函数,这些函数单独对变量中的每个 word 进行操作,您可以获得您想要的:

SOURCES := $(patsubst %,src/%.c,$(MODULES))
OBJS := $(patubst %,bin/%.o,$(MODULES))

你遇到的下一个问题是:

$(OBJS): $(SOURCES)
        $(CXX) $(CXXFLAGS) -c $^ -o $@

扩展为这样的:

bin/foo.o bin/bar.o bin/biz.o : src/foo.c src/bar.c src/biz.c
        $(CXX) $(CXXFLAGS) -c $^ -o $@

同样,make 不会以某种方式推断您希望左侧的每个目标文件都以某种方式与右侧的某个源文件匹配,使用一些字符串匹配启发式。这不是 make 的工作方式。如果左侧有多个目标,make 会为每个目标创建一个单独的规则,其中每个目标都包含右侧的所有先决条件。所以上面的内容和你写的一样:

bin/foo.o : src/foo.c src/bar.c src/biz.c
        $(CXX) $(CXXFLAGS) -c $^ -o $@
bin/bar.o : src/foo.c src/bar.c src/biz.c
        $(CXX) $(CXXFLAGS) -c $^ -o $@
bin/biz.o : src/foo.c src/bar.c src/biz.c
        $(CXX) $(CXXFLAGS) -c $^ -o $@

这意味着它将编译所有源文件以创建每个目标文件。

在 makefile 中,您必须编写一个规则,根据该目标的先决条件一次构建 一个 目标。因此,例如,您可以使用模式规则:

bin/%.o : src/%.c
        $(CXX) $(CXXFLAGS) -c $< -o $@

注意我使用$&lt; 而不是$^ 因为你只想编译源文件。请注意,这会为每个源文件调用一次编译器,以生成该输出文件。 Make 不适合单次调用构建工具生成许多不同输出的环境(尽管如果您愿意将自己限制在 GNU make 版本 4.3 或更高版本,您可以根据需要这样做)。

如果标题发生更改,这将不会重建任何目标文件,因为您没有将任何标题列为先决条件。

您提到在编译步骤中遇到了我的包含文件问题,但这对我们没有帮助。如果您在修复 makefile 后仍有编译问题,您可以打开一个新问题,但请准确包含(剪切和粘贴)您看到的错误类型以及生成这些错误的打印行。

【讨论】:

以上是关于Makefile 编译所有 src 并生成静态库的主要内容,如果未能解决你的问题,请参考以下文章

Makefile 到 CMakeLists.txt

makefile 交叉编译怎么引用静态库

怎么编写Makefile生成静态库

makefile -- 动态库、进程

Makefile学习----生成静态库文件

Makefile循环依赖错误