如何为不同的配置分离 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/foo
、x86_64/foo
和main/foo
。我建议尽量简单:)
我想我会选择@John 提到的$(OBJDIR)
解决方案。我真的希望像make -f ../Makefile VPATH=…
这样的东西是可能的,但我想它不是。 @uzsoft 我认为 Makefile 不应该了解这些不同的环境,而是应该具有适应性。因此我的'meta-Makefile'评论。
你可以很容易地在命令行上配置OBJDIR
:make 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)