Skip to content

Commit 0102f80

Browse files
committed
Merge bitcoin#21375: guix: Misc feedback-based fixes + hier restructuring
7476b46 guix: Build dmg as a static binary (Carl Dong) 06d6cf6 depends: libdmg-hfsplus: Skip CMake RPATH patching (Carl Dong) 65176ab guix: Remove codesign_allocate+pagestuff from unsigned tarball (Carl Dong) ca85679 guix: Use clang-toolchain instead of clang (Carl Dong) 1aec0ed guix: Fallback to local build for substitute-enabled Guix users (Carl Dong) 1742f8e guix: Add early health check for guix-daemon (Carl Dong) c1ae726 guix: More thoroughly control native toolchain (Carl Dong) 3974112 guix: Supply --link-profile (Carl Dong) d55a105 guix: Add troubleshooting documentation entries (Carl Dong) 7f401c9 guix: Adapt guix-build to prelude, restructure hier (Carl Dong) 4eccf06 guix: Remove guix-build.sh filename extension (Carl Dong) 7753357 guix: Add source-able bash prelude and utils (Carl Dong) e5b49a0 guix: Create windeploy inside distsrc-* (Carl Dong) 3e9982a contrib: Silence git-describe when looking for tag (Carl Dong) d5a71e9 guix: Use --cores instead of --max-jobs (Carl Dong) Pull request description: This PR addresses a few hiccups encountered by the brave souls who've been experimenting with the Guix scripts: - Resolves confusion between `--cores=` and `--max-jobs=` - `guix`'s `--cores=` actually corresponds to make's `--jobs=`, so let's just control `--cores=` with our overridable env var - `git-describe` will scream `fatal: no tag exactly matches '<hash>'` when looking for a tag, but we don't care, so silence that - `windeploy/unsigned` should be inside `distsrc-*` and created idempotently (sorry I know this one annoyed people) - Add troubleshooting documentation to `README.md` - Add early health check for `guix-daemon` in case user forgot to start a `guix-daemon` - Depending on configuration, a `--fallback` flag may be needed to tell Guix to not fail if substitutes fail but fallback to building locally - `codesign_allocate` and `pagestuff` are now unnecessary for codesigning as we're now using `signapple` A few robustness changes are also included: - We supply the `--link-profile` flag, as some Guix packages may expect the profile to be available under `$HOME/.guix-profile` - We now clear and manually set all toolchain-related env vars (e.g. `C*_INCLUDE_PATH`) ourselves, after patching a Qt::moc bug - We use the native `clang-toolchain` package for darwin builds instead of `clang`, lining up with all our other toolchain packages. Finally, we restructure the guix building hierarchy such that it looks something like: ``` guix-build-<short-hash-or-version-tag> ├── distsrc-<short-hash-or-version-tag>-${HOST} │ ├── contrib │ ├── depends │ ├── src │ └── ... ├── distsrc-<short-hash-or-version-tag>-... └── output ├── dist-archive │ └── bitcoin-<short-hash-or-version-tag>.tar.gz ├── *-linux-* │ ├── bitcoin-<short-hash-or-version-tag>-*-linux-*-debug.tar.gz │ └── bitcoin-<short-hash-or-version-tag>-*-linux-*.tar.gz ├── x86_64-apple-darwin18 │ ├── bitcoin-<short-hash-or-version-tag>-osx64.tar.gz │ ├── bitcoin-<short-hash-or-version-tag>-osx-unsigned.dmg │ └── bitcoin-<short-hash-or-version-tag>-osx-unsigned.tar.gz └── x86_64-w64-mingw32 ├── bitcoin-<short-hash-or-version-tag>-win64-debug.zip ├── bitcoin-<short-hash-or-version-tag>-win64-setup-unsigned.exe ├── bitcoin-<short-hash-or-version-tag>-win64.zip └── bitcoin-<short-hash-or-version-tag>-win-unsigned.tar.gz ``` Separating guix builds by their version identifier (basically namespacing them) allows us to change the layout in the future without worry about potential naming conflicts. ACKs for top commit: sipa: ACK 7476b46 laanwj: ACK 7476b46 Tree-SHA512: 0e899aa941aafdf552b2a7e8a08131ee9283180bbef7334439e2461a02aa7235ab7b9ca9c149b80fc5d0a9f4bbd35bc80fcee26197c0836ba8eaf2d86ffa0386
2 parents 1ea5c7e + 7476b46 commit 0102f80

