build.d: Fix dependencies on generated string-import files (#21192)

This is just a byproduct of taking a closer look at this code,
as part of investigating the recent CI failures on Windows, where
the VERSION and SYSCONFDIR.imp rules seem to run twice - and then
fail for the 2nd run, Windows complaining about another process using
the file. I guess that could be an Anti-malware process running right
after creating the file the first time. And both rules check the file
contents as part of their condition, so if the rule is processed twice,
we try to immediately read its contents after the write.

Each of these 2 auto-generated files is string-imported exactly once:

* `SYSCONFDIR.imp` in the driver's `dmd/dinifile.d` (and actually on
  Posix only)
* `VERSION` in the lexer's `dmd/globals.d`

I've revised the deps accordingly, which might avoid processing these
rules multiple times as a side-effect.
This commit is contained in:
Martin Kinkelin 2025-04-10 23:03:54 +02:00 committed by GitHub
parent 0aee4697bd
commit bb25d82a3b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -263,7 +263,6 @@ alias lexer = makeRuleWithArgs!((MethodInitializer!BuildRule builder, BuildRule
.sources(sources.lexer)
.deps([
versionFile,
sysconfDirFile,
common(suffix, extraFlags)
])
.msg("(DC) LEXER" ~ suffix)
@ -378,7 +377,7 @@ alias backend = makeRuleWithArgs!((MethodInitializer!BuildRule builder, BuildRul
).array)
);
/// Returns: the rules that generate required string files: VERSION and SYSCONFDIR.imp
/// Returns: the rule that generates string-import file `VERSION` (for the lexer)
alias versionFile = makeRule!((builder, rule) {
alias contents = memoize!(() {
if (dmdRepo.buildPath(".git").exists)
@ -420,6 +419,7 @@ alias versionFile = makeRule!((builder, rule) {
.commandFunction(() => writeText(rule.target, contents));
});
/// Returns: the rule that generates string-import file `SYSCONFDIR.imp` (for the driver)
alias sysconfDirFile = makeRule!((builder, rule) => builder
.target(env["G"].buildPath("SYSCONFDIR.imp"))
.condition(() => !rule.target.exists || rule.target.readText != env["SYSCONFDIR"])
@ -469,7 +469,7 @@ alias dmdExe = makeRuleWithArgs!((MethodInitializer!BuildRule builder, BuildRule
.sources(dmdSources.chain(lexer.targets, backend.targets, common.targets).array)
.target(env["DMD_PATH"] ~ targetSuffix)
.msg("(DC) DMD" ~ targetSuffix)
.deps([lexer, backend, common])
.deps([sysconfDirFile, lexer, backend, common])
.command([
env["HOST_DMD_RUN"],
"-of" ~ rule.target,
@ -757,13 +757,15 @@ alias runCxxUnittest = makeRule!((runCxxBuilder, runCxxRule) {
.name("cxx-unittest")
.description("Build the C++ unittests")
.msg("(DC) CXX-UNITTEST")
.deps([lexer(null, null), cxxFrontend])
.deps([sysconfDirFile, lexer(null, null), cxxFrontend])
.sources(sources.dmd.driver ~ sources.dmd.frontend ~ sources.root ~ sources.common ~ env["D"].buildPath("cxxfrontend.d"))
.target(env["G"].buildPath("cxx-unittest").exeName)
.command([ env["HOST_DMD_RUN"], "-of=" ~ exeRule.target, "-vtls", "-J" ~ env["RES"],
"-L-lstdc++", "-version=NoMain", "-version=NoBackend"
].chain(
flags["DFLAGS"], exeRule.sources, exeRule.deps.map!(d => d.target)
flags["DFLAGS"], exeRule.sources,
// don't compile deps[0], the SYSCONFDIR.imp string-import file
exeRule.deps[1 .. $].map!(d => d.target)
).array)
);
@ -967,7 +969,7 @@ alias html = makeRule!((htmlBuilder, htmlRule) {
.sources(sourceArray)
.target(env["DOC_OUTPUT_DIR"].buildPath(d2html(source)[srcDir.length + 1..$]
.replace(dirSeparator, "_")))
.deps([dmdDefault, versionFile, sysconfDirFile])
.deps([dmdDefault])
.command([
dmdDefault.deps[0].target,
"-o-",