Skip to content

Conversation

jefferyto
Copy link
Member

Maintainer: @lu-zero, me (for python-setuptools-rust)
Compile tested: armsr-armv7/armsr-armv8/malta-be/x86-generic/x86-64, 2023-10-03 snapshot sdk
Run tested: armsr-armv7/armsr-armv8/malta-be/x86-generic/x86-64 (qemu), 2023-10-03

Description:
The overall goal of these changes is to improve build performance (caching downloads, caching compilation results, not building host Python). This also improves overall build "consistency" (using the make jobserver, using the same options when building Python extensions written in Rust) and better optimizes target binary sizes.

I wasn't able to get rust/cargo to use the make jobserver when building rust itself. I opened rust-lang/rust#116101 but so far I am not optimistic about this being resolved.

These changes have the side effect of fixing a bug I introduced earlier to enable building of Python extensions written in Rust (#22319), so I hope this can be merged soon 😅

Please see the individual commit messages/changes for details.

Copy link
Contributor

@lu-zero lu-zero left a comment

Choose a reason for hiding this comment

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

It looks very nice, I'm still a bit concerned on not having rustc/cargo in CARGO_HOME, but if it is surviving a CI run we should be fine.

@@ -17,7 +25,7 @@ define Host/Compile/Cargo
CC=$(HOSTCC_NOCACHE) \
cargo install -v \
--profile stripped \
$(if $(RUST_PKG_FEATURES),--features "$(RUST_PKG_FEATURES)") \
Copy link
Contributor

Choose a reason for hiding this comment

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

why removing PKG_FEATURES?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was changed to RUST_HOST_FEATURES - in general I think host and target build options should be separate, in this case RUST_HOST_FEATURES can default to RUST_PKG_FEATURES if not set, if that is preferred.

Copy link
Contributor

@lu-zero lu-zero Oct 9, 2023

Choose a reason for hiding this comment

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

Not sure which way is more straightforward, your call :). Overall your set is very cool :) Thank you a lot

@jefferyto jefferyto force-pushed the rust-build-performance branch from 80ba57f to f2c3fae Compare October 8, 2023 23:11
@jefferyto
Copy link
Member Author

Updates:

  • "Fixed" CI build

@jefferyto
Copy link
Member Author