File tree

12 files changed

+401
-78
lines changed

12 files changed

+401
-78
lines changed

Diff for: contrib/gitian-descriptors/assign_DISTNAME

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55
# A helper script to be sourced into the gitian descriptors
66

7-
if RECENT_TAG="$(git describe --exact-match HEAD)"; then
7+
if RECENT_TAG="$(git describe --exact-match HEAD 2> /dev/null)"; then
88
VERSION="${RECENT_TAG#v}"
99
else
1010
VERSION="$(git rev-parse --short=12 HEAD)"

Diff for: contrib/guix/README.md

+104-5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,50 @@ at the end of the `guix pull`)
8080
export PATH="${HOME}/.config/guix/current/bin${PATH:+:}$PATH"
8181
```
8282

83+
### Controlling the number of threads used by `guix` build commands
84+
85+
By default, the scripts under `./contrib/guix` will invoke all `guix` build
86+
commands with `--cores="$JOBS"`. Note that `$JOBS` defaults to `$(nproc)` if not
87+
specified. However, astute manual readers will also notice that there is a
88+
`--max-jobs=` flag (which defaults to 1 if unspecified).
89+
90+
Here is the difference between `--cores=` and `--max-jobs=`:
91+
92+
> Note: When I say "derivation," think "package"
93+
94+
`--cores=`
95+
96+
- controls the number of CPU cores to build each derivation. This is the value
97+
passed to `make`'s `--jobs=` flag.
98+
99+
`--max-jobs=`
100+
101+
- controls how many derivations can be built in parallel
102+
- defaults to 1
103+
104+
Therefore, the default is for `guix` build commands to build one derivation at a
105+
time, utilizing `$JOBS` threads.
106+
107+
Specifying the `$JOBS` environment variable will only modify `--cores=`, but you
108+
can also modify the value for `--max-jobs=` by specifying
109+
`$ADDITIONAL_GUIX_COMMON_FLAGS`. For example, if you have a LOT of memory, you
110+
may want to set:
111+
112+
```sh
113+
export ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8'
114+
```
115+
116+
Which allows for a maximum of 8 derivations to be built at the same time, each
117+
utilizing `$JOBS` threads.
118+
119+
Or, if you'd like to avoid spurious build failures caused by issues with
120+
parallelism within a single package, but would still like to build multiple
121+
packages when the dependency graph allows for it, you may want to try:
122+
123+
```sh
124+
export JOBS=1 ADDITIONAL_GUIX_COMMON_FLAGS='--max-jobs=8'
125+
```
126+
83127
## Usage
84128

85129
### As a Tool for Deterministic Builds
@@ -125,12 +169,16 @@ find output/ -type f -print0 | sort -z | xargs -r0 sha256sum
125169
the actual SDK (e.g. SDK_PATH=$HOME/Downloads/macOS-SDKs instead of
126170
$HOME/Downloads/macOS-SDKs/Xcode-11.3.1-11C505-extracted-SDK-with-libcxx-headers).
127171

128-
* _**MAX_JOBS**_
172+
* _**JOBS**_
173+
174+
Override the number of jobs to run simultaneously, you might want to do so on
175+
a memory-limited machine. This may be passed to:
176+
177+
- `guix` build commands as in `guix environment --cores="$JOBS"`
178+
- `make` as in `make --jobs="$JOBS"`
179+
- `xargs` as in `xargs -P"$JOBS"`
129180

130-
Override the maximum number of jobs to run simultaneously, you might want to
131-
do so on a memory-limited machine. This may be passed to `make` as in `make
132-
--jobs="$MAX_JOBS"` or `xargs` as in `xargs -P"$MAX_JOBS"`. _(defaults to the
133-
value of `nproc` outside the container)_
181+
_(defaults to the value of `nproc` outside the container)_
134182

135183
* _**SOURCE_DATE_EPOCH**_
136184

@@ -217,6 +265,57 @@ To use dongcarl's substitute server for Bitcoin Core builds after having
217265
export SUBSTITUTE_URLS='https://guix.carldong.io https://ci.guix.gnu.org'
218266
```
219267

