使用Makefile编译头文件依赖关系

4

我正在使用C语言编写一个UDP客户端服务器应用程序; 当依赖关系发生变化时,我想自动编译2个源文件和3个头文件,因此我决定使用make工具。

makefile的目标称为"edit"

    edit : server_UDP.o  client_UDP.o \
            gcc -o edit server_UDP.o  client_UDP.o \


    client_UDP.o : client_UDP.c cliHeader_UDP.h  wrapHeader.h
            gcc -c client_UDP.c

    server_UDP.o : server_UDP.c servHeader_UDP.h  wrapHeader.h
            gcc -c  server_UDP.c

当我在wrapHeader.h中更改几行代码时,它不会触发重新编译。

当wrapHeader.h发生更改时,如何修改编辑makefile规则以重新编译server_UDP和client_UDP?

**注意:wrapHeader.h是主头文件。

cliHeader_UDP.h:包括“wrapHeader.h”

servHeader_UDP.h:包括“wrapHeader.h”


1
无论是gcc还是Gnu make都有一个极好的功能集,当它们一起设置工作时,将会精确地做到您想要的事情。gcc -MM编译器开关将几乎为您生成一个与make兼容的目标。有关如何完成此操作以及一些示例代码,请参阅gnu make的在线文档此网站,特别注意此部分 - WhozCraig
可能是[Makefile,头文件依赖关系]的重复问题(https://dev59.com/NnE95IYBdhLWcg3wPrgI) - Ciro Santilli OurBigBook.com
2个回答

2
我认为您需要的是生成依赖文件。
您可以使用“-MMD -MP”参数指定编译器为您生成依赖文件,它会在源文件所在的文件夹中创建一个与源文件同名但扩展名为*.d的新文件。
依赖文件包含代码所依赖的所有头文件,这将导致GNU make在修改所使用的头文件时编译您的源文件。
下面是一个启用了依赖文件的示例makefile:
# Makefile

CC   := gcc
LD   := g++

# The output executable.
BIN   := program

# Toolchain arguments.
CFLAGS    := 
CXXFLAGS  := $(CFLAGS)
LDFLAGS   := 

# Project sources.
C_SOURCE_FILES := mysourcefile1.c src/myothersrc.c
C_OBJECT_FILES := $(patsubst %.c,%.o,$(C_SOURCE_FILES))

# The dependency file names.
DEPS := $(C_OBJECT_FILES:.o=.d)

all: $(BIN)

clean:
    $(RM) $(C_OBJECT_FILES) $(DEPS) $(BIN)

rebuild: clean all

$(BIN): $(C_OBJECT_FILES)
    $(LD) $(C_OBJECT_FILES) $(LDFLAGS) -o $@

%.o: %.c
    $(CC) -c -MMD -MP $< -o $@ $(CFLAGS)

# Let make read the dependency files and handle them.
-include $(DEPS)

这应该适用于您的情况:
SOURCES := server_UDP.c client_UDP.c
OBJECTS := $(patsubst %.c,%.o,$(SOURCES))

DEPS := $(OBJECTS:.o=.d)

edit: $(OBJECTS)
    gcc -o edit $(OBJECTS)

%.o: %.c
    gcc -c $< -o $@

-include $(DEPS)

我浏览了这些有用的链接,但是由于我对Makefile实用程序还很陌生,所以并没有完全理解。Dylan McKay,能否在我的编辑文件中提供一个示例,以便更好地理解如何放置代码,因为我感到困惑... - zak
但我想更深入地了解Makefile,什么是patsubst,以及OBJECTS:= $(patsubst%.c,%.o,$(SOURCES))的含义。DEPS:= $(OBJECTS:.o = .d) - zak
patsubst 是 GNU make 提供的一个函数,用于将一个模式替换为另一个模式。当你调用 $(patsubst %.c,%.o,$(SOURCES)) 时,实际上是将 "SOURCES" 变量中每个文件的 .c 扩展名替换为 .o。 - Dylan
deps的作用基本上与DEPS:=(OBJECTS:.o = .d)相同,实际上,您可以使用patsubst创建一个执行相同操作的语句。 $(OBJECTS:.o = .d)表达式只是在“OBJECTS”变量中将“.o”替换为“.d”。 - Dylan
谢谢你的帮助,但它仍然不能按照我想要的方式工作。当我更改wrapperHeader时,没有任何变化,我可以把文件发送给您测试一下吗?昨天我尝试了3小时30分钟,但结果仍然相同...如果您能帮忙,那将是非常大的帮助。 - zak
看看这个GNU Make文档的示例,严肃点,sed如何与-MM结合使用以创建一个多目标规则file.o file.d : file.c。这很重要,因为如果.c文件发生更改,.o和依赖项.d文件都将重新构建,一旦构建了.d文件,其中的头文件的任何未来更新都会触发.o的新构建。此外,向.c文件添加新的#include也会重新生成.d文件。我已经广泛使用它,它真的非常好用。 - WhozCraig

0

你没有说edit.c是否包含你的两个特定头文件,但我猜如果它链接到对象,那么它必须包含。

这正是makepp发挥其优势的场景之一:如果你遵循每个.o文件都需要链接一个相应名称的include语句的约定(在你的情况下,这将是client_UDP.hserver_UDP.h),那么makepp将自动解决所有问题,除了检测头文件作为依赖项。

这甚至可以递归地工作,所以如果你有一个wrapHeader.c(其中在edit.c中没有相应的include语句),那么它会自动编译和链接。

所以你不需要一个makefile。但如果你想避免每次调用makepp edit,那么你可以创建一个一行命令。

edit:

如果您只是有一些简单需求的话,学习make语法就足够了。但如果您需要更复杂的需求,那也不用担心,GNU make几乎可以做到所有事情。此外,还有很多其他有用的功能,您甚至可以通过一些Perl编程来扩展您的makefile。


该文件是用于Makefile命令的,client_UDP和server_udp不是头文件,而是它们的源代码。 - zak
抱歉,我不理解你在说什么。如果你想讨论更多,请前往我们的 sourceforge 论坛,我们可以在那里进行讨论。如果你更喜欢说世界语、德语或法语,也可以在那里使用这些语言。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接