GNU make:在 Makefile 中提取参数 -j

发布于 2024-10-21 15:23:02 字数 248 浏览 1 评论 0原文

我已经搜索了一个小时,但这些信息似乎无处可寻...

我希望能够提取(并可能使用)通过 -j 选项传递的请求的 make“作业”数量,或者在子 make 的情况下由 Make 本身在 Makefile 中。

到目前为止我见过的最有前途的东西是 $(MAKEFLAGS) 变量,但在我的系统上(如果我这样做,比如 make -j2),这个变量的内容只是“--jobserver-fds=3,4 -j”。有什么方法可以获取通过 -j 传递的实际作业数量吗?

I've been searching for an hour, and this information appears to be nowhere...

I'd like to be able to extract (and possibly use) the number of requested make "jobs," as passed via the -j option, or by Make itself in the case of sub-makes, in the Makefile.

The most promising thing I've seen so far is the $(MAKEFLAGS) variable, but on my system (if I do, say, make -j2) the contents of this variable are only "--jobserver-fds=3,4 -j". Is there any way to get the actual number of jobs passed with -j?

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

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

发布评论

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

评论(3

原谅过去的我 2024-10-28 15:23:02

实际上有一种方法可以在 *nix 上的 makefile 中完全实现这一点。

MAKE_PID := $(shell echo $PPID)
JOB_FLAG := $(filter -j%, $(subst -j ,-j,$(shell ps T | grep "^\s*$(MAKE_PID).*$(MAKE)")))
JOBS     := $(subst -j,,$(JOB_FLAG))

grep 也需要安装,但这几乎是必然的。它也可以进一步改进以处理 --jobs

根据评论中的要求,使用正则表达式并支持 --jobs 的版本:

MAKE_PID := $(shell echo $PPID)
JOBS := $(shell ps T | sed -n 's%.*$(MAKE_PID).*$(MAKE).* \(-j\|--jobs=\) *\([0-9][0-9]*\).*%\2%p')

Actually there is a way to implement this completely inside your makefile on *nix.

MAKE_PID := $(shell echo $PPID)
JOB_FLAG := $(filter -j%, $(subst -j ,-j,$(shell ps T | grep "^\s*$(MAKE_PID).*$(MAKE)")))
JOBS     := $(subst -j,,$(JOB_FLAG))

grep also needs to be installed, but it is almost a given. It can be further improved to handle --jobs too.

A version using regex and supporting --jobs, as requested in the comments:

MAKE_PID := $(shell echo $PPID)
JOBS := $(shell ps T | sed -n 's%.*$(MAKE_PID).*$(MAKE).* \(-j\|--jobs=\) *\([0-9][0-9]*\).*%\2%p')
镜花水月 2024-10-28 15:23:02

抱歉,如果不编写扫描进程列表来识别调用参数的应用程序或脚本,就无法识别并行作业的数量。

检查源代码 http ://cvs.savannah.gnu.org/viewvc/make/main.c?revision=1.246&root=make&view=markup 。搜索 job_slots > 1..

更新:如果您可以控制操作范围,则可以使用自己的程序/脚本包装 make 应用程序,解析参数,设置专用环境变量,然后调用原始 make。

I'm sorry but there is no way to identify the number of parallel jobs -- without writing an application or script that scan the process list to identify the calling parameters.

Check the source code at http://cvs.savannah.gnu.org/viewvc/make/main.c?revision=1.246&root=make&view=markup . Search for job_slots > 1.

Update: If you have control over the operating range you could wrap the make application with your own program/script, parse the parameters, set an dedicated environment variable and call the original make afterwards.

伪装你 2024-10-28 15:23:02

使用作业服务器 FD 来推断实际可用的作业数量,

我想出了一种不同的方法,我更喜欢解析命令行,正如已接受的答案中所建议的那样。我对后者的主要问题是,它在递归调用的 makefile 中不起作用,因为 jobs 参数是通过那里的 env 传递的,然后它代表 jobserver,它不会告诉您它将有多少个 job token所以

我决定接受 jobserver 的东西,并制作一个小的 Python 脚本,它消耗 jobserver 中的所有令牌,对它们进行计数,然后将它们放回去。

这是一个绝妙的想法,而且似乎非常容易实现,而且对我来说非常有效。

关于如何使用它有一些注意事项:

  1. 必须在配方上使用 + 前缀来调用脚本,因为这使得“submake”功能能够复制子进程的作业服务器描述符。能够“生成工人”
  2. 以给出正确的作业计数,在配方中包含此脚本的规则应该成为所有目标的通用仅订单虚假先决条件,以便它可以由 make 优先运行到其他任何东西,并且永远不会与其他东西并行,因为这样计数就会关闭
  3. 当前脚本实现的最大数量将达到 1024 个令牌。请随意改进代码以避免限制,可以通过围绕读取的简单循环和一些逻辑来完成。

Python 脚本:


import argparse, os

def safe_int(s):
    try:
        return int(s)
    except:
        return -1

class JobserverArgs:
    known_names = ["jobserver-fds","jobserver-auth"]
    def __init__(self):
        self.fds = "-1,-1"

    @staticmethod
    def from_argv():
        ja = JobserverArgs()
        parser = argparse.ArgumentParser()
        for name in JobserverArgs.known_names:
            parser.add_argument('--'+name, dest="fds")
        parser.parse_known_args(namespace=ja)
        return ja

    def get_fds(self):
        return tuple([safe_int(fd) for fd in (self.fds+",").split(",")][:2])


fd_in, fd_out = JobserverArgs.from_argv().get_fds()

if fd_in == -1 or fd_out == -1:
    print(1)
else:
    os.set_blocking(fd_in, False)

    tokens = os.read(fd_in, 1024)
    os.write(fd_out, tokens)

    print(len(tokens)+1)

示例 makefile:

TARGETS := a b c d e

.PHONY: $(TARGETS)
$(TARGETS):
    @for i in 1 2; do echo "$@$i"; sleep 1; done

.PHONY: all
all: $(TARGETS)
    @echo done all

$(TARGETS): | common

.PHONY: common
common:
    +$(eval JOBS:=$(shell python jobs.py $(MAKEFLAGS)))
    @echo JOBS=$(JOBS)

运行它:

projects/make-fun » make all -j100
JOBS=100
a1
b1
c1
d1
e1
a2
b2
c2
d2
e2
done all

Using the job-server FDs to deduce the actual available job count

I've come up with a different approach which I prefer over parsing the command line as it was suggested in the accepted answer. The main issue I have with the latter is that it doesn't work in a recursively called makefile, as the jobs parameter is passed via the env there, and then it's representing the jobserver which tells you nothing of how many job tokens it's going to provide

So I have decided to embrace the jobserver thing and make a small Python script that consumes all tokens from the jobserver, counts them, and then puts them back.

This was a neat idea that appeared to be surprisingly easy to implement, and it worked very well for me.

There are a few notes on how it should be used:

  1. the script must be called with a + prefix on the recipe because that enables the "submake" functionality which duplicates the jobserver descriptors for the child process to be able to "spawn workers"
  2. to give the correct job count the rule containing this script in the recipe should be made a common order-only phony prerequisite to all your targets so that it will be run by make prior to anything else and never in parallel to other things, cause then the count would be off
  3. The current script implementation will max out at 1024 tokens. Feel free to improve the code to avoid the limitation, can be done with a simple loop around the read and a little logic.

The Python script:


import argparse, os

def safe_int(s):
    try:
        return int(s)
    except:
        return -1

class JobserverArgs:
    known_names = ["jobserver-fds","jobserver-auth"]
    def __init__(self):
        self.fds = "-1,-1"

    @staticmethod
    def from_argv():
        ja = JobserverArgs()
        parser = argparse.ArgumentParser()
        for name in JobserverArgs.known_names:
            parser.add_argument('--'+name, dest="fds")
        parser.parse_known_args(namespace=ja)
        return ja

    def get_fds(self):
        return tuple([safe_int(fd) for fd in (self.fds+",").split(",")][:2])


fd_in, fd_out = JobserverArgs.from_argv().get_fds()

if fd_in == -1 or fd_out == -1:
    print(1)
else:
    os.set_blocking(fd_in, False)

    tokens = os.read(fd_in, 1024)
    os.write(fd_out, tokens)

    print(len(tokens)+1)

example makefile:

TARGETS := a b c d e

.PHONY: $(TARGETS)
$(TARGETS):
    @for i in 1 2; do echo "$@$i"; sleep 1; done

.PHONY: all
all: $(TARGETS)
    @echo done all

$(TARGETS): | common

.PHONY: common
common:
    +$(eval JOBS:=$(shell python jobs.py $(MAKEFLAGS)))
    @echo JOBS=$(JOBS)

running it:

projects/make-fun » make all -j100
JOBS=100
a1
b1
c1
d1
e1
a2
b2
c2
d2
e2
done all
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文