xref: /openbmc/openbmc/poky/meta/recipes-devtools/rust/rust_1.85.1.bb (revision c9537f57ab488bf5d90132917b0184e2527970a5)
1SUMMARY = "Rust compiler and runtime libaries"
2HOMEPAGE = "http://www.rust-lang.org"
3SECTION = "devel"
4LICENSE = "(MIT | Apache-2.0) & Unicode-3.0"
5LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=9c0fae516fe8aaea2fb601db4800daf7"
6
7inherit rust
8inherit cargo_common
9
10DEPENDS += "rust-llvm"
11# native rust uses cargo/rustc from binary snapshots to bootstrap
12# but everything else should use our native builds
13DEPENDS:append:class-target = " cargo-native rust-native"
14DEPENDS:append:class-nativesdk = " cargo-native rust-native"
15
16RDEPENDS:${PN}:append:class-target = " gcc g++ binutils"
17
18# Otherwise we'll depend on what we provide
19INHIBIT_DEFAULT_RUST_DEPS:class-native = "1"
20# We don't need to depend on gcc-native because yocto assumes it exists
21PROVIDES:class-native = "virtual/${TARGET_PREFIX}rust"
22
23S = "${RUSTSRC}"
24
25# Use at your own risk, accepted values are stable, beta and nightly
26RUST_CHANNEL ?= "stable"
27PV .= "${@bb.utils.contains('RUST_CHANNEL', 'stable', '', '-${RUST_CHANNEL}', d)}"
28
29export FORCE_CRATE_HASH = "${BB_TASKHASH}"
30
31RUST_ALTERNATE_EXE_PATH ?= "${STAGING_LIBDIR}/llvm-rust/bin/llvm-config"
32RUST_ALTERNATE_EXE_PATH_NATIVE = "${STAGING_LIBDIR_NATIVE}/llvm-rust/bin/llvm-config"
33
34# We don't want to use bitbakes vendoring because the rust sources do their
35# own vendoring.
36CARGO_DISABLE_BITBAKE_VENDORING = "1"
37
38setup_cargo_environment () {
39    # The first step is to build bootstrap and some early stage tools,
40    # these are build for the same target as the snapshot, e.g.
41    # x86_64-unknown-linux-gnu.
42    # Later stages are build for the native target (i.e. target.x86_64-linux)
43    cargo_common_do_configure
44}
45
46inherit rust-target-config
47
48do_rust_setup_snapshot () {
49    for installer in "${UNPACKDIR}/rust-snapshot-components/"*"/install.sh"; do
50        "${installer}" --prefix="${WORKDIR}/rust-snapshot" --disable-ldconfig
51    done
52
53    # Some versions of rust (e.g. 1.18.0) tries to find cargo in stage0/bin/cargo
54    # and fail without it there.
55    mkdir -p ${RUSTSRC}/build/${RUST_BUILD_SYS}
56    ln -sf ${WORKDIR}/rust-snapshot/ ${RUSTSRC}/build/${RUST_BUILD_SYS}/stage0
57
58    # Need to use uninative's loader if enabled/present since the library paths
59    # are used internally by rust and result in symbol mismatches if we don't
60    if [ ! -z "${UNINATIVE_LOADER}" -a -e "${UNINATIVE_LOADER}" ]; then
61        for bin in cargo rustc rustdoc; do
62            patchelf ${WORKDIR}/rust-snapshot/bin/$bin --set-interpreter ${UNINATIVE_LOADER}
63        done
64    fi
65}
66addtask rust_setup_snapshot after do_unpack before do_configure
67addtask do_test_compile after do_configure do_rust_gen_targets
68do_rust_setup_snapshot[dirs] += "${WORKDIR}/rust-snapshot"
69do_rust_setup_snapshot[vardepsexclude] += "UNINATIVE_LOADER"
70do_rust_setup_snapshot[depends] += "patchelf-native:do_populate_sysroot"
71
72RUSTC_BOOTSTRAP = "${STAGING_BINDIR_NATIVE}/rustc"
73CARGO_BOOTSTRAP = "${STAGING_BINDIR_NATIVE}/cargo"
74RUSTC_BOOTSTRAP:class-native = "${WORKDIR}/rust-snapshot/bin/rustc"
75CARGO_BOOTSTRAP:class-native = "${WORKDIR}/rust-snapshot/bin/cargo"
76
77python do_configure() {
78    import json
79    import configparser
80
81    # toml is rather similar to standard ini like format except it likes values
82    # that look more JSON like. So for our purposes simply escaping all values
83    # as JSON seem to work fine.
84
85    e = lambda s: json.dumps(s)
86
87    config = configparser.RawConfigParser()
88
89    # [target.ARCH-poky-linux]
90    host_section = "target.{}".format(d.getVar('RUST_HOST_SYS'))
91    config.add_section(host_section)
92
93    llvm_config_target = d.expand("${RUST_ALTERNATE_EXE_PATH}")
94    llvm_config_build = d.expand("${RUST_ALTERNATE_EXE_PATH_NATIVE}")
95    config.set(host_section, "llvm-config", e(llvm_config_target))
96
97    config.set(host_section, "cxx", e(d.expand("${RUST_TARGET_CXX}")))
98    config.set(host_section, "cc", e(d.expand("${RUST_TARGET_CC}")))
99    config.set(host_section, "linker", e(d.expand("${RUST_TARGET_CCLD}")))
100    if "musl" in host_section:
101        config.set(host_section, "musl-root", e(d.expand("${STAGING_DIR_HOST}${exec_prefix}")))
102
103    # If we don't do this rust-native will compile it's own llvm for BUILD.
104    # [target.${BUILD_ARCH}-unknown-linux-gnu]
105    build_section = "target.{}".format(d.getVar('RUST_BUILD_SYS'))
106    if build_section != host_section:
107        config.add_section(build_section)
108
109        config.set(build_section, "llvm-config", e(llvm_config_build))
110
111        config.set(build_section, "cxx", e(d.expand("${RUST_BUILD_CXX}")))
112        config.set(build_section, "cc", e(d.expand("${RUST_BUILD_CC}")))
113        config.set(build_section, "linker", e(d.expand("${RUST_BUILD_CCLD}")))
114
115    target_section = "target.{}".format(d.getVar('RUST_TARGET_SYS'))
116    if target_section != host_section and target_section != build_section:
117        config.add_section(target_section)
118
119        config.set(target_section, "llvm-config", e(llvm_config_target))
120
121        config.set(target_section, "cxx", e(d.expand("${RUST_TARGET_CXX}")))
122        config.set(target_section, "cc", e(d.expand("${RUST_TARGET_CC}")))
123        config.set(target_section, "linker", e(d.expand("${RUST_TARGET_CCLD}")))
124
125    # [llvm]
126    config.add_section("llvm")
127    config.set("llvm", "static-libstdcpp", e(False))
128    config.set("llvm", "download-ci-llvm", e(False))
129    if "llvm" in (d.getVar('TC_CXX_RUNTIME') or ""):
130        config.set("llvm", "use-libcxx", e(True))
131
132    # [rust]
133    config.add_section("rust")
134    config.set("rust", "rpath", e(True))
135    config.set("rust", "remap-debuginfo", e(True))
136    config.set("rust", "download-rustc", e(False))
137    config.set("rust", "llvm-tools", e(False))
138    config.set("rust", "channel", e(d.expand("${RUST_CHANNEL}")))
139
140    # Whether or not to optimize the compiler and standard library
141    config.set("rust", "optimize", e(True))
142
143    # Emits extraneous output from tests to ensure that failures of the test
144    # harness are debuggable just from logfiles
145    config.set("rust", "verbose-tests", e(True))
146
147    # [build]
148    config.add_section("build")
149    config.set("build", "submodules", e(False))
150    config.set("build", "docs", e(False))
151
152    rustc = d.getVar('RUSTC_BOOTSTRAP')
153    config.set("build", "rustc", e(rustc))
154
155    cargo = d.getVar('CARGO_BOOTSTRAP')
156    config.set("build", "cargo", e(cargo))
157
158    config.set("build", "vendor", e(True))
159
160    config.set("build", "target", e([d.getVar("RUST_TARGET_SYS")]))
161
162    config.set("build", "host", e([d.getVar("RUST_HOST_SYS")]))
163
164    # We can't use BUILD_SYS since that is something the rust snapshot knows
165    # nothing about when trying to build some stage0 tools (like fabricate)
166    config.set("build", "build", e(d.getVar("RUST_BUILD_SYS")))
167
168    # [install]
169    config.add_section("install")
170    # ./x.py install doesn't have any notion of "destdir"
171    # but we can prepend ${D} to all the directories instead
172    config.set("install", "prefix",  e(d.getVar("D") + d.getVar("prefix")))
173    config.set("install", "bindir",  e(d.getVar("D") + d.getVar("bindir")))
174    config.set("install", "libdir",  e(d.getVar("D") + d.getVar("libdir")))
175    config.set("install", "datadir", e(d.getVar("D") + d.getVar("datadir")))
176    config.set("install", "mandir",  e(d.getVar("D") + d.getVar("mandir")))
177    config.set("install", "sysconfdir",  e(d.getVar("D") + d.getVar("sysconfdir")))
178
179    with open("config.toml", "w") as f:
180        f.write('change-id = 116881\n\n')
181        config.write(f)
182
183    # set up ${WORKDIR}/cargo_home
184    bb.build.exec_func("setup_cargo_environment", d)
185}
186
187rust_runx () {
188    echo "COMPILE ${PN}" "$@"
189
190    # CFLAGS, LDFLAGS, CXXFLAGS, CPPFLAGS are used by rust's build for a
191    # wide range of targets (not just TARGET). Yocto's settings for them will
192    # be inappropriate, avoid using.
193    unset CFLAGS
194    unset LDFLAGS
195    unset CXXFLAGS
196    unset CPPFLAGS
197
198    export RUSTFLAGS="${RUST_DEBUG_REMAP}"
199
200    # Copy the natively built llvm-config into the target so we can run it. Horrible,
201    # but works!
202    if [ ${RUST_ALTERNATE_EXE_PATH_NATIVE} != ${RUST_ALTERNATE_EXE_PATH} -a ! -f ${RUST_ALTERNATE_EXE_PATH} ]; then
203        mkdir -p `dirname ${RUST_ALTERNATE_EXE_PATH}`
204        cp ${RUST_ALTERNATE_EXE_PATH_NATIVE} ${RUST_ALTERNATE_EXE_PATH}
205        if [ -e ${STAGING_LIBDIR_NATIVE}/libc++.so.1 ]; then
206            patchelf --set-rpath \$ORIGIN/../../../../../`basename ${STAGING_DIR_NATIVE}`${libdir_native} ${RUST_ALTERNATE_EXE_PATH}
207        else
208            patchelf --remove-rpath ${RUST_ALTERNATE_EXE_PATH}
209        fi
210    fi
211
212    oe_cargo_fix_env
213
214    python3 src/bootstrap/bootstrap.py ${@oe.utils.parallel_make_argument(d, '-j %d')} "$@" --verbose
215}
216rust_runx[vardepsexclude] += "PARALLEL_MAKE"
217
218require rust-source.inc
219require rust-snapshot.inc
220
221INSANE_SKIP:${PN}:class-native = "already-stripped"
222FILES:${PN} += "${libdir}/rustlib"
223FILES:${PN} += "${libdir}/*.so"
224FILES:${PN}-dev = ""
225
226do_compile () {
227}
228
229do_test_compile[dirs] = "${B}"
230do_test_compile () {
231    rust_runx build src/tools/remote-test-server --target "${RUST_TARGET_SYS}"
232}
233
234ALLOW_EMPTY:${PN} = "1"
235
236PACKAGES =+ "${PN}-rustdoc ${PN}-tools-clippy ${PN}-tools-rustfmt"
237FILES:${PN}-rustdoc = "${bindir}/rustdoc"
238FILES:${PN}-tools-clippy = "${bindir}/cargo-clippy ${bindir}/clippy-driver"
239FILES:${PN}-tools-rustfmt = "${bindir}/rustfmt"
240RDEPENDS:${PN}-rustdoc = "${PN}"
241RDEPENDS:${PN}-tools-clippy = "${PN}"
242RDEPENDS:${PN}-tools-rustfmt = "${PN}"
243
244SUMMARY:${PN}-tools-clippy = "A collection of lints to catch common mistakes and improve your Rust code"
245SUMMARY:${PN}-tools-rustfmt = "A tool for formatting Rust code according to style guidelines"
246
247do_install () {
248    rust_do_install
249}
250
251rust_do_install() {
252    rust_runx install
253}
254
255rust_do_install:class-nativesdk() {
256    export PSEUDO_UNLOAD=1
257    rust_runx install
258    rust_runx install clippy
259    rust_runx install rustfmt
260    unset PSEUDO_UNLOAD
261
262    install -d ${D}${bindir}
263    for i in cargo-clippy clippy-driver rustfmt; do
264        cp build/${RUST_BUILD_SYS}/stage2-tools/${RUST_HOST_SYS}/release/$i ${D}${bindir}
265        patchelf --set-rpath "\$ORIGIN/../lib" ${D}${bindir}/$i
266    done
267
268    chown root:root ${D}/ -R
269    rm ${D}${libdir}/rustlib/uninstall.sh
270    rm ${D}${libdir}/rustlib/install.log
271    rm ${D}${libdir}/rustlib/manifest*
272    rm ${D}${libdir}/rustlib/${RUST_HOST_SYS}/lib/libstd*.so
273
274    ENV_SETUP_DIR=${D}${base_prefix}/environment-setup.d
275    mkdir "${ENV_SETUP_DIR}"
276    RUST_ENV_SETUP_SH="${ENV_SETUP_DIR}/rust.sh"
277    RUST_HOST_TRIPLE=`echo ${RUST_HOST_SYS} | tr '[:lower:]' '[:upper:]' | sed 's/-/_/g'`
278    RUST_HOST_CC=`echo ${RUST_HOST_SYS} | sed 's/-/_/g'`
279    SDKLOADER=${@bb.utils.contains('SDK_ARCH', 'x86_64', 'ld-linux-x86-64.so.2', '', d)}${@bb.utils.contains('SDK_ARCH', 'i686', 'ld-linux.so.2', '', d)}${@bb.utils.contains('SDK_ARCH', 'aarch64', 'ld-linux-aarch64.so.1', '', d)}${@bb.utils.contains('SDK_ARCH', 'ppc64le', 'ld64.so.2', '', d)}${@bb.utils.contains('SDK_ARCH', 'riscv64', 'ld-linux-riscv64-lp64d.so.1', '', d)}
280
281    cat <<- EOF > "${RUST_ENV_SETUP_SH}"
282	export CARGO_TARGET_${RUST_HOST_TRIPLE}_RUNNER="\$OECORE_NATIVE_SYSROOT/lib/${SDKLOADER}"
283	export CC_$RUST_HOST_CC="${CCACHE}${HOST_PREFIX}gcc"
284	EOF
285}
286
287FILES:${PN} += "${base_prefix}/environment-setup.d"
288
289EXTRA_TOOLS ?= "cargo-clippy clippy-driver rustfmt"
290rust_do_install:class-target() {
291    export PSEUDO_UNLOAD=1
292    rust_runx install
293    rust_runx install clippy
294    rust_runx install rustfmt
295    unset PSEUDO_UNLOAD
296
297    install -d ${D}${bindir}
298    for i in ${EXTRA_TOOLS}; do
299        cp build/${RUST_BUILD_SYS}/stage2-tools/${RUST_HOST_SYS}/release/$i ${D}${bindir}
300        patchelf --set-rpath "\$ORIGIN/../lib" ${D}${bindir}/$i
301    done
302
303    install -d ${D}${libdir}/rustlib/${RUST_HOST_SYS}
304    install -m 0644 ${WORKDIR}/rust-targets/${RUST_HOST_SYS}.json ${D}${libdir}/rustlib/${RUST_HOST_SYS}/target.json
305
306    chown root:root ${D}/ -R
307    rm ${D}${libdir}/rustlib/uninstall.sh
308    rm ${D}${libdir}/rustlib/install.log
309    rm ${D}${libdir}/rustlib/manifest*
310    rm ${D}${libdir}/rustlib/${RUST_HOST_SYS}/lib/libstd*.so
311}
312
313addtask do_update_snapshot after do_patch
314do_update_snapshot[nostamp] = "1"
315
316# Run with `bitbake -c update_snapshot rust` to update `rust-snapshot.inc`
317# with the checksums for the rust snapshot associated with this rustc-src
318# tarball.
319python do_update_snapshot() {
320    import json
321    import re
322    import sys
323
324    from collections import defaultdict
325
326    key_value_pairs = {}
327    with open(os.path.join(d.getVar("S"), "src", "stage0")) as f:
328        for line in f:
329            # Skip empty lines or comments
330            if not line.strip() or line.startswith("#"):
331                continue
332            # Split the line into key and value using '=' as separator
333            match = re.match(r'(\S+)\s*=\s*(\S+)', line.strip())
334            if match:
335                key = match.group(1)
336                value = match.group(2)
337                key_value_pairs[key] = value
338    # Extract the required values from key_value_pairs
339    config_dist_server = key_value_pairs.get('dist_server', '')
340    compiler_date = key_value_pairs.get('compiler_date', '')
341    compiler_version = key_value_pairs.get('compiler_version', '')
342
343    src_uri = defaultdict(list)
344    # Assuming checksums_sha256 is now a key-value pair like: checksum_key = checksum_value
345    for k, v in key_value_pairs.items():
346        # Match the pattern for checksums
347        if "dist" in k and "tar.xz" in k:
348            m = re.search(f"dist/{compiler_date}/(?P<component>.*)-{compiler_version}-(?P<arch>.*)-unknown-linux-gnu\\.tar\\.xz", k)
349            if m:
350                component = m.group('component')
351                arch = m.group('arch')
352                src_uri[arch].append(f"SRC_URI[{component}-snapshot-{arch}.sha256sum] = \"{v}\"")
353    # Create the snapshot string with the extracted values
354    snapshot = """\
355## This is information on the rust-snapshot (binary) used to build our current release.
356## snapshot info is taken from rust/src/stage0
357## Rust is self-hosting and bootstraps itself with a pre-built previous version of itself.
358## The exact (previous) version that has been used is specified in the source tarball.
359## The version is replicated here.
360
361SNAPSHOT_VERSION = "%s"
362
363""" % compiler_version
364    # Add the checksum components to the snapshot
365    for arch, components in src_uri.items():
366        snapshot += "\n".join(components) + "\n\n"
367    # Add the additional snapshot URIs
368    snapshot += """\
369SRC_URI += " \\
370    ${RUST_DIST_SERVER}/dist/${RUST_STD_SNAPSHOT}.tar.xz;name=rust-std-snapshot-${RUST_BUILD_ARCH};subdir=rust-snapshot-components \\
371    ${RUST_DIST_SERVER}/dist/${RUSTC_SNAPSHOT}.tar.xz;name=rustc-snapshot-${RUST_BUILD_ARCH};subdir=rust-snapshot-components \\
372    ${RUST_DIST_SERVER}/dist/${CARGO_SNAPSHOT}.tar.xz;name=cargo-snapshot-${RUST_BUILD_ARCH};subdir=rust-snapshot-components \\
373"
374
375RUST_DIST_SERVER = "%s"
376
377RUST_STD_SNAPSHOT = "rust-std-${SNAPSHOT_VERSION}-${RUST_BUILD_ARCH}-unknown-linux-gnu"
378RUSTC_SNAPSHOT = "rustc-${SNAPSHOT_VERSION}-${RUST_BUILD_ARCH}-unknown-linux-gnu"
379CARGO_SNAPSHOT = "cargo-${SNAPSHOT_VERSION}-${RUST_BUILD_ARCH}-unknown-linux-gnu"
380""" % config_dist_server
381    # Write the updated snapshot information to the rust-snapshot.inc file
382    with open(os.path.join(d.getVar("THISDIR"), "rust-snapshot.inc"), "w") as f:
383        f.write(snapshot)
384}
385
386RUSTLIB_DEP:class-nativesdk = ""
387
388# musl builds include libunwind.a
389INSANE_SKIP:${PN} = "staticdev"
390
391BBCLASSEXTEND = "native nativesdk"
392