递归 Make 传递不正确的 -j 参数 更新 1更新 2

问题描述

我正在使用递归 Makefile 运行 make (GNU Make 3.82)。
我正在运行 make -j2 以便仅并行生成 2 个进程。
内部 Makefile 使用 $(MAKE) 调用

然而,看起来内部 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”组合 -j 时,“make”似乎决定从 MAKEFLAGS 参数中去除“2”。

知道什么会导致“make”将 MAKEFLAGS 设置为 -j 而不是 -j2 吗?


更新 1

我已经确定了问题所在,但我仍然不明白它为什么会发生以及如何解决

问题是当 sub-make 在 SCL 上下文中运行时,作业服务器无法正常工作。
这是必需的,因为我需要 sub-make 来使用特定的 gcc 工具链。

SCL      = scl enable devtoolset-8
...
sub_make:
    $(SCL) "$(MAKE) -C $(SUB_MAKE_DIR) ... "

当这样运行时,sub-make 会产生无限数量的工作。删除 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 通信的方式中发生了一些变化.

解决方法

这里没有错。顶级 make 知道总共有多少个作业,并安排所有子 make 通过作业服务器共享这些作业(这就是 --jobserver-fds 中的 MAKEFLAGS 条目的用途)。子品牌不需要知道总共有多少个工作,他们只需要知道如何询问他们是否可以开始新工作。

在您使用的非常旧的 GNU make 版本中,无法从子 make 中知道此构建的特定 -j 编号。

从 GNU make 4.2 开始,make 会将特定的 -j 值添加到 MAKEFLAGS 以供参考,即使它仍未被使用。

编辑

我对 scl 或其工作原理一无所知。但是,GNU make jobserver 通过在所有子 make 之间共享文件描述符来工作。如果这个 scl 工具干扰了它,比如说通过强制关闭所有文件描述符,或者在 docker 镜像中运行 sub-make,显然它无法访问这些共享文件描述符,或者一些类似的东西,那么它显然无法与 jobserver 功能一起使用,您必须在 scl 中运行整个 make。

一种选择是不将 -j 放在外部 make 上,而是使用 -jscl 内部运行单个内部 make。

,

您能否运行 make --print-data-base 并检查您是否获得了正确的 -j 值。

可以执行一个简单的测试示例,如下所示,您可以在其中测试 gnu make 是否能够并行编译多个文件以生成目标文件并提供正确的 -j 值:

# .SILENT:
.PHONY:compile objs
TARGET = program.exe
CC=gcc

SOURCES = file_1.c file_2.c file_3.c
OBJ_FILES:= $(SOURCES:.c=.o)


objs: $(OBJ_FILES)

%.o: %.c
    $(CC) $(FLAGS) -c $< -o $@

all: test 

# Enable parallel compilation
compile:
    make -j ${NUMBER_OF_PROCESSORS} objs

link : compile $(TARGET)

$(TARGET): $(OBJ_FILES)
    $(CC) $(FLAGS) $(OBJ_FILES) -o $@

test: link 
    # Execute test script
    echo "Executing test script"

执行命令:ma​​ke test
这将帮助您调试并检查是否存在 gnu-make 问题或某些内部错误或 make 无法并行运行,因为它没有找到任何东西。我已经使用 ${NUMBER_OF_PROCESSORS} 来使用所有可用的处理器,您可以根据需要更改它的值并测试不同的运行。

编辑
不幸的是,我不知道 sc1。如果 scl 是确定的根本原因,那么选项将在 sc1 内运行整个 make。或者最好通过在 sc1 中显式传递 -j2 来测试一次,因为全局标志可能没有传递给 SC1。