CI failed for riscv64 because ripgrep failed to build - it appears unrelated to this PR (same error causing it to fail to build for buildbots: https://downloads.openwrt.org/snapshots/faillogs/riscv64_riscv64/packages/ripgrep/compile.txt).

@lu-zero
Copy link
Contributor

lu-zero commented Oct 9, 2023

Looks like jemallocator and/or jemalloc have to be updated to work on risc-v. I guess it is fine to drop ripgrep on riscv until upstream fixes it, if somebody have access to a risc-v system would be nice to track down why that constant is missing there...

@Ansuel
Copy link
Member

Ansuel commented Oct 9, 2023

@jefferyto looks ok to me... Also take notice that this (or at least the fix to PATH) should be backported to 23.05 as uwsgi is also broken there.

@oskarirauta
Copy link
Contributor

oskarirauta commented Oct 9, 2023

@lu-zero @Ansuel @jefferyto

A proposal.

Rust 1.73.0 is available, if you add this patch from gentoo, it's also buildable on/for musl 1.2.4 without openwrt/openwrt#12667 - but you need to add --set=target.$(RUSTC_TARGET_ARCH).crt-static=false to TARGET_CONFIGURE_ARGS if you are building on musl 1.2.4. I suggest there could be a Config.in file with option to enable it for build hosts that are musl, such as alpine or openwrt (both need some minor changes but build openwrt very well in the end, changes are needed for example for perl to build).

I have a sample here (without Config file) of rust 1.73.0 that is the first to build on musl 1.2.4 without compatibility patch from openwrt/openwrt#12667. That Makefile has mentioned configuration arg to succeed on musl build host.

@Ansuel
Copy link
Member

Ansuel commented Oct 9, 2023

@oskarirauta mhhh but the problem this pr fix would still be there correct?

@oskarirauta
Copy link
Contributor

@Ansuel Sure - my proposal fixes other things. But I wanted to point out some findings, such as that patch and it finally working on musl 1.2.4 (been waiting since musl 1.2.4 was out) and ofcourse, new version (actually also required for musl 1.2.4).

Just thought, that there is no point for me making a PR, if this is about to succeed soon as this is a bit different. And also, I've pointed out earlier the extra TARGET_CONFIGURE_ARGS necessary on musl build hosts, and it hasn't got any wind under it's wings, so better maybe to propose to people who are actually maintaining project. Proposal to put it as a configurable option - is something that I wanted to avoid, but from Makefile, it is very difficult to detect if host system is using musl. ldd --version prints it out, but it's not capturable, for example..

@Ansuel
Copy link
Member

Ansuel commented Oct 9, 2023

@oskarirauta actually no probably never used but we set config if musl is used instead of glibc. Check your .config file. I don't like using the configuration as we would face situation with glibc selected and rust musl option set. The option should be handled internally.

@oskarirauta
Copy link
Contributor

@Ansuel

I tried that. I just couldn't figure out the way.. Here's few:

dev@media:~# ldd --version
musl libc (x86_64)
Version 1.2.4
Dynamic Program Loader
Usage: ldd [options] [--] pathname

This cannot be parsed even in shell, for e.g. ldd --version | head -n 1 fails.
output is somehow different from normal stdout.

#!/bin/sh
musl_lib=$(ldd $(whereis ls | awk '{print $2}') | grep 'musl' | head -1 | cut -d ' ' -f1)
[ -n "$musl_lib" ] && musl_lib=true || musl_lib=false
echo lib: $musl_lib

Later works in shell... But in Makefile, if I try:
IS_MUSL:=$(ldd $(whereis ls | awk '{print $2}') | grep 'musl' | head -1 | cut -d ' ' -f1)
or ifneq ($(ldd $(whereis ls | awk '{print $2}') | grep 'musl' | head -1 | cut -d ' ' -f1),)
both attempts fail.

I'd be interested to see what you come up, it seems that quite few people have searched for answer to this. I also think it should be handled internally, just couldn't figure out the way. Checking libc link isn't reliable. libc.so isn't always link to ld-musl-x86_64.so or it cannot be counted that it is. For example on openwrt:

dev@media:/usr/src/openwrt# ls -l /lib/libc.so
-rwxr-xr-x 1 root root 3256328 Sep 30 23:06 /lib/libc.so

But I am very pleased that it was taken to consideration, finally I don't need to fork rust part of repo :)

@Ansuel
Copy link
Member

Ansuel commented Oct 9, 2023

#
# C Library
#
# CONFIG_LIBC_USE_GLIBC is not set
CONFIG_LIBC_USE_MUSL=y
# CONFIG_MUSL_DISABLE_CRYPT_SIZE_HACK is not set

not ok to use ldd to check this. you can use config

@oskarirauta
Copy link
Contributor

oskarirauta commented Oct 9, 2023

@Ansuel I think it is about host system.. What you use to build it. config does not know what is building it, it just knows the target.

That though does solve the problem for me, because I build musl, on musl, but it is deceiving.. But I think there is a reason why you haven't set that argument in the first place. And if there is no such reason, it could aswell be enabled for all..

ldd tells details about host system, especially if you really use system ldd, which is just a link to libc.so.

@Ansuel
Copy link
Member

Ansuel commented Oct 9, 2023

oh... so you want to use musl for host? well afaik that is totally not supported... last time i tried an alpine container to build stuff there were lots of problems and never manage to complete it in an usable state so I would first check and make that work.

Did the situation changed? Also instead of ldd can't you just parse the output of opening the libc .so?

@jefferyto
Copy link
Member Author

Rust 1.73.0 is available, if you add this patch from gentoo, it's also buildable on/for musl 1.2.4

I think updating Rust and enabling it to build on musl hosts would be best handled in separate pull requests; this PR is probably a bit too big already.

@trippleflux
Copy link

trippleflux commented Oct 10, 2023

Is there a new way to invoke compilation in subdir of $(PKG_BUILD_DIR) like MAKE_PATH in for normal compilation?.

This is useful for example gping rust package which using gping subdir of its source code : https://github.com/orf/gping/tree/master/gping .

Normally I am doing the following in the previous rust package (before this PR) :

define Build/Compile
	$(call Build/Compile/Cargo,gping)
endef

[EDIT]
Found the way :

define Build/Compile
	$(call Build/Compile/Cargo,$(PKG_BUILD_DIR)/gping)
endef

A bit weird for me to be honest.

@1715173329
Copy link
Member

please rebase to update package procs as well, then let's merge it?

--profile $(CARGO_PKG_PROFILE) \
$(if $(strip $(RUST_PKG_FEATURES)),--features "$(strip $(RUST_PKG_FEATURES))") \
--root $(PKG_INSTALL_DIR) \
--path "$(if $(strip $(1)),$(strip $(1)),$(PKG_BUILD_DIR))" \
Copy link
Contributor

Choose a reason for hiding this comment

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

Keep the cd $(PKG_BUILD_DIR) so you can pass the relative paths to the Build/Compile/Cargo invocation.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is done, no need for cd.

The build system already requires Python to be installed.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
Features to be enabled for host may not be the same as those for target.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
Signed-off-by: Jeffery To <jeffery.to@gmail.com>
* Compress dist archives with gzip instead of xz; gzip is faster to
  compress and decompress

* Use a for loop instead of calling find to extract archives

* Use libdeflate's gzip to decompress instead of gzip

* Limit search for install scripts to top level of extracted archives

This also runs the install scripts with bash instead of sh, in
accordance with the shebang lines inside the scripts.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This allows rustc/cargo/etc to be called without having to set PATH, as
$(STAGING_DIR)/host/bin is already in PATH.

This also fixes CARGO_HOME not being set during Host/Configure and
Host/Compile.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This also:

* Modify the "release" profile in place of adding the "stripped" profile

  Only the profile for target is modified; there are no file size
  constraints for host.

* For host, build with the "release" profile

* For target, build with either the "dev" or "release" profile based on
  CONFIG_DEBUG

There is no environment variable to specify the "strip" option, but
enabling this option is not necessary as the build system will already
strip binaries based on CONFIG_NO_STRIP / CONFIG_USE_STRIP /
CONFIG_USE_SSTRIP.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
As CARGO_HOME mainly functions as a download and source cache[1], moving
it into $(DL_DIR) allows it to persist and be reused between different
buildroots/sdks (when DL_DIR is set to a custom/external location).

[1]: https://doc.rust-lang.org/cargo/guide/cargo-home.html

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This consolidates all environment variables for cargo into:

* CARGO_HOST_CONFIG_VARS / CARGO_PKG_CONFIG_VARS

  These contain all cargo-specific environment variables, i.e. without
  "common" variables like CC.

* CARGO_HOST_VARS / CARGO_PKG_VARS (renamed from CARGO_VARS)

  These contain all environment variables to be passed to cargo.

This also:

* Set the CARGO_BUILD_TARGET environment variable instead of using the
  --target command-line option

* Update Python include files to use CARGO_HOST_CONFIG_VARS /
  CARGO_PKG_CONFIG_VARS

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This allows cargo to use make's jobserver when building packages, by
marking the cargo command as recursive (with the + prefix[1]) and
setting MAKEFLAGS.

This also:

* Give cargo/x.py the build directory instead of having to change the
  current directory (and opening subshells)

* Set PKG_BUILD_PARALLEL/HOST_BUILD_PARALLEL for Rust packages to enable
  the use of make's jobserver

[1]: https://www.gnu.org/software/make/manual/html_node/POSIX-Jobserver.html

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
Using sccache makes recompilation of rustc and Rust packages faster.

This also makes the rust package visible in menuconfig, in order for the
sccache options to be accessible.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
* codegen-units, lto, opt-level - Set to values to optimize binary
  size[1].

* overflow-checks - Enabled because in release mode, integer overflows
  are defined as two's complement wrap[2]. It is highly unlikely that
  any program is intentionally relying on this behaviour; it would be
  better to panic instead of continue execution in this case.

* debug, debug-assertions, panic, rpath - Set to their default (release)
  values, to override any settings made by packages, e.g. ripgrep sets
  debug = 1[3].

[1]: https://github.com/johnthagen/min-sized-rust
[2]: https://huonw.github.io/blog/2016/04/myths-and-legends-about-integer-overflow-in-rust/
[3]: https://github.com/BurntSushi/ripgrep/blob/13.0.0/Cargo.toml#L79-L80

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
This adds a patch (submitted upstream in
PyO3/setuptools-rust#364), to read the profile
to pass to cargo from an environment variable.

This also updates the Python include files to set the environment
variable based on values from rust-values.mk.

Signed-off-by: Jeffery To <jeffery.to@gmail.com>
@jefferyto jefferyto force-pushed the rust-build-performance branch from f2c3fae to 29ca979 Compare October 11, 2023 07:50
@jefferyto
Copy link
Member Author

jefferyto commented Oct 11, 2023

Changes:

  • Rebase on master
  • Add PKG_BUILD_PARALLEL:=1 to procs
  • Restore relative path argument to $(call Build/Compile/Cargo)
  • Expand rustc bootstrap patch to cache downloads made by download.rs, e.g. for llvm
  • Add commit to speed up Host/Install (gzip instead of xz, libdeflate-gzip instead of gzip)

Is there a new way to invoke compilation in subdir of $(PKG_BUILD_DIR) like MAKE_PATH in for normal compilation?.

Fixed 🙏

please rebase to update package procs as well, then let's merge it?

Done!

@lu-zero
Copy link
Contributor

lu-zero commented Oct 11, 2023

Hopefully ripgrep will have a new release soon, in the mean time either we distribute a snapshot or omit it from riscv

@1715173329 1715173329 merged commit 1752719 into openwrt:master Oct 11, 2023
@BKPepe
Copy link
Member

BKPepe commented Oct 11, 2023

We will wait a few days until we will backport it to OpenWrt 23.05 branch, right? :)

@Ansuel
Copy link
Member

Ansuel commented Oct 11, 2023

@BKPepe I would create a pr just to check if the thing can be backported with no changes

@jefferyto jefferyto deleted the rust-build-performance branch October 12, 2023 05:57
@jefferyto
Copy link
Member Author

Hopefully ripgrep will have a new release soon, in the mean time either we distribute a snapshot or omit it from riscv

Perhaps you can file an issue with ripgrep and/or jemallocator about riscv support?

We will wait a few days until we will backport it to OpenWrt 23.05 branch, right? :)

I have opened a PR (#22376), of course can wait a few days before merging.

@lu-zero
Copy link
Contributor

lu-zero commented Oct 12, 2023

Hopefully ripgrep will have a new release soon, in the mean time either we distribute a snapshot or omit it from riscv

Perhaps you can file an issue with ripgrep and/or jemallocator about riscv support?

it should work fine already, it is just the current ripgrep release is very old. Switching to the current master would make it work.

We will wait a few days until we will backport it to OpenWrt 23.05 branch, right? :)

I have opened a PR (#22376), of course can wait a few days before merging.

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.

7 participants