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

时间:2013-04-17 11:21:03

标签: c++ makefile code-generation

我有一个脚本,它根据配置文件生成多个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重新制作,我为生成的Makefile.inc包含了一个目标规则,所以如果Makefile.inc(配置文件)的依赖关系比Makefile.inc更新,那么重新生成,Make将重新启动。

所以这就是目标:

  1. 检查是否需要(重新)生成Makefile.inc。
  2. 包括它
  3. 在Makefile中的$ LIBOBJS变量中使用Makefile.inc中的变量。
  4. 这实际上有效。如果我更新messages.conf文件,Make会检测到它,并将运行python脚本。然后它将重新启动,包含新的Makefile.inc,然后继续编译。

    但是这部分不起作用:如果我更新messages.conf文件,但只有.h或.cpp文件默认位于$ LIBOBJS列表中,Make将不会继续编译。

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

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

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

    谁知道造成这种情况的原因,可能是什么解决方案?是否有更好的方法来使用makefile处理代码生成?

    提前致谢。

    注意:我也使用gcc生成的依赖文件,并且在我添加代码生成之前工作正常,所以我认为这不是问题。

2 个答案:

答案 0 :(得分:2)

您需要在all之前移动include目标。 Make总是构建它在makefile中看到的第一个目标,除非你在命令行上给出一个特定的目标。由于include位于任何目标之前,因此Makefile.inc中定义的第一个目标将成为默认目标,并且当您运行make时,将构建该目标。这就是为什么它试图构建exceptions.o然后停止。如果您明确地运行make all,它将按预期运行。

答案 1 :(得分:0)

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