Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: build when target_arch==build_arch #146

Conversation

sarfata
Copy link
Contributor

@sarfata sarfata commented Oct 3, 2023

In #82 we fixed the build when the target arch is the same as the build arch. A side effect of the fix is that the rust build-scripts (which are intended to run on the build host) are now built with the target compiler and cflags.

This is fine in most cases but it breaks when the host system is older than the system we are building. For example, we might build for a newer glibc that will be available on the target but when we run the build script on the host, this version does not exist which leads to the error described in #83.

Another version of the same problem is that we may try to use some build flags that are available on the compiler for the target (aarch64-poky-linux-gcc) but not on the host compiler (gcc) because the host compiler is an older version of gcc than the one we are using for the target.

This patch fixes the problem by using two unstable features of cargo:

  • UNSTABLE_TARGET_APPLIES_TO_HOST allows us to pass the CARGO_TARGET_APPLIES_TO_HOST=false setting so that the target build settings are not used when building for the host.
  • UNSTABLE_HOST_CONFIG allows us to set build flags for the host in a [host] section of the Cargo.toml file.

The __CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS environment variable is required to use these unstable features on a stable rust. This patch works with stable rust and does not require unstable.

The inspiration for this solution comes from buildroot.

fixes #83

@martijnthe
Copy link

martijnthe commented Oct 4, 2023

@nastevens FYI, this fixes the same problem that #133 and #137 are also trying to fix.

Thank you in advance for taking a look.

@posborne
Copy link
Member

posborne commented Oct 6, 2023

Thank you @sarfata for the patch and @martijnthe for the reference to the other tickets. I believe this is sound but would love @nastevens to take a look as well but will probably move forward with it.

@banditopazzo @samliddicott @jameshilliard if you have other thoughts or are on board with this form of the patch. Seems clear we need to land one of these changesets in tree for the case described.

if [ "${RUST_BUILD}" = "${RUST_TARGET}" ]; then
export __CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS="nightly"
export CARGO_UNSTABLE_TARGET_APPLIES_TO_HOST="true"
export CARGO_UNSTABLE_HOST_CONFIG="true"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being set? I don't see any CARGO_HOST_ variables being set here. In buildroot we enable this so we can set the host config option CARGO_HOST_RUSTFLAGS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understood correctly, it's because of the setting is in ${CARGO_HOME}/config

# (Rust unstable) - See do_compile below.
echo "[host]" >> ${CARGO_HOME}/config
echo "linker = '${WRAPPER_DIR}/linker-native-wrapper.sh'" >> ${CARGO_HOME}/config

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just set CARGO_HOST_LINKER="${WRAPPER_DIR}/linker-native-wrapper.sh" instead of using the cargo config file?

You should also be able to get rid of the cargo config entirely by configuring the target linker and any other config file variables something like this as well:

CARGO_TARGET_${RUST_TARGET}_LINKER="${WRAPPER_DIR}/linker-wrapper.sh"

In general I think sticking to configuring cargo using env variables only seems to be less likely to break than mixing env based configs with config file based configs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being set?
As pointed out by @banditopazzo it's for the host configuration.

Why not just set CARGO_HOST_LINKER="${WRAPPER_DIR}/linker-native-wrapper.sh" instead of using the cargo config file?

When HOST != TARGET we configure both compilers via the .cargo/config file. I chose to keep doing this this way to stay as close as possible to what we have today.

I understand you would prefer to completely get rid of .cargo/config and move everything to env vars. Sounds good to me too.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When HOST != TARGET we configure both compilers via the .cargo/config file. I chose to keep doing this this way to stay as close as possible to what we have today.

In general there should be no need to configure cargo differently for HOST != TARGET vs HOST == TARGET builds if the host/target config splitting env variables are set up correctly AFAIU.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general there should be no need to configure cargo differently for HOST != TARGET vs HOST == TARGET builds if the host/target config splitting env variables are set up correctly AFAIU.

