[clang] [llvm] [LLVM] Add GNU make jobserver support (PR #145131)
Artem Belevich via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 14 11:09:21 PDT 2025
================
@@ -0,0 +1,257 @@
+//===- llvm/Support/Jobserver.cpp - Jobserver Client Implementation -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Jobserver.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <new>
+
+#define DEBUG_TYPE "jobserver"
+
+using namespace llvm;
+
+namespace {
+struct JobserverConfig {
+ enum Mode {
+ None,
+ PosixFifo,
+ PosixPipe,
+ Win32Semaphore,
+ };
+ Mode TheMode = None;
+ std::string Path;
+ int ReadFD = -1;
+ int WriteFD = -1;
+};
+
+/// A helper function that checks if `Input` starts with `Prefix`.
+/// If it does, it removes the prefix from `Input`, assigns the remainder to
+/// `Value`, and returns true. Otherwise, it returns false.
+bool getPrefixedValue(StringRef Input, StringRef Prefix, StringRef &Value) {
+ if (Input.consume_front(Prefix)) {
+ Value = Input;
+ return true;
+ }
+ return false;
+}
+
+/// A helper function to parse a string in the format "R,W" where R and W are
+/// non-negative integers representing file descriptors. It populates the
+/// `ReadFD` and `WriteFD` output parameters. Returns true on success.
+bool getFileDescriptorPair(StringRef Input, int &ReadFD, int &WriteFD) {
+ if (sscanf(Input.str().c_str(), "%d,%d", &ReadFD, &WriteFD) != 2)
+ return false;
+ return ReadFD >= 0 && WriteFD >= 0;
+}
+
+/// Parses the `MAKEFLAGS` environment variable string to find jobserver
+/// arguments. It splits the string into space-separated arguments and searches
+/// for `--jobserver-auth` or `--jobserver-fds`. Based on the value of these
+/// arguments, it determines the jobserver mode (Pipe, FIFO, or Semaphore) and
+/// connection details (file descriptors or path).
+Expected<JobserverConfig> parseNativeMakeFlags(StringRef MakeFlags) {
+ JobserverConfig Config;
+ if (MakeFlags.empty())
+ return Config;
+
+ // Split the MAKEFLAGS string into arguments.
+ SmallVector<StringRef, 8> Args;
+ StringRef S = MakeFlags;
+ while (!S.empty()) {
+ size_t Start = S.find_first_not_of(" \t");
+ if (Start == StringRef::npos)
+ break;
+ S = S.substr(Start);
+ size_t End = S.find_first_of(" \t");
+ if (End == StringRef::npos) {
+ Args.push_back(S);
+ break;
+ }
+ Args.push_back(S.substr(0, End));
+ S = S.substr(End);
+ }
+
+ // If '-n' (dry-run) is present as a legacy flag (not starting with '-'),
+ // disable the jobserver.
+ if (!Args.empty() && !Args[0].starts_with("-") && Args[0].contains('n'))
+ return Config;
+
+ // Iterate through arguments to find jobserver flags.
+ // Note that make may pass multiple --jobserver-auth flags; the last one wins.
+ for (StringRef Arg : Args) {
+ StringRef Value;
+ if (getPrefixedValue(Arg, "--jobserver-auth=", Value)) {
+ int R, W;
+ // Try to parse as a file descriptor pair first.
+ if (getFileDescriptorPair(Value, R, W)) {
+ Config.TheMode = JobserverConfig::PosixPipe;
+ Config.ReadFD = R;
+ Config.WriteFD = W;
----------------
Artem-B wrote:
If we were to combine ReadFD and WriteFD into a struct (or just store them as a pair in the Config), then we could drop R/W temporaries and simplify it a bit:
```
if (auto Descriptors = getFileDescriptorPair(Value)) {
Config.TheMode = JobserverConfig::PosixPipe;
Config.Descriptors = *Descriptors;
```
https://github.com/llvm/llvm-project/pull/145131
More information about the llvm-commits
mailing list