Repository navigation
feat(compilerlib): give each compilation a working directory of its own - #262
Draft
SizzleUnrlsd wants to merge 24 commits into
Draft
SizzleUnrlsd wants to merge 24 commits into
SizzleUnrlsd wants to merge 24 commits into
Conversation
The linker runs as a program of its own, which starts in the process's working directory. A link with -working-directory writes the program in that directory, and leaves the process there, as clang does. The test pins both, which giving each compilation a working directory of its own must keep. Refs #261
The assembler runs as a program of its own too. An empty source, which every target assembles, gives its object in the directory of -working-directory. Refs #261
The directory of -working-directory resolves the source and the include directory, and receives the output and the dependency file, of a plain and of an instrumented compilation. Refs #261
normalizeWorkingDirectoryArgs parses a command line as the driver does, rewrites each -working-directory, in either spelling, into the two-argument form with an absolute directory, and returns the last one. Nothing calls it yet. Refs #261
The driver moved the process to a relative directory, then gave the option unchanged to the -cc1 job, which resolved it again from there: the source was not found. The directory is made absolute before the driver reads it, so that it names one directory to both. Refs #261
compilerlib reads the objects of a link without sources, to choose between the C and C++ drivers, before the driver moves to the directory of -working-directory: a relative object was looked up in the process's directory and not found. It is now looked up in that directory. Refs #261
A -cc1 job reads a sanitizer's ignore list through its file system, not through its file manager, and the driver reads it first: both must find it in the directory of -working-directory. Refs #261
resolveCc1OutputPaths makes absolute, against a directory, the relative paths of the files a -cc1 job writes: its output, dependency file, header list, optimization record, split DWARF, stack usage, serialized diagnostics and time trace. Nothing calls it yet. Refs #261
compile() read and wrote files through the file system of the process, so -working-directory moved the whole process there, for good: a host compiling from several threads had to change the working directory itself, under a lock that serialized every compilation. Each compilation now has a file system of its own, whose working directory -working-directory moves while the process's stays. The -cc1 jobs read through it, LLVM 21 and earlier included, and the files they write are made absolute against it, since Clang writes them relative to the process's directory. A job that runs as a program of its own, as the linker and the assembler do, starts in the process's directory: for such a compilation, the process still moves to the directory. Compilations from eight threads, each in a directory of its own with a header of the same name, read their own header, instrumented or not. Refs #261
A job builds compilerlib and its unit tests with ThreadSanitizer, and runs the tests of -working-directory, those of concurrent compilations included. LLVM and Clang come from packages built without it: a race inside their code goes unseen. Refs #261
Clang parses -mllvm, -mdebug-pass and -mlimit-float-precision into LLVM's command-line options, and sets whether LLVM times its passes from -ftime-report, for the whole process. Refs #261
Not only -mllvm: -mdebug-pass, -mlimit-float-precision and -ftime-report too. Refs #261
The entry of compilations from several threads named -mllvm alone. Refs #261
This was referenced Nov 12, 2026
A -cc1 job wrote the statistics file of -save-stats, the dependency graph of -dependency-dot and its module cache relative to the process's working directory, which -working-directory no longer moves: the statistics of -save-stats=cwd landed in the process's directory. Their paths are now made absolute against the compilation's directory, as are those of the other files the job writes. Refs #261
resolveDriverOutputPaths rewrites -MJ <file> and -gen-cdb-fragment-path <directory>, which the driver itself writes, into the two-argument form, with a relative path made absolute against a directory. Nothing calls it yet. Refs #261
The driver writes the compilation database fragment of -MJ relative to the process's working directory, which -working-directory no longer moves: the fragment landed in the process's directory. Its path, and that of -gen-cdb-fragment-path, are now made absolute against the compilation's directory before the driver reads them. Refs #261
SizzleUnrlsd
added a commit
to CoreTrace/coretrace-stack-analyzer
that referenced
this pull request
Nov 12, 2026
The newer commit of CoreTrace/coretrace-compiler#262 also writes the fragment of -MJ, the statistics of -save-stats, the graph of -dependency-dot and the module cache in the directory of -working-directory, as the analyzer did when it moved the process there. Refs #271
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
With
-working-directory <dir>,compilerlib::compilemoved the whole process to<dir>and left it there (#261). A host that compiles the commands of a compilation database, each from its own directory, therefore serialized its compilations under a lock, as coretrace-stack-analyzer does. Each compilation now reads and writes files through a file system of its own, whose working directory-working-directorymoves while the process's stays: compilations can run from several threads at once.Closes #261
Behaviour changes
-working-directorywhose jobs all run in this process: a compilation to a file, to memory, instrumented or not. Before, it was left in<dir>. This is what lets compilations run at once.-fno-integrated-cc1) starts in the process's working directory. For such a compilation, the process still moves to<dir>and stays there, as clang does. No compilation that worked before is refused.<dir>. It failed witherror reading 'unit.c': the driver moved the process to it, and the-cc1job, which received it unchanged, resolved it again from there.-working-directory <dir> unit.o main.o -o programfailed withfailed to inspect object: unit.o: compilerlib read the objects, to choose between the C and C++ drivers, from the process's directory.Change
test(compilerlib): ...(4 commits): a link, an assembly, the output and dependency file of a plain and of an instrumented compilation, and a sanitizer's ignore list, all with-working-directory. They pass on main and pin what the change must keep.refactor(compilerlib): make the -working-directory arguments absoluteandfix(compilerlib): resolve a relative -working-directory once: the option is made absolute before the driver reads it.fix(compilerlib): inspect objects linked alone in -working-directory.refactor(compilerlib): resolve the files a -cc1 job writes in a helper: the output, dependency file, header list, optimization record, split DWARF, stack usage, serialized diagnostics and time trace, which Clang writes relative to the process's directory.feat(compilerlib): give each compilation a working directory of its own:llvm::vfs::createPhysicalFileSystem, and the driver moves its working directory, not the process's;-cc1jobs the driver runs in this process read through it from LLVM 16 on. Before LLVM 22, such a job creates its own file system, the process's, unless it is given one: a sanitizer's ignore list given by a relative path would then be looked up in the process's directory, and the job would end the host process (see the mutations below);-cc1job writes are made absolute against the directory;docs(compilerlib)anddocs(readme): whatcompileguarantees with threads, and its limits.fix(compilerlib): resolve the statistics and module cache of -cc1 jobs,refactor(compilerlib): make the files the driver writes absoluteandfix(compilerlib): write the -MJ fragment in the -working-directory: files written relative to the process's directory, found by testing against main after the first version of this branch. The-cc1job writes the statistics of-save-stats, the graph of-dependency-dotand its module cache; the driver itself writes the fragment of-MJand the directory of-gen-cdb-fragment-path. With-working-directory, main wrote them in that directory, since the process had moved there; they are now made absolute against it.ci(build): run the -working-directory tests under ThreadSanitizer: a job that builds compilerlib and its unit tests with ThreadSanitizer.Limits
-mllvmis parsed into LLVM's command-line options inExecuteCompilerInvocation, without a lock;-mdebug-passand-mlimit-float-precisionare parsed the same way insetCommandLineOptsofBackendUtil.cpp, whose comment says that the parser "is not thread-safe";-ftime-reportsetsllvm::TimePassesIsEnabledandllvm::TimePassesPerRunin the constructor ofBackendConsumer(CodeGenAction.cpp).falsewithout-ftime-report: compilations that run at once write the same value at the same time. This is a data race in Clang's code, benign in effect but undefined by the C++ standard. ThreadSanitizer cannot see it here, since Clang is not instrumented.LLVM_USE_SANITIZER=Thread.Tests
Local runs, on macOS arm64 with AppleClang and LLVM 20.1.2.
The new compile tests against main's compilerlib:
RelativeDirectoryIsRelativeToTheProcesserror reading 'unit.c'ObjectsAreLinkedFromTheDirectoryfailed to inspect object: unit.oProcessStaysInItsDirectory(plain, instrumented)ConcurrentCompilationTest(plain, instrumented): 8 threads, 3 rounds eachCompilationDatabaseFragmentIsWrittenInTheDirectory(-MJ),StatisticsAreWrittenInTheDirectory(-save-stats=cwd)Mutations of this branch, each caught by the tests named:
-cc1job keeps its own file system before LLVM 22IgnoreListIsReadInTheDirectoryends the test process:LLVM ERROR: can't open file 'ignore.txt'ObjectsAreLinkedFromTheDirectory-working-directorypassed on as givenRelativeDirectoryIsRelativeToTheProcess-cc1job writes are not resolvedEach commit builds, and passes the working-directory, concurrency and argument tests it has.
ctest -j2at the head: 277/277, the 257 of main plus 20 new tests.clang-format 18,
scripts/check-license-compliance.shand the commit checker pass.Measurements
coretrace-stack-analyzer db7fb25, with coretrace-compiler built from main (f0a22d9), against the same analyzer compiling in parallel through this branch (its draft change passes each compile command's directory as
-working-directory). macOS arm64 (M3, 8 cores), LLVM 20.1.2,--format=json --timing, no IR cache, an empty resource summary cache. Medians of 5 runs, 3 for the 53 sources; the builds alternate within each repetition.--jobs--jobs=2, 239 MB to 328 MB for the 8 C++ files, 1.26 GB to 1.42 GB for the 53 sources.CI
The runs of 8a99cf3, which adds the
-MJand statistics fixes, are under way. At b05bd18:RelativeDirectoryIsRelativeToTheProcessskips itself: the runner's working directory and temporary directory are on two drives, so no relative path joins them.could not read Username for 'https://github.com'); run again, it passed.