mirror of
https://git.yoctoproject.org/poky
synced 2026-01-29 21:08:42 +01:00
The cargo class defaults to out-of-tree builds in WORKDIR/build, but
at no point was that directory cleaned. This causes problems with the
rust standard library recipe (libstd-rs) which installs manually with cp,
so rebuilds can be contaminated with the contents of previous builds.
I believe that post-release we should switch cargo.bbclass to mandating
out-of-tree builds to reduce the complexity, but for now in out-of-tree
builds we can just delete the ${B}/target directory.
Note that we use ${B}/target because there at least were reasons to use
that name[1], it is unclear if these limitations still hold. We can't
simply clean ${B} because that will break recipes that use cargo and
something else to build, for example librsvg.
[1] https://github.com/rust-lang/cargo/pull/1657
(From OE-Core rev: 1452ac7a44196454a52f3f6d883290ddcccfd3f8)
(From OE-Core rev: 9d9ce457630ea7403ffe7028e3370647db0b83fa)
Signed-off-by: Ross Burton <ross.burton@arm.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
243 lines
7.3 KiB
Plaintext
243 lines
7.3 KiB
Plaintext
#
|
|
# Copyright OpenEmbedded Contributors
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
#
|
|
|
|
##
|
|
## Purpose:
|
|
## This class is to support building with cargo. It
|
|
## must be different than cargo.bbclass because Rust
|
|
## now builds with Cargo but cannot use cargo.bbclass
|
|
## due to dependencies and assumptions in cargo.bbclass
|
|
## that Rust & Cargo are already installed. So this
|
|
## is used by cargo.bbclass and Rust
|
|
##
|
|
|
|
# add crate fetch support
|
|
inherit rust-common
|
|
|
|
# Where we download our registry and dependencies to
|
|
export CARGO_HOME = "${UNPACKDIR}/cargo_home"
|
|
|
|
# The pkg-config-rs library used by cargo build scripts disables itself when
|
|
# cross compiling unless this is defined. We set up pkg-config appropriately
|
|
# for cross compilation, so tell it we know better than it.
|
|
export PKG_CONFIG_ALLOW_CROSS = "1"
|
|
|
|
# Don't instruct cargo to use crates downloaded by bitbake. Some rust packages,
|
|
# for example the rust compiler itself, come with their own vendored sources.
|
|
# Specifying two [source.crates-io] will not work.
|
|
CARGO_DISABLE_BITBAKE_VENDORING ??= "0"
|
|
|
|
# Used by libstd-rs to point to the vendor dir included in rustc src
|
|
CARGO_VENDORING_DIRECTORY ??= "${CARGO_HOME}/bitbake"
|
|
|
|
# The directory of the Cargo.toml relative to the root directory, per default
|
|
# assume there's a Cargo.toml directly in the root directory
|
|
CARGO_SRC_DIR ??= ""
|
|
|
|
# The actual path to the Cargo.toml
|
|
CARGO_MANIFEST_PATH ??= "${S}/${CARGO_SRC_DIR}/Cargo.toml"
|
|
|
|
# Path to Cargo.lock
|
|
CARGO_LOCK_PATH ??= "${@ os.path.join(os.path.dirname(d.getVar('CARGO_MANIFEST_PATH')), 'Cargo.lock')}"
|
|
|
|
CARGO_RUST_TARGET_CCLD ??= "${RUST_TARGET_CCLD}"
|
|
cargo_common_do_configure () {
|
|
mkdir -p ${CARGO_HOME}/bitbake
|
|
|
|
cat <<- EOF > ${CARGO_HOME}/config.toml
|
|
# EXTRA_OECARGO_PATHS
|
|
paths = [
|
|
$(for p in ${EXTRA_OECARGO_PATHS}; do echo \"$p\",; done)
|
|
]
|
|
EOF
|
|
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
# Local mirror vendored by bitbake
|
|
[source.bitbake]
|
|
directory = "${CARGO_VENDORING_DIRECTORY}"
|
|
EOF
|
|
|
|
if [ ${CARGO_DISABLE_BITBAKE_VENDORING} = "0" ]; then
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
[source.crates-io]
|
|
replace-with = "bitbake"
|
|
local-registry = "/nonexistent"
|
|
EOF
|
|
fi
|
|
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
[http]
|
|
# Multiplexing can't be enabled because http2 can't be enabled
|
|
# in curl-native without dependency loops
|
|
multiplexing = false
|
|
|
|
# Ignore the hard coded and incorrect path to certificates
|
|
cainfo = "${STAGING_ETCDIR_NATIVE}/ssl/certs/ca-certificates.crt"
|
|
|
|
EOF
|
|
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
# HOST_SYS
|
|
[target.${RUST_HOST_SYS}]
|
|
linker = "${CARGO_RUST_TARGET_CCLD}"
|
|
EOF
|
|
|
|
if [ "${RUST_HOST_SYS}" != "${RUST_BUILD_SYS}" ]; then
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
# BUILD_SYS
|
|
[target.${RUST_BUILD_SYS}]
|
|
linker = "${RUST_BUILD_CCLD}"
|
|
EOF
|
|
fi
|
|
|
|
if [ "${RUST_TARGET_SYS}" != "${RUST_BUILD_SYS}" -a "${RUST_TARGET_SYS}" != "${RUST_HOST_SYS}" ]; then
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
# TARGET_SYS
|
|
[target.${RUST_TARGET_SYS}]
|
|
linker = "${RUST_TARGET_CCLD}"
|
|
EOF
|
|
fi
|
|
|
|
# Put build output in build directory preferred by bitbake instead of
|
|
# inside source directory unless they are the same
|
|
if [ "${B}" != "${S}" ]; then
|
|
# We should consider mandating out-of-tree builds and just using [cleandirs]
|
|
rm -rf ${B}/target
|
|
mkdir -p ${B}
|
|
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
[build]
|
|
# Use out of tree build destination to avoid polluting the source tree
|
|
target-dir = "${B}/target"
|
|
EOF
|
|
fi
|
|
|
|
cat <<- EOF >> ${CARGO_HOME}/config.toml
|
|
|
|
[term]
|
|
progress.when = 'always'
|
|
progress.width = 80
|
|
EOF
|
|
}
|
|
|
|
python cargo_common_do_patch_paths() {
|
|
import shutil
|
|
|
|
cargo_config = os.path.join(d.getVar("CARGO_HOME"), "config.toml")
|
|
if not os.path.exists(cargo_config):
|
|
return
|
|
|
|
src_uri = (d.getVar('SRC_URI') or "").split()
|
|
if len(src_uri) == 0:
|
|
return
|
|
|
|
patches = dict()
|
|
workdir = d.getVar('UNPACKDIR')
|
|
fetcher = bb.fetch2.Fetch(src_uri, d)
|
|
for url in fetcher.urls:
|
|
ud = fetcher.ud[url]
|
|
if ud.type == 'git' or ud.type == 'gitsm':
|
|
name = ud.parm.get('name')
|
|
destsuffix = ud.parm.get('destsuffix')
|
|
if name is not None and destsuffix is not None:
|
|
if ud.user:
|
|
repo = '%s://%s@%s%s' % (ud.proto, ud.user, ud.host, ud.path)
|
|
else:
|
|
repo = '%s://%s%s' % (ud.proto, ud.host, ud.path)
|
|
path = '%s = { path = "%s" }' % (name, os.path.join(workdir, destsuffix))
|
|
patches.setdefault(repo, []).append(path)
|
|
|
|
with open(cargo_config, "a+") as config:
|
|
for k, v in patches.items():
|
|
print('\n[patch."%s"]' % k, file=config)
|
|
for name in v:
|
|
print(name, file=config)
|
|
|
|
if not patches:
|
|
return
|
|
|
|
# Cargo.lock file is needed for to be sure that artifacts
|
|
# downloaded by the fetch steps are those expected by the
|
|
# project and that the possible patches are correctly applied.
|
|
# Moreover since we do not want any modification
|
|
# of this file (for reproducibility purpose), we prevent it by
|
|
# using --frozen flag (in CARGO_BUILD_FLAGS) and raise a clear error
|
|
# here is better than letting cargo tell (in case the file is missing)
|
|
# "Cargo.lock should be modified but --frozen was given"
|
|
|
|
lockfile = d.getVar("CARGO_LOCK_PATH")
|
|
if not os.path.exists(lockfile):
|
|
bb.fatal(f"{lockfile} file doesn't exist")
|
|
|
|
# There are patched files and so Cargo.lock should be modified but we use
|
|
# --frozen so let's handle that modifications here.
|
|
#
|
|
# Note that a "better" (more elegant ?) would have been to use cargo update for
|
|
# patched packages:
|
|
# cargo update --offline -p package_1 -p package_2
|
|
# But this is not possible since it requires that cargo local git db
|
|
# to be populated and this is not the case as we fetch git repo ourself.
|
|
|
|
lockfile_orig = lockfile + ".orig"
|
|
if not os.path.exists(lockfile_orig):
|
|
shutil.copy(lockfile, lockfile_orig)
|
|
|
|
newlines = []
|
|
with open(lockfile_orig, "r") as f:
|
|
for line in f.readlines():
|
|
if not line.startswith("source = \"git"):
|
|
newlines.append(line)
|
|
|
|
with open(lockfile, "w") as f:
|
|
f.writelines(newlines)
|
|
}
|
|
do_configure[postfuncs] += "cargo_common_do_patch_paths"
|
|
|
|
do_compile:prepend () {
|
|
oe_cargo_fix_env
|
|
}
|
|
|
|
oe_cargo_fix_env () {
|
|
export CC="${RUST_TARGET_CC}"
|
|
export CXX="${RUST_TARGET_CXX}"
|
|
export CFLAGS="${CFLAGS}"
|
|
export CXXFLAGS="${CXXFLAGS}"
|
|
export AR="${AR}"
|
|
export TARGET_CC="${RUST_TARGET_CC}"
|
|
export TARGET_CXX="${RUST_TARGET_CXX}"
|
|
export TARGET_CFLAGS="${CFLAGS}"
|
|
export TARGET_CXXFLAGS="${CXXFLAGS}"
|
|
export TARGET_AR="${AR}"
|
|
export HOST_CC="${RUST_BUILD_CC}"
|
|
export HOST_CXX="${RUST_BUILD_CXX}"
|
|
export HOST_CFLAGS="${BUILD_CFLAGS}"
|
|
export HOST_CXXFLAGS="${BUILD_CXXFLAGS}"
|
|
export HOST_AR="${BUILD_AR}"
|
|
}
|
|
|
|
EXTRA_OECARGO_PATHS ??= ""
|
|
|
|
EXPORT_FUNCTIONS do_configure
|
|
|
|
# The culprit for this setting is the libc crate,
|
|
# which as of Jun 2023 calls directly into 32 bit time functions in glibc,
|
|
# bypassing all of glibc provisions to choose the right Y2038-safe functions. As
|
|
# rust components statically link with that crate, pretty much everything
|
|
# is affected, and so there's no point trying to have recipe-specific
|
|
# INSANE_SKIP entries.
|
|
#
|
|
# Upstream ticket and PR:
|
|
# https://github.com/rust-lang/libc/issues/3223
|
|
# https://github.com/rust-lang/libc/pull/3175
|
|
INSANE_SKIP:append = " 32bit-time"
|