A sibling loaded with two arg lists is built twice, and both builds end up in one program #41
Labels
No labels
bug
claude:blocked
claude:done
claude:failed
claude:in-progress
claude:ready
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Catcrafts/Crafter.Build#41
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
When a project reaches the same sibling along two paths with different arg lists, the sibling is loaded and built twice, and both builds go into one program without a word from crafter-build. If the lists change what the sibling declares, that program is put together from two incompatible versions of one module. In the repro below the build succeeds and the program reads garbage; an earlier variant of the same repro segfaulted.
The graph is
P → MandP → A → M:Mreads a flag of its own:--wideadds-DWIDE, which gives the exportedstruct Smore members.AloadsMwith the default args and exportsMakeS(), which returns anS.PsendsMits args without--wide, and loadsAwith the default.crafter-build --wideinP, then the program. Both exit 0:With
--wideon both paths there is oneM, and the program prints40,40ands.b = 2.The fixture relies on the default args from #40; on master,
.args = depArgsinAbuilds the same graph. Line numbers refer to6e2d835.Fixture: three LocalProject projects, no network
m/interfaces/M.cppmm/project.cppa/interfaces/A.cppma/project.cppp/project.cppp/main.cppCause
GitProjectandLocalProjectkey their cache on the arg list (implementations/Crafter.Build-External.cpp:368,:453), soMwith[]andMwith[--wide]are twoConfigurations with two variant directories, and both get built. That part is right:Agets the list it passes and is compiled against theMit asked for, which is why it reports 40.GetCompileCommandwalks a configuration's dependencies transitively, deduplicating by pointer (implementations/Crafter.Build-Clang.cpp:351), and puts each one'sPcmDiron-fprebuilt-module-path(:358).P's compile gets bothMdirectories, its own first. Clang finds moduleMby name and takes the first match, forP'simport Mand for theMthatA's BMI imports alike, and nothing checks that it is theMthatAwas compiled against.P's code sees the 8-byteS, whileA's object code was compiled with the 40-byte one, which is theSthatMakeS()returns.A program can contain one module named
M. Each consumer getting its ownMholds for each compile, but not insideP, which contains both. The two paths have to agree.When the lists differ only in flags that don't change how
Mcompiles (a flag onlyPreads,--debug), the two builds are interchangeable and the cost is buildingMtwice. That is the case #40's README suggests a filtered list for: "a list built from the project's args, say one without a flag only this project reads (it would otherwise give the sibling a build directory of its own)". Filtering on one path is what gives the sibling its second build directory.No current Catcrafts graph hits this: Network, Graphics-imsd-messages, HelloDom and SimpleClient each send one changed list to all of their siblings.
Suggested fix
Configurations, and name both paths with their lists: "Same project" can be the project file plus the configuration name. Matching on the module names the configurations export would also catch aLocalProjectcheckout and aGitProjectclone of one project meeting in one program, for example when only one path honours--local.#pragma crafter dependencytool).Build()fails with that message when the lists differ, and builds with oneMwhen they agree.Not suggested: picking one of the two
Ms and rebuilding the other consumer against it. Arg lists have no merge rule, so the consumer that loses silently gets a differentMfrom the one it asked for.