Makefile,头依赖项

Mik*_*ike 90 dependencies makefile header-files

假设我有一个带有规则的makefile

%.o: %.c
 gcc -Wall -Iinclude ...
Run Code Online (Sandbox Code Playgroud)

我想要在头文件更改时重建*.o.无论何时/include更改任何头文件,都必须重建dir中的所有对象,而不是计算出依赖项列表.

我想不出一个改变规则以适应这个的好方法,我愿意接受建议.如果标题列表不必硬编码,则奖励积分

dmc*_*kee 113

如果您使用的是GNU编译器,编译器可以为您组装一个依赖项列表.Makefile片段:

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ -MF  ./.depend;

include .depend
Run Code Online (Sandbox Code Playgroud)

要么

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ > ./.depend;

include .depend
Run Code Online (Sandbox Code Playgroud)

where SRCS是指向整个源文件列表的变量.

还有工具makedepend,但我从来都不喜欢它gcc -MM

  • 是否可以在每个文件之前添加一些前缀来表明它在另一个目录中,例如`build/file.o`? (4认同)
  • 我喜欢这个技巧,但是只有当源文件发生变化时我才能让`depend`运行?无论如何,它似乎每次都在运行...... (2认同)
  • @chase:嗯,我错误地依赖于目标文件,当它显然应该在源上并且两个目标的依赖顺序错误时也是如此.这就是我从内存中输入的内容.现在就试试. (2认同)
  • 为什么需要分号?如果我尝试不使用它,或者不使用-MF ./.depend作为最后一个参数,它将仅将最后一个文件的依赖项保存在$(SRCS)中。 (2认同)

Sop*_*hie 63

大多数答案都令人惊讶地复杂或错误.然而,其他地方已经发布了简单而强大的示例[ codereview ].不可否认,gnu预处理器提供的选项有点令人困惑.但是,记录了从构建目标中删除所有目录,-MM而不是bug [ gpp ]:

默认情况下,CPP获取主输入文件的名称,删除任何 目录组件和任何文件后缀(如".c"),并附加平台的常用对象后缀.

(稍微更新)-MMD选项可能是你想要的.为了完整性,支持多个src目录并使用一些注释构建目录的makefile示例.对于没有构建目录的简单版本,请参阅[ codereview ].

CXX = clang++
CXX_FLAGS = -Wfatal-errors -Wall -Wextra -Wpedantic -Wconversion -Wshadow

# Final binary
BIN = mybin
# Put all auto generated stuff to this build dir.
BUILD_DIR = ./build

# List of all .cpp source files.
CPP = main.cpp $(wildcard dir1/*.cpp) $(wildcard dir2/*.cpp)

# All .o files go to build dir.
OBJ = $(CPP:%.cpp=$(BUILD_DIR)/%.o)
# Gcc/Clang will create these .d files containing dependencies.
DEP = $(OBJ:%.o=%.d)

# Default target named after the binary.
$(BIN) : $(BUILD_DIR)/$(BIN)

# Actual target of the binary - depends on all .o files.
$(BUILD_DIR)/$(BIN) : $(OBJ)
    # Create build directories - same structure as sources.
    mkdir -p $(@D)
    # Just link all the object files.
    $(CXX) $(CXX_FLAGS) $^ -o $@

# Include all .d files
-include $(DEP)

# Build target for every single object file.
# The potential dependency on header files is covered
# by calling `-include $(DEP)`.
$(BUILD_DIR)/%.o : %.cpp
    mkdir -p $(@D)
    # The -MMD flags additionaly creates a .d file with
    # the same name as the .o file.
    $(CXX) $(CXX_FLAGS) -MMD -c $< -o $@

.PHONY : clean
clean :
    # This should remove all generated files.
    -rm $(BUILD_DIR)/$(BIN) $(OBJ) $(DEP)
Run Code Online (Sandbox Code Playgroud)

此方法有效,因为如果单个目标有多个依赖关系,则只需连接依赖关系,例如:

a.o: a.h
a.o: a.c
    ./cmd
Run Code Online (Sandbox Code Playgroud)

相当于:

a.o: a.c a.h
    ./cmd
Run Code Online (Sandbox Code Playgroud)

如上所述:Makefile为单个目标的多个依赖关系?

  • OBJ 变量值存在拼写错误:`CPP` 应为 `CPPS` (2认同)

Mar*_*ido 25

正如我在这里发布的那样gcc可以创建依赖项并同时编译:

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

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MF $(patsubst %.o,%.d,$@) -o $@ $<
Run Code Online (Sandbox Code Playgroud)

'-MF'参数指定用于存储依赖项的文件.

'-include'开头的破折号告诉Make在.d文件不存在时继续(例如在第一次编译时).

注意gcc中似乎存在关于-o选项的错误.如果将对象文件名设置为obj/_file__c.o,则生成的文件 .d仍将包含文件 .o,而不是obj/_file__c.o.

  • 当我尝试这个时,它导致我的所有.o文件被创建为空文件.我确实在构建子文件夹中有我的对象(所以$ OBJECTS包含build/main.o build/smbus.o build/etc ...)并且肯定会创建.d文件,如您所描述的明显的bug,但它肯定根本没有构建.o文件,而如果我删除-MM和-MF则会这样做. (4认同)
  • @bobpaul因为`man gcc`说`-MM`意味着`-E`,"在预处理后停止".你需要`-MMD`:http://stackoverflow.com/a/30142139/895245 (3认同)

Mic*_*son 23

怎么样的:

includes = $(wildcard include/*.h)

%.o: %.c ${includes}
    gcc -Wall -Iinclude ...
Run Code Online (Sandbox Code Playgroud)

您也可以直接使用通配符,但我倾向于发现我需要它们不止一个地方.

请注意,这仅适用于小型项目,因为它假定每个目标文件都依赖于每个头文件.

  • 但是,这样做的问题在于,每次进行一次小的更改时,每个目标文件都会被重新编译,即,如果你有100个源/头文件,并且只做一个小的更改,那么所有100个都会被重新编译. (14认同)
  • 这是一个非常糟糕的解决方案。当然,它可以在一个小项目上运行,但是对于任何规模的团队和构建而言,这都会导致糟糕的编译时间,并等同于每次运行“ make clean all”。 (2认同)

mic*_*ael 6

马丁的上述解决方案效果很好,但不能处理驻留在子目录中的 .o 文件。Godric 指出 -MT 标志可以解决这个问题,但它同时会阻止 .o 文件被正确写入。下面将解决这两个问题:

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

-include $(DEPS)

%.o: %.c
    $(CC) $(CFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,$@) $<
    $(CC) $(CFLAGS) -o $@ $<
Run Code Online (Sandbox Code Playgroud)