268+
## Troubleshooting
269+
270+
### Derivation failed to build
271+
272+
When you see a build failure like below:
273+
274+
```
275+
building /gnu/store/...-foo-3.6.12.drv...
276+
/ 'check' phasenote: keeping build directory `/tmp/guix-build-foo-3.6.12.drv-0'
277+
builder for `/gnu/store/...-foo-3.6.12.drv' failed with exit code 1
278+
build of /gnu/store/...-foo-3.6.12.drv failed
279+
View build log at '/var/log/guix/drvs/../...-foo-3.6.12.drv.bz2'.
280+
cannot build derivation `/gnu/store/...-qux-7.69.1.drv': 1 dependencies couldn't be built
281+
cannot build derivation `/gnu/store/...-bar-3.16.5.drv': 1 dependencies couldn't be built
282+
cannot build derivation `/gnu/store/...-baz-2.0.5.drv': 1 dependencies couldn't be built
283+
guix time-machine: error: build of `/gnu/store/...-baz-2.0.5.drv' failed
284+
```
285+
286+
It means that `guix` failed to build a package named `foo`, which was a
287+
dependency of `qux`, `bar`, and `baz`. Importantly, note that the last "failed"
288+
line is not necessarily the root cause, the first "failed" line is.
289+
290+
Most of the time, the build failure is due to a spurious test failure or the
291+
package's build system/test suite breaking when running multi-threaded. To
292+
rebuild _just_ this derivation in a single-threaded fashion:
293+
294+
```sh
295+
$ guix build --cores=1 /gnu/store/...-foo-3.6.12.drv
296+
```
297+
298+
If the single-threaded rebuild stil did not succeed, you may need to dig deeper.
299+
You may view `foo`'s build logs in `less` like so (please replace paths with the
300+
path you see in the build failure output):
301+
302+
```sh
303+
$ bzcat /var/log/guix/drvs/../...-foo-3.6.12.drv.bz2 | less
304+
```
305+
306+
`foo`'s build directory is also preserved and available at
307+
`/tmp/guix-build-foo-3.6.12.drv-0`. However, if you fail to build `foo` multiple
308+
times, it may be `/tmp/...drv-1` or `/tmp/...drv-2`. Always consult the build
309+
failure output for the most accurate, up-to-date information.
310+
311+
#### python(-minimal): [Errno 84] Invalid or incomplete multibyte or wide character
312+
313+
This error occurs when your `$TMPDIR` (default: /tmp) exists on a filesystem
314+
which rejects characters not present in the UTF-8 character code set. An example
315+
is ZFS with the utf8only=on option set.
316+
317+
More information: https://bugs.python.org/issue37584
318+
220319
## FAQ
221320

222321
### How can I trust the binary installation?

Diff for: contrib/guix/guix-build.sh renamed to contrib/guix/guix-build

+76-33
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22
export LC_ALL=C
33
set -e -o pipefail
44

5+
# Source the common prelude, which:
6+
# 1. Checks if we're at the top directory of the Bitcoin Core repository
7+
# 2. Defines a few common functions and variables
8+
#
9+
# shellcheck source=libexec/prelude.bash
10+
source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
11+
12+
513
###################
6-
## Sanity Checks ##
14+
## SANITY CHECKS ##
715
###################
816

917
################
10-
# Check 1: Make sure that we can invoke required tools
18+
# Required non-builtin commands should be invokable
1119
################
12-
for cmd in git make guix cat mkdir curl; do
13-
if ! command -v "$cmd" > /dev/null 2>&1; then
14-
echo "ERR: This script requires that '$cmd' is installed and available in your \$PATH"
15-
exit 1
16-
fi
17-
done
20+
21+
check_tools cat mkdir make git guix
1822

1923
################
20-
# Check 2: Make sure GUIX_BUILD_OPTIONS is empty
24+
# GUIX_BUILD_OPTIONS should be empty
2125
################
2226
#
2327
# GUIX_BUILD_OPTIONS is an environment variable recognized by guix commands that
@@ -45,8 +49,9 @@ exit 1
4549
fi
4650

