diff --git a/sdk_container/src/third_party/portage-stable/eclass/cargo.eclass b/sdk_container/src/third_party/portage-stable/eclass/cargo.eclass index 7db34efb4e..3a63e50272 100644 --- a/sdk_container/src/third_party/portage-stable/eclass/cargo.eclass +++ b/sdk_container/src/third_party/portage-stable/eclass/cargo.eclass @@ -109,7 +109,7 @@ ECARGO_VENDOR="${ECARGO_HOME}/gentoo" # # If you enable CARGO_OPTIONAL, you have to set BDEPEND on virtual/rust # for your package and call at least cargo_gen_config manually before using -# other src_functions of this eclass. +# other src_functions or cargo_env of this eclass. # Note that cargo_gen_config is automatically called by cargo_src_unpack. # @ECLASS_VARIABLE: myfeatures @@ -248,7 +248,7 @@ cargo_crate_uris() { # @FUNCTION: cargo_gen_config # @DESCRIPTION: -# Generate the $CARGO_HOME/config necessary to use our local registry and settings. +# Generate the $CARGO_HOME/config.toml necessary to use our local registry and settings. # Cargo can also be configured through environment variables in addition to the TOML syntax below. # For each configuration key below of the form foo.bar the environment variable CARGO_FOO_BAR # can also be used to define the value. @@ -261,7 +261,7 @@ cargo_gen_config() { mkdir -p "${ECARGO_HOME}" || die - cat > "${ECARGO_HOME}/config" <<- _EOF_ || die "Failed to create cargo config" + cat > "${ECARGO_HOME}/config.toml" <<- _EOF_ || die "Failed to create cargo config" [source.gentoo] directory = "${ECARGO_VENDOR}" @@ -324,9 +324,7 @@ _cargo_gen_git_config() { # Return the directory within target that contains the build, e.g. # target/aarch64-unknown-linux-gnu/release. cargo_target_dir() { - local abi - tc-is-cross-compiler && abi=/$(rust_abi) - echo "${CARGO_TARGET_DIR:-target}${abi}/$(usex debug debug release)" + echo "${CARGO_TARGET_DIR:-target}/$(rust_abi)/$(usex debug debug release)" } # @FUNCTION: cargo_src_unpack @@ -523,36 +521,92 @@ cargo_src_configure() { [[ ${ECARGO_ARGS[@]} ]] && einfo "Configured with: ${ECARGO_ARGS[@]}" } +# @FUNCTION: cargo_env +# @USAGE: Command with its arguments +# @DESCRIPTION: +# Run the given command under an environment needed for performing tasks with +# Cargo such as building. RUSTFLAGS are appended to additional flags set here. +# Ensure these are set consistently between Cargo invocations, otherwise +# rebuilds will occur. Project-specific rustflags set against [build] will not +# take affect due to Cargo limitations, so add these to your ebuild's RUSTFLAGS +# if they seem important. +cargo_env() { + [[ ${_CARGO_GEN_CONFIG_HAS_RUN} ]] || \ + die "FATAL: please call cargo_gen_config before using ${FUNCNAME}" + + # Shadow flag variables so that filtering below remains local. + local flag + for flag in $(all-flag-vars); do + local -x "${flag}=${!flag}" + done + + # Rust extensions are incompatible with C/C++ LTO compiler see e.g. + # https://bugs.gentoo.org/910220 + filter-lto + + tc-export AR CC CXX PKG_CONFIG + + # Set vars for cc-rs crate. + local -x \ + HOST_AR=$(tc-getBUILD_AR) + HOST_CC=$(tc-getBUILD_CC) + HOST_CXX=$(tc-getBUILD_CXX) + HOST_CFLAGS=${BUILD_CFLAGS} + HOST_CXXFLAGS=${BUILD_CXXFLAGS} + + # Unfortunately, Cargo is *really* bad at handling flags. In short, it uses + # the first of the RUSTFLAGS env var, any target-specific config, and then + # any generic [build] config. It can merge within the latter two types from + # different sources, but it will not merge across these different types, so + # if a project sets flags under [target.'cfg(all())'], it will override any + # flags we set under [build] and vice-versa. + # + # It has been common for users and ebuilds to set RUSTFLAGS, which would + # have overridden whatever a project sets anyway, so the least-worst option + # is to include those RUSTFLAGS in target-specific config here, which will + # merge with any the project sets. Only flags in generic [build] config set + # by the project will be lost, and ebuilds will need to add those to + # RUSTFLAGS themselves if they are important. + # + # We could potentially inspect a project's generic [build] config and + # reapply those flags ourselves, but that would require a proper toml parser + # like tomlq, it might lead to confusion where projects also have + # target-specific config, and converting arrays to strings may not work + # well. Nightly features to inspect the config might help here in future. + # + # As of Rust 1.80, it is not possible to set separate flags for the build + # host and the target host when cross-compiling. The flags given are applied + # to the target host only with no flags being applied to the build host. The + # nightly host-config feature will improve this situation later. + # + # The default linker is "cc" so override by setting linker to CC in the + # RUSTFLAGS. The given linker cannot include any arguments, so split these + # into link-args along with LDFLAGS. + local -x CARGO_BUILD_TARGET=$(rust_abi) + local TRIPLE=${CARGO_BUILD_TARGET//-/_} + local TRIPLE=${TRIPLE^^} LD_A=( $(tc-getCC) ${LDFLAGS} ) + local -x CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS="-C strip=none -C linker=${LD_A[0]}" + [[ ${#LD_A[@]} -gt 1 ]] && local CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS+="$(printf -- ' -C link-arg=%s' "${LD_A[@]:1}")" + local CARGO_TARGET_"${TRIPLE}"_RUSTFLAGS+=" ${RUSTFLAGS}" + + ( + # These variables will override the above, even if empty, so unset them + # locally. Do this in a subshell so that they remain set afterwards. + unset CARGO_BUILD_RUSTFLAGS CARGO_ENCODED_RUSTFLAGS RUSTFLAGS + + "${@}" + ) +} + # @FUNCTION: cargo_src_compile # @DESCRIPTION: # Build the package using cargo build. cargo_src_compile() { debug-print-function ${FUNCNAME} "$@" - [[ ${_CARGO_GEN_CONFIG_HAS_RUN} ]] || \ - die "FATAL: please call cargo_gen_config before using ${FUNCNAME}" - - filter-lto - tc-export AR CC CXX PKG_CONFIG - - if tc-is-cross-compiler; then - export CARGO_BUILD_TARGET=$(rust_abi) - local TRIPLE=${CARGO_BUILD_TARGET//-/_} - export CARGO_TARGET_"${TRIPLE^^}"_LINKER=$(tc-getCC) - - # Set vars for cc-rs crate. - tc-export_build_env - export \ - HOST_AR=$(tc-getBUILD_AR) - HOST_CC=$(tc-getBUILD_CC) - HOST_CXX=$(tc-getBUILD_CXX) - HOST_CFLAGS=${BUILD_CFLAGS} - HOST_CXXFLAGS=${BUILD_CXXFLAGS} - fi - set -- cargo build $(usex debug "" --release) ${ECARGO_ARGS[@]} "$@" einfo "${@}" - "${@}" || die "cargo build failed" + cargo_env "${@}" || die "cargo build failed" } # @FUNCTION: cargo_src_install @@ -564,16 +618,13 @@ cargo_src_compile() { cargo_src_install() { debug-print-function ${FUNCNAME} "$@" - [[ ${_CARGO_GEN_CONFIG_HAS_RUN} ]] || \ - die "FATAL: please call cargo_gen_config before using ${FUNCNAME}" - set -- cargo install $(has --path ${@} || echo --path ./) \ --root "${ED}/usr" \ ${GIT_CRATES[@]:+--frozen} \ $(usex debug --debug "") \ ${ECARGO_ARGS[@]} "$@" einfo "${@}" - "${@}" || die "cargo install failed" + cargo_env "${@}" || die "cargo install failed" rm -f "${ED}/usr/.crates.toml" || die rm -f "${ED}/usr/.crates2.json" || die @@ -585,12 +636,9 @@ cargo_src_install() { cargo_src_test() { debug-print-function ${FUNCNAME} "$@" - [[ ${_CARGO_GEN_CONFIG_HAS_RUN} ]] || \ - die "FATAL: please call cargo_gen_config before using ${FUNCNAME}" - set -- cargo test $(usex debug "" --release) ${ECARGO_ARGS[@]} "$@" einfo "${@}" - "${@}" || die "cargo test failed" + cargo_env "${@}" || die "cargo test failed" } fi