facebook / facebook/buck2

buck2 recompiling *all source files* when a link-only dependency changes

Open
#340 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
4.4k
Forks
394
PR merge metrics
No merged PRs in 30d

Description

I've been working on trying to create a hermetic windows sdk. I have something like this:

```
# winsdk/BUCK

prebuilt_cxx_library(
name="advapi32",
visibility=["PUBLIC"],
header_only=False,
static_lib="winsdk/Lib/um/x64/AdvAPI32.Lib",
)

prebuilt_cxx_library(
name="comctl32",
visibility=["PUBLIC"],
header_only=False,
static_lib="winsdk/Lib/um/x64/ComCtl32.Lib",
)

# lots more prebuilt_cxx_library calls

prebuilt_cxx_library(
name="headers",
visibility=["PUBLIC"],
exported_preprocessor_flags=[
"/DNOMINMAX",
"/D_WIN32_WINNT=0x0601",
"/DWINVER=0x0601",
"/DNTDDI_VERSION=0x06010000",
"/DWIN32_LEAN_AND_MEAN",
],
public_include_directories=[
"winsdk/Include/shared",
"winsdk/Include/ucrt",
"winsdk/Include/um",
"winsdk/Include/winrt",
],

# If it seems weird that I'm including linker dependencies from a target that is supposed to only export headers, it's because
# winsdk has a lot of implicit dependencies in their headers, by way of #pragma comment(lib, ...)
exported_deps=[
":comctl32",
":kernel32",
":powrprof",
":psapi",
":shell32",
":shlwapi",
":user32",
":uuid",
]
)
```

Somewhere else in another file, I have a `cxx_library()` which depends on this:

```
# MyLibrary/BUCK

cxx_library(
name="MyLibrary",
deps=[
"//winsdk:headers"
]
```

I run a build, everything works fine and completes successfully. I then decide I want to add another static lib to the dependencies, let's say winmm.lib. So I go into winsdk/BUCK and add this:

```
prebuilt_cxx_library(
name="winmm",
visibility=["PUBLIC"],
header_only=False,
static_lib="winsdk/Lib/um/x64/WinMM.Lib",
)
```

and then add one line to the end of `exported_deps` to reference the new target `:winmm`.

At this point when I run buck2 build it will rebuild *every single source file in MyLibrary*.

This feels unnecessary. I know that in theory even a `prebuilt_cxx_library()` can export headers or compile flags, which necessitate rebuilding the world. But in this case I'm not doing that. The only delta here is the addition of a `.lib` file on the link line, so there is nothing to be gained from recompiling anything. Maybe `hash_all_commands` and/or `materializations = deferred` in my `.buckconfig` could help (I haven't tried it yet, because I don't understand them well), but the problem seems even higher level than that. buck2 should have enough information (in theory anyway), to not even do *anything*.

My suspicion is that the logic (which I don't know where to find this in source code) is something like "an exported dep changed? Rebuild the world". But you can be smart about it, by reaching into the dep that changed and doing some basic sanity checks to see if the change had the *potential* to impact anything. Of course, you can't always know, and when you don't know you have to err on the side of caution and rebuild everything. But sometimes you can know, and maybe this is one of those cases?

Thoughts?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.