4751
################
48-
# Check 3: Make sure that we're not in a dirty worktree
52+
# The git worktree should not be dirty
4953
################
54+
5055
if ! git diff-index --quiet HEAD -- && [ -z "$FORCE_DIRTY_WORKTREE" ]; then
5156
cat << EOF
5257
ERR: The current git worktree is dirty, which may lead to broken builds.
@@ -60,27 +65,25 @@ Hint: To make your git worktree clean, You may want to:
6065
using a dirty worktree
6166
EOF
6267
exit 1
63-
else
64-
GIT_COMMIT=$(git rev-parse --short=12 HEAD)
6568
fi
6669

70+
mkdir -p "$VERSION_BASE"
71+
6772
################
68-
# Check 4: Make sure that build directories do not exist
73+
# Build directories should not exist
6974
################
7075

7176
# Default to building for all supported HOSTs (overridable by environment)
7277
export HOSTS="${HOSTS:-x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu powerpc64-linux-gnu powerpc64le-linux-gnu
7378
x86_64-w64-mingw32
7479
x86_64-apple-darwin18}"
7580

76-
DISTSRC_BASE="${DISTSRC_BASE:-${PWD}}"
77-
7881
# Usage: distsrc_for_host HOST
7982
#
8083
# HOST: The current platform triple we're building for
8184
#
8285
distsrc_for_host() {
83-
echo "${DISTSRC_BASE}/distsrc-${GIT_COMMIT}-${1}"
86+
echo "${DISTSRC_BASE}/distsrc-${VERSION}-${1}"
8487
}
8588

8689
# Accumulate a list of build directories that already exist...
@@ -106,12 +109,11 @@ for host in $hosts_distsrc_exists; do
106109
done
107110
exit 1
108111
else
109-
110112
mkdir -p "$DISTSRC_BASE"
111113
fi
112114

113115
################
114-
# Check 5: When building for darwin, make sure that the macOS SDK exists
116+
# When building for darwin, the macOS SDK should exists
115117
################
116118

117119
for host in $HOSTS; do
@@ -128,13 +130,40 @@ for host in $HOSTS; do
128130
esac
129131
done
130132

133+
################
134+
# Check that we can connect to the guix-daemon
135+
################
136+
137+
cat << EOF
138+
Checking that we can connect to the guix-daemon...
139+
140+
Hint: If this hangs, you may want to try turning your guix-daemon off and on
141+
again.
142+
143+
EOF
144+
if ! guix gc --list-failures > /dev/null; then
145+
cat << EOF
146+
147+
ERR: Failed to connect to the guix-daemon, please ensure that one is running and
148+
reachable.
149+
EOF
150+
exit 1
151+
fi
152+
153+
# Developer note: we could use `guix repl` for this check and run:
154+
#
155+
# (import (guix store)) (close-connection (open-connection))
156+
#
157+
# However, the internal API is likely to change more than the CLI invocation
158+
159+
131160
#########
132-
# Setup #
161+
# SETUP #
133162
#########
134163

135164
# Determine the maximum number of jobs to run simultaneously (overridable by
136165
# environment)
137-
MAX_JOBS="${MAX_JOBS:-$(nproc)}"
166+
JOBS="${JOBS:-$(nproc)}"
138167