We still need a way to pass the HOST linker (linker-native-wrapper.sh). If we just set the host/target config splitting env variables, then cargo reverts to gcc/ld with no options when compiling for the host. That might work sometimes but I don't think it's correct because I believe we want to use the sysroot-native libraries when building anything for the host.

On my system, linker-native-wrapper.sh contains:

#!/bin/sh
gcc  -L/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/usr/lib                         -L/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/lib                         -Wl,--enable-new-dtags                         -Wl,-rpath-link,/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/usr/lib                         -Wl,-rpath-link,/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/lib                         -Wl,-rpath,/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/usr/lib                         -Wl,-rpath,/home/thomas/yocto/build/tmp/work/cortexa57-poky-linux/xxx/1.0-r0/recipe-sysroot-native/lib                         -Wl,-O1 -Wl,--allow-shlib-undefined -Wl,--dynamic-linker=/home/thomas/yocto/build/tmp/sysroots-uninative/x86_64-linux/lib/ld-linux-x86-64.so.2 "$@"

If we do not set any host option, we will revert to just calling gcc and we do not get the -Wl,-rpath-link,... setting when building the build-script. Without this setting, when we run the build-script later, it cannot find the right version of glibc. This was causing #83.

There are two ways to set the Host Linker (via cargo_home/config like I have done here) or via CARGO_HOST_LINKER (like in the other PR). I chose the former because this way, the config file looks the same whether TARGET==HOST or not.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this setting, when we run the build-script later, it cannot find the right version of glibc. This was causing #83.

I think that was a different issue where cargo is picking up target linker flags for host builds rather than not picking up additional native flags for the host build, although I'm more familiar with buildroot which does things somewhat differently.

I chose the former because this way, the config file looks the same whether TARGET==HOST or not.

I mean, why not just get rid of the cargo config file entirely and pass all config options as env variables? In both cases they should look the same for TARGET==HOST or not AFAIU.

In buildroot we use only the env varibles since we'd otherwise have to regenerate the config file for each package build due to our per-package build isolation changing things like linker paths for each package build, by using env variables we don't have to worry about that as the env is updated automatically with the correct paths for each package.

Additionally this makes it easier for us to handle say python package builds with cargo modules(ie python-cryptography) as we can simply append the cargo environment to our python environment without having to also trigger a config regeneration operation.

# When RUST_BUILD == RUST_TARGET, we need to use an unstable Rust feature
# to specify different build options for the target and the Host.
# The Host configuration is set in do_configure() above.
if [ "${RUST_BUILD}" = "${RUST_TARGET}" ]; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably best to remove this check and just unconditionally apply these env variables like we do in buildroot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do.

@banditopazzo
Copy link
Contributor

I'm not a big fan of using ${CARGO_HOME}/config to pass settings.

What's the reason behind this instead of using only env variables?

@sarfata
Copy link
Contributor Author

sarfata commented Oct 6, 2023

I'm not a big fan of using ${CARGO_HOME}/config to pass settings.

What's the reason behind this instead of using only env variables?

I was just following what existed before the PR. I can change to env vars everywhere.

@banditopazzo
Copy link
Contributor

I'm not a big fan of using ${CARGO_HOME}/config to pass settings.
What's the reason behind this instead of using only env variables?

I was just following what existed before the PR. I can change to env vars everywhere.

ok, @posborne what do you think?

@posborne
Copy link
Member

posborne commented Oct 6, 2023

@sarfata I'm good with using env vars over the config file and agree that when possible (which I think is most or all cases now) that is preferred. I believe when we were first developing this layer, that mechanism was either unavailable or not widely publicized which I suspect is that reason we used the config file approach but I don't believe there is any reason to continue with that approach now.

@posborne posborne self-requested a review October 6, 2023 20:14
@jameshilliard
Copy link

when possible (which I think is most or all cases now) that is preferred

AFAIU all cargo config file options can be set via the env variables. Are there any that aren't working via the env?

@posborne
Copy link
Member

posborne commented Oct 7, 2023

AFAIU all cargo config file options can be set via the env variables. Are there any that aren't working via the env?

