【发布时间】:2021-08-07 15:16:17
【问题描述】:
我正在使用递归 Makefile 运行 make (GNU Make 3.82)。
我正在运行make -j2,以便仅并行生成 2 个进程。
使用 $(MAKE) 调用内部 Makefile。
但是,内部 Makefile(由主 Makefile 启动)似乎无限生成进程,就好像它被赋予 -j 而不是 -j2。
为了验证这一点,我转储了子“make”的环境变量:
# pgrep -a make
17218 make -j2
17227 make -C obj_dir/ -f Vf1_package.mk ...
# strings /proc/17227/environ
...
MAKEFLAGS= --jobserver-fds=3,4 -j
...
MAKEFLAGS 没有在任何地方显式设置,-j 仅在命令行中提供,不会出现在 makefile 的任何地方。因此,在为子“make”编写 MAKEFLAGS 时,似乎“make”本身决定从 -j 参数中去除“2”。
知道什么可能导致“make”将MAKEFLAGS 设置为-j 而不是-j2?
更新 1
我已经确定了问题,但我仍然不明白为什么会发生以及如何解决。
问题是当子make在SCL上下文下运行时,作业服务器不能正常工作。
这是必需的,因为我需要子制作才能使用特定的 gcc 工具链。
SCL = scl enable devtoolset-8
...
sub_make:
$(SCL) "$(MAKE) -C $(SUB_MAKE_DIR) ... "
当这样运行时,子制作会产生无限数量的作业。删除 SCL 后,它会按预期工作。
- 为什么 SCL 会干扰 make 的作业服务器?
- 我该如何解决这个问题?我知道我可以在运行外部 Makefile 之前启用 SCL,但我想从 Makefile 中控制工具集。
更新 2
似乎与SCL更改PATH环境变量有关。在新的PATH 上,“make”是较新的(“GNU Make 4.2.1”)。
因此,如果顶级 make 正在运行旧的 GNU Make 3.82 而子 make 正在运行较新的 4.2.1 make,那么 make 作业服务器似乎会失败,也许这些版本之间在 make 与子 make 通信的方式上发生了一些变化.
【问题讨论】:
-
不知道你为什么认为
ls的版本和make的版本有关系;它们是完全不同的工具。如果你想知道 make 的版本,你应该运行make --version。但是,是的,GNU make 3.82 已经很老了(十多年前发布),并且在 GNU make 4.2(五年前发布)中制作的作业服务器发生了变化。所以如果你想让它工作,你需要使用相同版本的 make。 -
@MadScientist 抱歉打错了,这是“GNU Make 4.2.1”,而不是 ls,在 SCL 更改了
PATH之后。我已经解决了这个问题。对作业服务器的更改是问题的根源。这意味着不能在 make 中使用 SCL 以使用更新的工具链运行子 make。您是否有更多关于工作服务器变更性质的信息? -
它在 GNU make 的 NEWS 文件中。你可以在 Git 中看到最新的副本:git.savannah.gnu.org/cgit/make.git/tree/NEWS 在 4.2 版本信息中提到了它。基本上,jobserver 接口是作为其他工具可以使用的外部可见工具发布的(其他多线程 GNU 构建工具,如 GNU 链接器等也可以使用 jobserver 令牌,这样它们就不会压倒系统)。作为从仅内部可见设施迁移到外部可见设施的一部分,必须清理一些命名。
标签: makefile gnu-make devtoolset