递归 Make 传递了错误的 -j 参数

问题描述 投票:0回答: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

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

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

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

像这样运行时,子 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 通信的方式发生了一些变化。

makefile gnu-make devtoolset
2个回答
1
投票

这里没有什么问题。顶级 make 知道总共有多少个作业,并且它安排所有子 make 通过作业服务器共享这些作业(这就是

--jobserver-fds
中的
MAKEFLAGS
条目的用途)。子品牌不需要知道总共有多少个工作,他们只需要知道如何询问是否可以开始新工作。

在您正在使用的非常旧的 GNU make 版本中,没有办法,从子 make 中,无法知道此构建的具体

-j
编号。

从 GNU make 4.2 开始,make 会将特定的

-j
值添加到
MAKEFLAGS
以供参考,即使它尚未使用。

编辑

我对

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

一个选项是不将

-j
放在外部 make 上,而是使用
-j
scl
内部运行单个内部 make。


0
投票

您可以运行

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"

执行命令:make test
这将帮助您调试并检查 gnu-make 是否存在问题或某些内部错误或 make 无法并行运行,因为它没有找到任何内容。我已经使用

${NUMBER_OF_PROCESSORS}
来使用所有可用的处理器,您可以更改它的值并根据您的需要测试不同的运行。

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

© www.soinside.com 2019 - 2024. All rights reserved.