I believe this is the case now. @nastevens wrote the earliest versions of this layer back in 2016 originally, so I think the support may not have been there in cargo back then. Doesn't matter these days.

@sarfata
Copy link
Contributor Author

sarfata commented Oct 9, 2023

Thanks everyone for opinions on this PR. Sorry for the delay getting the changes up. I am testing on a few different configuration and hoping to have this ready tomorrow.

@sarfata sarfata force-pushed the sarfata/fix-build-when-target_arch==build_arch branch 2 times, most recently from 223fb15 to b917586 Compare October 9, 2023 16:57
@sarfata
Copy link
Contributor Author

sarfata commented Oct 9, 2023

I have removed the cargo_home/config file to only use environment variables.
And instead of distinguishing "TARGET==HOST vs TARGET!=HOST", I now always use the CARGO_HOST_LINKER variable.

I think this addresses all the comments. I have tested this when TARGET==HOST and when not.

I had to use a little bit of inline python to rewrite the dashes into underscores for the environment variable name. I am not sure if there is a more Yocto-typical way to do this.

export CARGO_TARGET_${@rust_target(d, 'BUILD').replace('-','_')}_LINKER="${WRAPPER_DIR}/linker-wrapper.sh"

@posborne @jameshilliard @banditopazzo please let me know if you would like me to include anything else here.

export PKG_CONFIG_ALLOW_CROSS="1"
export LDFLAGS=""
export RUSTFLAGS="${RUSTFLAGS}"
export SSH_AUTH_SOCK="${SSH_AUTH_SOCK}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sarfata Is the drop of this intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope - Good catch thanks. Just fixed.

Copy link
Member

@posborne posborne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM and will approve and merge with SSH_AUTH_SOCK added back (open to more discussion). That flag was added in #143

In rust-embedded#82 we fixed the build when the target arch is the same as the build arch. A
side effect of the fix is that the rust build-scripts (which are intended to run
on the build host) are now built with the target compiler and cflags.

This is fine in most cases but it breaks when the host system is older than the
system we are building. For example, we might build for a newer glibc that will
be available on the target but when we run the build script on the host, this
version does not exist which leads to the error described in rust-embedded#83.

Another version of the same problem is that we may try to use some build flags
that are available on the compiler for the target (`aarch64-poky-linux-gcc`) but
not on the host compiler (`gcc`) because the host compiler is older than the one
we are using for the target.

This patch fixes the problem by using two unstable features of cargo:

 - [`UNSTABLE_TARGET_APPLIES_TO_HOST`](https://doc.rust-lang.org/cargo/reference/unstable.html#target-applies-to-host)
 allows us to pass the `CARGO_TARGET_APPLIES_TO_HOST=false` setting so that the
 target build settings are not used when building for the host.
 - [`UNSTABLE_HOST_CONFIG`](https://doc.rust-lang.org/cargo/reference/unstable.html#host-config)
 allows us to set build flags for the host.

The `__CARGO_TEST_CHANNEL_OVERRIDE_DO_NOT_USE_THIS` environment variable is
required to use these unstable features on a stable rust. This patch works with
stable rust and does not require unstable.

During review of this PR, it was decided to drop the `cargo_home/config` file
completely and use only environment variables.

The inspiration for this solution [comes from buildroot](https:/buildroot/buildroot/blob/25d865996d1d9753fe7d4dfe39cf18c7e9f91224/package/pkg-cargo.mk#L26-L47).

fixes rust-embedded#83
@sarfata sarfata force-pushed the sarfata/fix-build-when-target_arch==build_arch branch from b917586 to 8fb174f Compare October 9, 2023 21:23
@sarfata
Copy link
Contributor Author

sarfata commented Oct 9, 2023

@posborne SSH_AUTH_SOCK is back, I have squashed the commits and slightly updated the PR description. Ready to go I think.

@posborne
Copy link
Member

Thanks @sarfata and everyone else that participated in the review and other iterations of the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build error when linking against an older glibc
5 participants