如何为不同的配置分离 Makefile 构建输出?

Posted

技术标签:

【中文标题】如何为不同的配置分离 Makefile 构建输出?【英文标题】:How do I separate Makefile build outputs for different configurations? 【发布时间】:2017-04-03 09:10:53 【问题描述】:

鉴于我有一个项目,其 Makefile 如下所示:

all: foobar
foobar: foo.o bar.o

我可以针对不同的架构进行构建:

$ CC=clang make                    # or
$ CC=x86_64-w64-mingw32-gcc  make  # or
$ CC=arm-linux-gnueabihf-gcc make

这可行,但我希望能够同时维护多个配置的输出,例如在构建服务器上。

什么是解决这个问题的好方法?我考虑了以下几点:

使用 autotools 或其他构建工具,但我想看看没有什么是可能的 使用其中设置 VPATH 并包含根 Makefile 的 Makefile 创建构建目录 编写一个脚本,在构建每个架构后移动输出 修改 Makefile 以构建多个配置。我不喜欢这种解决方案,因为您最终会得到一种元 Makefile,它复杂且与您的特定构建环境紧密耦合 将变量添加到 Makefile 以设置输出目录。这可以工作,但这意味着我不能使用隐式 Makefile 规则。模式规则也会变得混乱

【问题讨论】:

当您说要保存输出时,您是指对象,还是只是最终的可执行文件?将$(OBJDIR) 设置为对象的输出目录是常见的做法,您可以根据构建配置有条件地设置它。隐式规则很容易重写,尽管您必须首先制定规则来创建 $(OBJDIR)。 我认为您应该对每个架构使用不同的目标(带有目录)。说arm/foox86_64/foomain/foo。我建议尽量简单:) 我想我会选择@John 提到的$(OBJDIR) 解决方案。我真的希望像make -f ../Makefile VPATH=… 这样的东西是可能的,但我想它不是。 @uzsoft 我认为 Makefile 不应该了解这些不同的环境,而是应该具有适应性。因此我的'meta-Makefile'评论。 你可以很容易地在命令行上配置OBJDIRmake OBJDIR=/foo/bar,然后在makefile中做一个OBJDIR ?= /foo/obj-default,以防用户没有指定它。如果您不介意丑陋的目录名称,您甚至可以执行 OBJDIR ?= /foo/obj-$(CC) 之类的操作... 【参考方案1】:

我会选择这样的:

# User configuration
BINARY  := hello
SOURCES := main.c

# Create the output paths
out     ?= out
outdir  := $(out)/$(CC)
outbin  := $(outdir)/$(BINARY)
objects := $(outdir)/$(SOURCES:.c=.o)

# Default target
all: $(outbin)

# Binary target
$(outbin): $(objects)
    $(CC) -o $@ $^

# Objects target
$(objects): $(outdir)/%.o: %.c
    mkdir -p $(@D)
    $(CC) -o $@ -c $<

# The cleanning targets
clean:
    $(RM) -r $(outdir)

mrproper:
    $(RM) -r $(out)

# Declare phony targets
.PHONY: all clean mrproper

请注意,objects 目标使用static pattern 能够获取当前目录中的源文件和输出目录中的目标文件。


它也和基本的Makefile一样容易使用:

$ make
mkdir -p out/cc
cc -o out/cc/main.o -c main.c
cc -o out/cc/hello out/cc/main.o

$ make
make: Nothing to be done for 'all'.

$ tree
.
├── main.c
├── Makefile
└── out
    └── cc
        ├── hello
        └── main.o

2 directories, 4 files

$ CC=gcc make
mkdir -p out/gcc
gcc -o out/gcc/main.o -c main.c
gcc -o out/gcc/hello out/gcc/main.o

$ tree
.
├── main.c
├── Makefile
└── out
    ├── cc
    │   ├── hello
    │   └── main.o
    └── gcc
        ├── hello
        └── main.o

3 directories, 6 files

【讨论】:

感谢您的详尽回答。我想这就是我要前进的方向。如果在此期间没有其他新想法出现,我会在稍后将其标记为答案。 一个后续问题:是否可以在经典后缀语法中执行obj/%.o: %.c 规则? @SijmenMulder 是的,我相信你可以。我更喜欢这种表示法,因为它仅对您指定的目标有效。 一个快速评论,不要在每个对象的配方中运行mkdir -p。而是添加行 $(objects) : | $(outdir)$(outdir) : ; mkdir -p $@,它们只会运行 mkdir 一次。 @John 只有当所有源文件都在同一目录中时,您的解决方案才能正常运行。否则你可以每次运行mkdir -p,或者如果你想要更干净的东西,你可以检查my other response。

以上是关于如何为不同的配置分离 Makefile 构建输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何为 Visual Studio 构建工具 cl.exe 编写 makefile(nmake)

如何为多个构建配置选择不同的 app.config

如何为angularjs分离不同文件中的控制器?

如何为不同的目标设置不同的 .entitlements 文件

如何为生产和开发环境 iOS 设置不同的证书和配置文件?

我应该如何为 linux 内核模块构建设置额外的包含路径?