The built-in GitHub action cache is too broken for us to use currently.
Pull request runs will evict trunk runs from the cache easily, which
will remove a useful baseline and make builds generally uncached and
extremely slow.
Instead, move to using Bazel's remote caching functionality with a GCP
storage bucket. This gives us nearly limitless storage and is actually
vastly simpler than the prior arrangement. It should also allow cache
sharing between different build configurations and other benefits.
This cache isn't usable by anyone else sadly, but it should at least
provide a better scaling technique for our CI.
This does require us to move from `pull_request` workflow to
a `pull_request_target` workflow and run the CI within the domain of the
project. This is only really safe for us to do while the project remains
private. When we go public we'll want to make the cache publicly
readable and change this code so that when not running on a branch in
the main repository we use the cache in a read-only mode and only write
back updates for branch runs. This should still be effective but
requires a bit more complexity here and in the remote cache including
setting up public access. For now, going with the simple if slightly
less secure model.
Range-based for loops remain messed up -- I'm just disabling the test here and turning a blind eye.
Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
This avoids having the stacked PR get auto-closed in step 7, and clarifies that you need to merge from trunk to the formerly-stacked PR in order to avoid spurious diffs.
TODOs in the test for known issues.
I may switch the approach to getting the variable type (on examination, this isn't working quite as well as I'd thought) but for now I think it's okay. I had an earlier approach though that may work better overall -- I'd been thinking this would work better, but as you can see in the null check for type information, I think I missed a key point.
Anyways, what'd really been vexing me was `int i, j` which I think I handle passably well now. There's obviously room for improvement, but given I've been going at this for a couple days now, I thought it best to checkpoint where I was.
This also includes some related framework changes to fix bumps I was running into. Overall the tool should operate a bit more smoothly with these changes. There are still issues with overlapping replacements, but I think it's primarily with range-based for loops which I just need to take some time to fix.
This was necessary when I was testing this on my own PR branch, but
without this rebuilds on trunk won't save a fresh cache for folks to use
on *their* pull commit branches. We just need a fresh key here.
Also add one more flag to our `.bazelrc` to improve the overall build
efficiency.
While the first build with this will be very slow (likely a couple of
hours), the caching layer we are using now should effectively cache this
for subsequent builds so that only the changed files have to be
recompiled. Updates to Clang and LLVM themselves will still result in
a slow rebuild, but normal development should remain fast.
The presence or absence of whitespace is used to determine which
operator is in use, following the rules described in #520.
Support for prefix * dereference operator follows #523.
Co-authored-by: Geoff Romer <gromer@google.com>
Currently, Bazel's disk cache grows without bound:
https://github.com/bazelbuild/bazel/issues/5139
Until this is fixed, provide a script to remove entries after 30 days.
If things are changing so rapidly that we need a more aggressive
threshold, we can adjust as we go. I'm somewhat hoping that we don't end
up with *that* many build artifacts, but let's see.
In practice, this means that `executable_semantics` will be built and run using the configuration specified on the command line, rather than e.g. always using `-c opt`.
Also fix a bug exposed by this change.
The Bazel disk cache provides a stable, durable, and supported
persistent cache of the intermediate steps of Bazel builds. This is like
`ccache` but covering more steps and more reliable.
It is based on the same fundamental infrastructure that enables
a *remote* build cache, and at some point we may want to enable that so
that our CI can pre-seed a cache for users. But for now, this just
enables local support for this.
For local builds this will ensure that intermediate artifacts are
re-used when changing branches, syncing, across Bazel server restarts or
even upgrades. It should dramatically reduce the need to re-build large
and slow components like all of Clang and LLVM. Largely, those should
only be rebuilt when we update our pinned revision of upstream and then
cached persistently on a given machine. Enabling this by default
requires hard-coding a path, and so I've also added built-in support for
importing a user config file if present so that folks can customize this
(and any other Bazel features) as desired.
This also wires the disk cache up for the GitHub cache in our CI. By
using the designated Bazel disk cache for this, we get a *much* simpler
and *much* more robust solution. So much so that I've re-arranged the
key structure so we can more aggressively re-use old caches. The only
downside is that nothing ever gets removed automatically from the cache.
I've added a layer that will trim any unused file roughly once a day.
For CI, the benefits of this are huge. None of the previous hacks are
needed to locate and preserve the cache. The design of the cache is
deeply durable and so we don't need to aggressively invalidate it. Last
but not least, it focuses the cache on the raw artifacts, which compress
exceptionally well. With the other changes to shrink the build outputs
and this one combined, I expect we will be able to enable all of the
build targets across all four config/os combinations without any
significant pressure on our space quota for GitHub action caches.
This gets us to a nearly clean state across the toolchain. A couple of
these are checks that I don't think we want to try to rigidly use and
I've disabled them completely. Others I've added relevant `NOLINT` style
suppressions or applied the automatic fix suggested by `clang-tidy`.
The implicit conversions that are allowed here with `NOLINT` are
probably worth at least a tiny bit of scrutiny to see if we could
replace the construct with something more direct without undue effort
and no longer need the implicit conversion. But until then, it seemed
fine to suppress.
Factor out code for pattern parsing, that only recognizes this form for
now, and uniformly form a 'PatternBinding' parse node for this, for
both variables and patterns.
Now that LLVM 12 has been released we no longer have any need to
bootstrap LLVM to get the desired featureset. LLVM 12 is available
widely, including in Homebrew across multiple platforms and in the
GitHub action runners.
Sadly, the Linux distribution builds of LLVM-12 are largely broken and
not as useful for us. The Homebrew Linux install was also broken
originally, but I've worked extensively with the Homebrew folks to get
the Linux install into a really good shape. It should now work reliably.
There are two primary bugs in Linux LLVM packages that need to be fixed
before we can just use them:
- https://bugs.llvm.org/show_bug.cgi?id=43604
- https://bugs.llvm.org/show_bug.cgi?id=46321
Once those are addressed and point releases with the fixes widely
available we can further simplify things.
Even with the need to use Homebrew installs, using the released LLVM has
the extra advantage of making it easy to properly support Darwin ARM and
I've added that configuration so that I can test things there.
Last but not least, this will significantly shrink our build outputs
which should allow building much more in continuous integration on
GitHub actions without exceeding the action cache size limits. I've even
added several tweaks and adjustments to the compile and build flags to
improve the build performance and reduce the build output size.
Once this is landed and stable, we can consider adding the refactoring
tooling back to our CI.
One of the biggest downsides of this path is that our CI has to download
and install the LLVM toolchain from Homebrew on each run. This is pretty
slow (takes a couple of minutes). But it is a fixed overhead -- it won't
get worse over time. Eventually, we can either look at a much fancier
action configuration to avoid this or hopefully the Debian packages will
get updated and we can move back to those.
The bootstrapping has served us long enough at this point. We can
resurrect it if we ever find a compelling reason for breaking off of the
latest LLVM release as our host toolchain.
Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com>
Per https://docs.bazel.build/versions/master/guide.html#option-defaults, test inherits from build, thus why this fixes caching.
The issue can be observed with `bazel build :all && bazel test :all`, the line:
`INFO: Build option --test_env has changed, discarding analysis cache.`
This should clean up our top level directory and the build patterns.
No non-mechanical edits here. Just injecting `toolchain/` and
`TOOLCHAIN_` and then running formatting tools.
This is actually code that I wrote a long time ago but didn't get added
to the repository, trying to tidy that up. This is the last code.
Nothing much interesting here, just a skeleton of a CLI. But seemed
better to add it than to not.
This replaces the use of `isExpansionInMainFile` with instead taking the list of input files, and only touching them. This doesn't keep `isExpansionInMainFile` because it should be redundant, and as such it'd be easy to forget. Unless it starts being a performance issue, it's probably better to omit.
This might need some customization, e.g. `woff2_decompress.impl.carbon` (as a file with a `main`) might be better as `woff2_decompress.carbon`, but I thought at least putting on `.carbon` extensions would help perspectives on files.
This restructures the script to make it easier to access standard info (e.g. cpp_files) without passing everywhere.
This picks up a newer version of LLVM and the LLVM Bazel integration.
The big change here is that we can configure the LLVM targets that are
built, which allows us to dramatically reduce the build costs by
focusing on a couple of CPUs for the time being.
There are a few API updates needed as well.
This also rotates the cache version so we start with a clean Bazel cache
from here. Otherwise we'd potentially pay the cost of carrying around
stale bits of LLVM endlessly.
The recovery is mostly useful when triaging multiple failures, it seems
easy for us to skip. Giving up the nice diagnostics doesn't lose much
for some types of error where there isn't any real information to
convey, so seems worth doing that for a few cases.
Removing the nice diagnostics from the rest of UBSan saves another
20%-ish of output size on LLVM, but seems like it would be giving up
usability. I think there are other approaches we can use instead so this
PR just focuses on the easy wins.
This is both a bit tricky and really easy with Bazel. The easy part,
especially compared to other build systems is that we can do this
regardless of the state of the repository -- Bazel will hermetically
check that everything is up-to-date, allowing the cache to be a bit
stale but still totally functional.
The easy part is that we can just ask Bazel to use an output base that
we cache and restore. This is super nice and even avoids most of the
Bazel installation bits.
The tricky part is that we need this to reconnect correctly to the
installed tree, so we need to exclude a crucial symlink that will then
get re-created at the right moment.
This gets really tricky due to LLVM and Clang (and this we would
struggle with no matter what build system we used). Building LLVM
creates a *ton* of object code. Just a huge amount. As a consequence,
we'd run into GitHub's limit for action cache size (5gb) really quickly
with 4 configurations.
So we can do another bit of tricky business and exclude the downloaded
`external` tree. This gets rebuilt easily, and there's no real need to
download it with the cached state -- its downloaded either way.
There are two follow-ups that I'd like to make here. One is to prod the
Bazel team to make things like persisting your output base a bit easier
to do reliably. Even better to make it easier to do *partial*
persisting.
Second follow-up is to work to make our usage of LLVM *much* less
wasteful. There are a bunch of steps here from changing how we use
sanitizers to how LLVM is built. Those will be follow-ups though.