【问题标题】:Flat object file directory structure output with GNU Make使用 GNU Make 输出平面对象文件目录结构
【发布时间】:2009-09-02 00:21:42
【问题描述】:

我有一个使用 GNU Make 的 C++ 小项目。我希望能够打开以下源文件:

src/
  a.cpp
  b/
    b.cpp
  c/
    c.cpp

进入以下输出结构(此时我不关心重复):

build/
  a.o
  b.o
  c.o

到目前为止,我有以下内容,不幸的是,它把 .o 和 .d 放在每个 .cpp 旁边:

OBJS            :=      $(foreach file,$(SRCS),$(file).o)
DEPS            :=      $(patsubst %.o,%.d,$(OBJS))
sinclude $(DEPS)

$(OBJS) : %.o : %.cpp
        @echo Compiling $<
        $(CC) $(CC_FLAGS) $(INCS) -MMD -o $@ $<  

我知道 $(notdir ...) 函数,但此时我使用它来过滤对象的努力失败了。任何人都可以对此有所了解吗?这似乎是相当合理的事情。

【问题讨论】:

    标签: makefile gnu-make


    【解决方案1】:

    至少有两种方法可以做到这一点。首先(也是我建议的)是您可以将构建目录添加到目标名称(即使使用模式规则)。例如:

    $(OBJS) : build/%.o : %.cpp
    

    其次,您可以使用 VPATH 变量告诉 make 在不同的目录中搜索先决条件。这可能是更常用(过度)使用的方法。它至少有一个严重的缺点,那就是如果你继续使用它,然后遇到“重复”问题,就没有办法解决问题。使用前一种方法,您始终可以在构建目录下镜像源目录结构,以避免重复冲突。

    编辑:我之前的回答有点缺乏细节,所以我将对其进行扩展,以表明这确实像宣传的那样有效。这是一个完整的工作示例 Makefile,它使用上述第一种技术来解决问题。只需将其粘贴到 Makefile 中并运行 make - 它会完成剩下的工作并显示这确实有效。

    编辑:我不知道如何让 SO 允许在我的答案文本中使用制表符(它用空格替换了它们)。复制并粘贴此示例后,您需要将命令脚本中的前导空格转换为制表符。

    BUILD_DIR := build
    
    SRCS := \
        a.c \
        b.c \
        c.c \
        a/a.c \
        b/b.c \
        c/c.c
    
    OBJS := ${SRCS:%.c=${BUILD_DIR}/%.o}
    
    foo: ${OBJS}
        @echo Linking $@ using $?
        @touch $@
    
    ${BUILD_DIR}/%.o: %.c
        @mkdir -p $(dir $@)
        @echo Compiling $< ...
        @touch $@
    
    ${SRCS}:
        @echo Creating $@
        @mkdir -p $(dir $@)
        @touch $@
    
    .PHONY: clean
    clean:
        rm -f foo
        rm -f ${OBJS}
    

    请特别注意,有些源文件名称重复(a.c 和 a/a.c、b.c 和 b/b.c 等),这不会导致任何问题。另请注意,没有使用 VPATH,由于其固有的限制,我建议避免使用它。

    【讨论】:

    • 好的,使用这种方法我可能需要一个额外的规则来在输出文件夹中创建子文件夹?
    • 我最终走上了这条路——因为无论如何我都需要创建目标和配置特定的构建文件夹,所以很容易在“buildfolders”步骤中添加另外几个文件夹。谢谢!
    • 构建文件夹的单独规则应该可以正常工作。不过,我通常做的只是在命令脚本中添加一个“@mkdir -p $(dir $@)”行来创建输出目录(如果它不存在)作为制作目标文件的一部分( s)。
    • 第一个解决方案要么在没有 vpath 的情况下失败,要么在您尝试将对象链接到可执行文件时失败,具体取决于您运行它的位置。 “重复”异议适用于“build/”解决方案,就像适用于 vpath 解决方案一样。
    • 我在 Windows8(64 位)上尝试了该解决方案。 Make 抛出错误:make: *** No rule to make target build\a\a.obj', needed by all'。停止。而且,这个答案是错误的。问题是如何将 C 文件的目录树制作成 .obj 上的平面目录。您给出的答案在构建目录中创建了一个目录树
    【解决方案2】:
    vpath %.cpp src src/b src/c
    

    然后引用不带目录名的源文件; Make 将搜索vpath

    【讨论】:

      【解决方案3】:

      按照最初的要求创建平面目录结构。

      确实使用vpath 来追踪源文件,但所有的簿记都是从SRC 列表中自动完成的。

      SRC = a/a.c a/aa.c b/b.c
      TARGET = done
      
      FILES = $(notdir $(SRC) )
      #make list of source paths, sort also removes duplicates
      PATHS = $(sort $(dir $(SRC) ) )
      
      BUILD_DIR = build
      OBJ = $(addprefix $(BUILD_DIR)/, $(FILES:.c=.o))
      DEP = $(OBJ:.o=.d)
      
      # default target before includes
      all: $(TARGET)
      
      include $(DEP)
      
      vpath %.c $(PATHS)
      
      # create dummy dependency files to bootstrap the process
      %.d:
          echo a=1 >$@
      
      $(BUILD_DIR)/%.o:%.c
          echo $@: $< > $(patsubst %.o,%.d,$@)
          echo $< >$@
      
      $(TARGET): $(OBJ)
          echo $^ > $@
      
      .PHONY: clean
      clean:
          del $(BUILD_DIR)/*.o
          del $(BUILD_DIR)/*.d
      

      对丑陋的echo 感到抱歉,但我只有我的赢箱来测试它。

      【讨论】:

        【解决方案4】:

        这适用于 Win32 mingw32-make。其作品。 最重要的部分是

        -mkdir $(patsubst %/,%,$(dir $@))

        对于win32。我们需要为 win32 去掉尾随 /。

        GENERATED_DIRS = a b
        
        # Dependency generator function
        mkdir_deps =$(foreach dir,$(GENERATED_DIRS),$(dir)/.mkdir.done)
        
        # Target rule to create the generated dependency.
        # And create the .mkdir.done file for stop continuous recreate the dir
        %/.mkdir.done: # target rule
            -mkdir $(patsubst %/,%,$(dir $@))
            echo $(patsubst %/,%,$(dir $@)) >$@
        
        all: $(mkdir_deps)
            @echo Begin
        
        clean:
            @echo Cleaning
        

        【讨论】:

          【解决方案5】:

          您可能并不特别喜欢这种方法,但是:

          AUTOMAKE_OPTIONS =
          

          在 Makefile.am 中做得很好。只是说你不需要手写所有的东西。

          【讨论】:

            猜你喜欢
            • 2014-03-06
            • 1970-01-01
            • 2012-11-13
            • 2021-07-23
            • 1970-01-01
            • 1970-01-01
            • 2020-11-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多