使用 make 构建多个二进制文件

发布于 2025-01-06 10:04:41 字数 317 浏览 0 评论 0原文

我想创建一个 Makefile(在父目录中)来调用其他几个 Makefile(在子目录中),这样我就可以通过仅调用一个父 Makefile 来构建多个二进制文件(每个项目子目录一个)。

我的研究因在递归 Makefile 上找到大量内容而受到阻碍,但我认为这就是您尝试将多个目录 Makefile 构建到单个二进制文件的地方?

也许我想做的最好是通过 shell 脚本更好地处理,也许依次在每个子目录中调用 make,但我认为 Makefile 可能是一个更优雅的解决方案?

任何指点感激地收到

PS 使用 linux 和 GNU 工具链

I want to create a Makefile (in a parent dir) to call several other Makefiles (in sub dirs) such that I can build several binaries (one per project sub dir) by invoking just the one parent Makefile.

My research has been hampered by finding loads of stuff on recursive Makefiles, but I think this is where you are trying to build several directories Makefiles into a single binary?

Maybe what I want to do is better handled by a shell script perhaps invoking make in each sub directory in turn, but I thought a Makefile might be a more elegant solution?

any pointers gratefully received

PS using linux and the GNU tool chain

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

池予 2025-01-13 10:04:41

上面第一个答案中给出的 for 循环解决方案实际上不应该按原样使用。在这种方法中,如果您的子版本之一失败,构建将不会失败(应该如此),而是继续使用其他目录。不仅如此,构建的最终结果将是最后一个子目录 make 的退出代码,因此如果成功,即使其他子目录失败,构建也会成功。不好!!

您可以通过执行以下操作来修复它:

all: 
        @for dir in $(SUBDIRS); \
        do \
            $(MAKE) -C ${dir} $@ || exit $?; \
        done

但是现在您遇到了相反的问题:如果您运行“make -k”(即使有错误也继续),那么在这种情况下将不会遵守。失败时它仍然会退出。

上述两种方法的另一个问题是它们会序列化所有子目录的构建,因此如果您启用并行构建(使用 make 的 -j 选项),则只会在单个子目录中发生,而不是在所有子目录中发生。

Eregrith 和 sinsedrix 的解决方案更接近您想要的,但仅供参考,当您调用递归 make 调用时,您永远不应该使用“make”。正如 johfel 的示例所示,您应该始终使用 $(MAKE)。

像这样的东西就是您想要的:

SUBDIRS = subdir1 subdir1 subdir3 ...

all: $(addprefix all.,$(SUBDIRS))
all.%:
        @ $(MAKE) -C '$*' '$(basename $@)'
.PHONY: $(addprefix all.,$(SUBDIRS))

当然,您可以为其他目标添加更多这样的节,例如“安装”或其他目标。还有更奇特的方法来处理具有任何通用目标的构建子目录,但这需要更多细节。

如果您想支持并行构建,您可能需要在此级别声明依赖关系,以避免并行构建相互依赖的目录。例如,在上面,如果在 subdir1 和 subdir2 都完成之前无法构建 subdir3 (但 subdir1 和 subdir2 可以并行构建),那么你可以在 makefile 中添加如下内容:

all.subdir3 : all.subdir1 all.subdir2

The for loop solution given in the first answer above actually shouldn't be used, as-is. In that method, if one of your sub-makes fails the build will not fail (as it should) but continue on with the other directories. Not only that, but the final result of the build will be whatever the exit code of the last subdirectory make was, so if that succeeded the build succeeds even if some other subdirectory failed. Not good!!

You could fix it by doing something like this:

all: 
        @for dir in $(SUBDIRS); \
        do \
            $(MAKE) -C ${dir} $@ || exit $?; \
        done

However now you have the opposite problem: if you run "make -k" (continue even if there are errors) then this won't be obeyed in this situation. It'll still exit on failure.

An additional issue with both of the above methods is that they serialize the building of all subdirectories, so if you enable parallel builds (with make's -j option) that will only happen within a single subdirectory, instead of across all subdirectories.

Eregrith and sinsedrix have solutions that are closer to what you want, although FYI you should never, ever use "make" when you are invoking a recursive make invocation. As in johfel's example you should ALWAYS use $(MAKE).

Something like this is what you want:

SUBDIRS = subdir1 subdir1 subdir3 ...

all: $(addprefix all.,$(SUBDIRS))
all.%:
        @ $(MAKE) -C '$*' '$(basename $@)'
.PHONY: $(addprefix all.,$(SUBDIRS))

And of course you can add more stanzas like this for other targets such as "install" or whatever. There are even more fancy ways to handle building subdirectories with any generic target, but this requires a bit more detail.

If you want to support parallel builds you may need to declare dependencies at this level to avoid parallel builds of directories which depend on each other. For example in the above if you cannot build subdir3 until after both subdir1 and subdir2 are finished (but it's OK for subdir1 and subdir2 to build in parallel) then you can add something like this to your makefile:

all.subdir3 : all.subdir1 all.subdir2
帅哥哥的热头脑 2025-01-13 10:04:41

方式调用子目录 makefile 中的目标

all: 
    $(MAKE) -C subdirectory1 $@
    $(MAKE) -C subdirectory2 $@
   ...

您可以通过或更好的

SUBDIRS=subd1 subd2 subd3

all: 
    @for dir in $(SUBDIRS); \
    do \
      $(MAKE) -C ${dir} $@; \
    done

You can call targets in subdirectory makefiles via

all: 
    $(MAKE) -C subdirectory1 $@
    $(MAKE) -C subdirectory2 $@
   ...

or better

SUBDIRS=subd1 subd2 subd3

all: 
    @for dir in $(SUBDIRS); \
    do \
      $(MAKE) -C ${dir} $@; \
    done
一抹苦笑 2025-01-13 10:04:41

您确实应该使用 cmake 从给定的 CMakeLists.txt 配置文件自动生成 Makefile。

这是一个随机链接,可帮助您入门。 在这里您可以找到一个简单的示例项目,包括多个子目录、可执行文件和共享库。

you should indeed use cmake to generate the Makefile automatically from a given CMakeLists.txt configuration file.

Here's a random link to get you started. Here you can find a simple sample project, including multiple subdirectories, executables, and a shared library.

欢烬 2025-01-13 10:04:41

每个makefile可以有多个目标,递归makefile仍然如此,通常这样写:

all: target1 target2 target3

target1 :
    make -C subdir

Then make all

Each makefile can have several target, it's still true with recursive makefiles, usually it's written:

all: target1 target2 target3

target1 :
    make -C subdir

Then make all

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文