139168
# Usage: host_to_commonname HOST
140169
#
@@ -152,7 +181,7 @@ host_to_commonname() {
152181
# Download the depends sources now as we won't have internet access in the build
153182
# container
154183
for host in $HOSTS; do
155-
make -C "${PWD}/depends" -j"$MAX_JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
184+
make -C "${PWD}/depends" -j"$JOBS" download-"$(host_to_commonname "$host")" ${V:+V=1} ${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"}
156185
done
157186

158187
# Determine the reference time used for determinism (overridable by environment)
@@ -164,19 +193,29 @@ time-machine() {
164193
# shellcheck disable=SC2086
165194
guix time-machine --url=https://github.com/dongcarl/guix.git \
166195
--commit=490e39ff303f4f6873a04bfb8253755bdae1b29c \
167-
--max-jobs="$MAX_JOBS" \
196+
--cores="$JOBS" \
168197
--keep-failed \
198+
--fallback \
169199
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
170200
${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_TIMEMACHINE_FLAGS} \
171201
-- "$@"
172202
}
173203

174204
# Make sure an output directory exists for our builds
175-
OUTDIR="${OUTDIR:-${PWD}/output}"
176-
[ -e "$OUTDIR" ] || mkdir -p "$OUTDIR"
205+
OUTDIR_BASE="${OUTDIR_BASE:-${VERSION_BASE}/output}"
206+
mkdir -p "$OUTDIR_BASE"
207+
208+
# Usage: outdir_for_host HOST
209+
#
210+
# HOST: The current platform triple we're building for
211+
#
212+
outdir_for_host() {
213+
echo "${OUTDIR_BASE}/${1}"
214+
}
215+
177216

178217
#########
179-
# Build #
218+
# BUILD #
180219
#########
181220

182221
# Function to be called when building for host ${1} and the user interrupts the
@@ -216,15 +255,15 @@ for host in $HOSTS; do
216255

217256
# shellcheck disable=SC2030
218257
cat << EOF
219-
INFO: Building commit ${GIT_COMMIT:?not set} for platform triple ${HOST:?not set}:
258+
INFO: Building ${VERSION:?not set} for platform triple ${HOST:?not set}:
220259
...using reference timestamp: ${SOURCE_DATE_EPOCH:?not set}
221-
...running at most ${MAX_JOBS:?not set} jobs
260+
...running at most ${JOBS:?not set} jobs
222261
...from worktree directory: '${PWD}'
223262
...bind-mounted in container to: '/bitcoin'
224263
...in build directory: '$(distsrc_for_host "$HOST")'
225264
...bind-mounted in container to: '$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")'
226-
...outputting in: '${OUTDIR:?not set}'
227-
...bind-mounted in container to: '/outdir'
265+
...outdirting in: '$(outdir_for_host "$HOST")'
266+
...bind-mounted in container to: '$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST")'
228267
EOF
229268

230269
# Run the build script 'contrib/guix/libexec/build.sh' in the build
@@ -299,24 +338,28 @@ EOF
299338
--no-cwd \
300339
--share="$PWD"=/bitcoin \
301340
--share="$DISTSRC_BASE"=/distsrc-base \
302-
--share="$OUTDIR"=/outdir \
341+
--share="$OUTDIR_BASE"=/outdir-base \
303342
--expose="$(git rev-parse --git-common-dir)" \
304343
${SOURCES_PATH:+--share="$SOURCES_PATH"} \
305344
${BASE_CACHE:+--share="$BASE_CACHE"} \
306345
${SDK_PATH:+--share="$SDK_PATH"} \
307-
--max-jobs="$MAX_JOBS" \
346+
--cores="$JOBS" \
308347
--keep-failed \
348+
--fallback \
349+
--link-profile \
309350
${SUBSTITUTE_URLS:+--substitute-urls="$SUBSTITUTE_URLS"} \
310351
${ADDITIONAL_GUIX_COMMON_FLAGS} ${ADDITIONAL_GUIX_ENVIRONMENT_FLAGS} \
311352
-- env HOST="$host" \
312-
MAX_JOBS="$MAX_JOBS" \
353+
DISTNAME="$DISTNAME" \
354+
JOBS="$JOBS" \
313355
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:?unable to determine value}" \
314356
${V:+V=1} \
315357
${SOURCES_PATH:+SOURCES_PATH="$SOURCES_PATH"} \
316358
${BASE_CACHE:+BASE_CACHE="$BASE_CACHE"} \
317359
${SDK_PATH:+SDK_PATH="$SDK_PATH"} \
318360
DISTSRC="$(DISTSRC_BASE=/distsrc-base && distsrc_for_host "$HOST")" \
319-
OUTDIR=/outdir \
361+
OUTDIR="$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST")" \
362+
DIST_ARCHIVE_BASE=/outdir-base/dist-archive \
320363
bash -c "cd /bitcoin && bash contrib/guix/libexec/build.sh"
321364
)
322365

0 commit comments

Comments
 (0)