首页 文章

如何确保使用具有多个MAKE目标的Makefile中的正确设置编译目标文件

提问于
浏览
2

我有一个小项目,它从相同的源文件构建了许多目标 . 目标需要使用不同的编译标志构建源文件 . 这实际上是在cygwin上,所以我会用它作为具体的例子,虽然我认为这是一个普遍的问题 .

所以这将是Makefile的一个例子:

a: CFLAGS =

a: a.o c.o

b: CFLAGS = -mno-cygwin

b: b.o c.o

这原则上工作,构建一个将使用CFLAGS编译的将编译,并且构建b将使用设置为-mno-cygwin的CFLAGS进行编译 . 但只有当c.o尚未存在时 .

这样做

> make a b

在virgin目录中,首先使用空CFLAGS编译a.c和c.c.然后它将尝试使用CFLAGS = -mno-cygwin构建b . 但由于c.o已经存在,因此不会重新编译c.c导致链接器错误,因为目标文件需要具有相同的此标志设置 .

再次,cygwin-flag只是一个具体的例子,我正在寻找一个通用的解决方案 .

我试过的是引入一个额外的目标检查当前的CFLAGS并删除所有目标文件,如果它不匹配:

ARCH    = `echo $(CFLAGS)`
checkTarget:
-@if test "`cat .arch`" != "$(ARCH)"; then \
    rm *.o; \
    /bin/echo -n $(ARCH) > .arch; \
fi

将此目标作为两个目标的依赖项插入可确保在需要时重新编译所有目标文件 .

a: CFLAGS =

a: checkTarget a.o c.o

b: CFLAGS = -mno-cygwin

b: checkTarget b.o c.o

然而,这会重新编译每个目标文件,这是不必要的,并且在较大的项目中成为问题 .

有一个更好的方法吗?

编辑:在单个答案的注释中包含一个提示,您可以使目标文件取决于CFLAGS的内容 . 我无法弄清楚如何做到这一点,除了将它们放到临时文件中并与之前的文件进行比较,然后将其复制到依赖文件上 . 有没有更好的方法?

2 回答

  • 0

    我们需要的是 c.o 的两个(或更多)版本,使用不同的标志编译并链接到不同的可执行文件中 . 你可以使用像 c_for_a.o 这样的人为的文件名来做到这一点,但将它们保存在不同的目录中更为整洁, for_a/for_b/

    a for_a/%: CFLAGS =
    
    a: a.o for_a/c.o
    
    b for_b/%: CFLAGS = -mno-cygwin
    
    b: b.o for_b/c.o
    

    (如果不清楚,我可以填写Makefile的其余部分 . )

    EDIT:
    如果你不想保留多个 c.o ,你有时需要重新编译c.o. checkTarget 的想法有一点点改进 .

    当您构建像 b 这样的目标并且 c.o 已经存在时,重要的是 c.o 是否使用适合 b 的_246166构建,并且您使用 checkTarget 来记录该信息 . 但是你不关心 CFLAGS 被使用了什么,只是他们是 bCFLAGS . 因此,您不必在 checkTarget 文件中记录任何内容,只需在构建新目标时更新它:

    a: CFLAGS =
    
    b: CFLAGS = -mno-cygwin
    
    # You may be able to combine the a and b rules...
    a: a.o c.o checkTarget
        # build c.o
        touch checkTarget
        # build the target
    
    b: b.o c.o checkTarget
        # build c.o
        touch checkTarget
        # build the target
    
    # Need this to create checkTarget the first time
    checkTarget:
        @touch $@
    
  • 2

    虽然有一些关于如何做我最初要求的建议here(正如slowdog指出的那样),但我决定将Beta的不同名称模式更进一步,并将各种变体的所有对象放在子目录中按照Beta在回答this question的第二个建议中的描述 .

    本质上,我的Makefile看起来像:

    A : AOBJDIR = .a
    AOBJECTS = $(addprefix $(AOBJDIR)/,$(ASRCS:.c=.o))
    
    $(AOBJECTS): $(AOBJDIR)/%o: %.c
        $(CC) $(CFLAGS) -MMD -o $@ -c $<
    
    $(AOBJDIR) :
        @mkdir $(AOBJDIR)
    
    -include $(AOBJECTS:.o=.d)
    
    a: $(AOBJDIR) $(AOBJECTS)
        $(LINK) ...
    

    因此,第一部分命名一个子目录,用于'a'的目标文件,并通过转换源文件名并添加子目录前缀在该目录中创建目标文件列表 .

    然后遵循这些目标文件的默认规则(抛出依赖项生成以获得良好的度量) .

    接下来的两个是确保子目录存在,并且包含依赖性信息 .

    最后,链接规则具有对子目录本身的额外依赖性,以确保在不存在时创建它 .

    在我的例子中,通过交换所有的a,可以对b重复该块 . 因此,如果我只能弄清楚如何将这个块打包成更通用的可以参数化的东西,我会很高兴 .

相关问题