Makefile 目标始终与代码生成保持同步

Posted

技术标签:

【中文标题】Makefile 目标始终与代码生成保持同步【英文标题】:Makefile target always up to date with code generation 【发布时间】:2013-04-17 11:21:03 【问题描述】:

我有一个基于配置文件生成多个 C++ .h 和 .cpp 文件的脚本。该脚本还会生成一个名为“Makefile.inc”的文件,该文件包含一个具有所需目标文件名的变量,用于生成的 .cpp 文件。

Makefile.inc 文件示例(所有路径都是绝对路径):

MESSAGE_OBJS = \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/error-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/challenge-request-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/challenge-response-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/login-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/get-game-list-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/game-list-response-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/join-game-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/connect-to-game-message.o \
    /scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/leave-game-message.o 

Using the answer in this question as base,我创建了以下 Makefile:

# Include the generated makefile for messages.
# This includes a variable with all message targets
include atlarge/messages/Makefile.inc

# Create a variable with all source targets
LIBOBJS = \
    atlarge/exceptions.o \
    atlarge/message-factory.o \
    atlarge/envelope.o \
    atlarge/client.o \
    atlarge/user.o \
    atlarge/atlarge-protocol.o \
    atlarge/atlarge-gameserver.o \
    $(MESSAGE_OBJS)


CXXFLAGS += -W -Wall -I. -g -O3 -MD \
    `pkg-config jansson --cflags` \
    `libgcrypt-config --cflags` \
    `pkg-config glib-2.0 --cflags` \
    -fPIC -DDEBUG -DENABLE_LOGGING

PREFIX = /usr/local

# TODO use pkg-config for jansson
LDLIBS += -lm -ljansson -latlarge-util `libgcrypt-config --libs` `pkg-config glib-2.0 --libs` 
LDFLAGS += -shared -L/usr/local/lib

# Include automatically generated dependencies
-include $(LIBOBJS:.o=.d)

all: libatlarge.so

# If the message Makefile doesn't exist yet, generate it
atlarge/messages/Makefile.inc: atlarge/messages/messages.conf
    python ../common/messagegen.py -o ./atlarge/messages/ atlarge/messages/messages.conf

libatlarge.so: $(LIBOBJS)
    $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)

clean:
    @rm -f *.o
    @rm -f atlarge/*.o
    @rm -f atlarge/messages/*.o
    @rm -f atlarge/messages/*.cpp
    @rm -f atlarge/messages/*.h
    @rm -f atlarge/messages/Makefile.inc
    @rm -f atlarge/*.d
    @rm -f atlarge/messages/*.d
    @rm -f *.d
    @rm -f ../common/*.d
    @rm -f ../common/*.o
    @rm -f *.a
    @rm -f *.so
    @rm -f tags

install: libatlarge.so
    @install -m 0644 $^ $(PREFIX)/lib
    @install -m 0755 -d $(PREFIX)/include/atlarge
    @install -m 0755 -d $(PREFIX)/include/atlarge/messages
    @install -m 0644 -D atlarge/*.h $(PREFIX)/include/atlarge
    @install -m 0644 -D atlarge/messages/*.h $(PREFIX)/include/atlarge/messages
    @ldconfig
    @echo "Installed"


.PHONY: all clean install splint messages

如您所见,我首先包含生成的 Makefile.inc。然后定义一个包含所有库对象文件的变量,该变量使用生成的 Makefile.inc 中声明的变量。然后声明一些带有编译器标志的变量。

为了利用Makefile remaking,我为生成的 Makefile.inc 添加了一个目标规则,所以如果 Makefile.inc(配置文件)的依赖比 Makefile.inc 更新,它重新生成,Make 将自行重启。

所以这是目标:

    检查是否需要(重新)生成 Makefile.inc。 包含它 在主 Makefile 的 $LIBOBJS 变量中使用 Makefile.inc 中的变量。

这确实有效。如果我更新 messages.conf 文件,Make 会检测到这一点,并将运行 python 脚本。然后它将自行重启,包含新的 Makefile.inc,然后继续编译。

但是这里出现了不起作用的部分:如果我更新 messages.conf 文件,但只更新默认情况下在 $LIBOBJS 列表中的 .h 或 .cpp 文件, Make 不会继续编译。

例如,如果更改 client.cpp 而没有其他文件,我会收到以下错误:

make: `atlarge/exceptions.o' is up to date.

嗯,很好,你发现 exceptions.o 是最新的,但我更改了 client.cpp,那你为什么不开始编译那个呢?为什么 make 看到 LIBOBJS 中的第一个目标是最新的后立即退出?

谁知道是什么原因造成的,有什么解决办法?是否有更好的方法来使用 makefile 处理代码生成?

提前致谢。

注意:我也使用 gcc 生成的依赖文件,在我添加代码生成之前运行良好,所以我认为这不是问题。

【问题讨论】:

【参考方案1】:

您需要将all 目标移动到include 之前。 Make 总是构建它在 makefile 中看到的第一个目标,除非你在命令行上给出一个特定的目标。由于include 出现在任何目标之前,Makefile.inc 中定义的第一个目标将是默认目标,当您运行make 时,它将被构建。这就是它尝试构建exceptions.o 然后停止的原因。如果您显式运行make all,它将按预期工作。

【讨论】:

谢谢,解决了。现在看起来很明显。【参考方案2】:

目标文件对源文件的依赖关系在哪里 还是头文件? 一个隐含的规则,应该 如果.cpp 文件在同一个文件中,则获取依赖项 目录为.o,但如果不是,则必须 提供您自己的,或使用 VPATH(参见手册中的第 4.5.1 节)。和 您还需要为包含生成依赖项,请参阅 §4.1.4 在手册中。

【讨论】:

GCC生成的所有依赖文件都在原文件的同一目录下。所以例如client.cpp在同一个目录下有一个依赖文件client.d。我认为依赖文件不是问题。如果原始文件编译,它们会自动生成,并且内容看起来也很好。

以上是关于Makefile 目标始终与代码生成保持同步的主要内容,如果未能解决你的问题,请参考以下文章

检查拉取请求是不是与目标分支保持同步

Swagger笔记

makefile文件详解

保持引导日期选择器始终打开

Swagger使用总结(十九)

保持存档表结构(列等)与实时表同步