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

gcc: do not allow version skew when cross-building gcc #352821

Merged
merged 1 commit into from
Nov 25, 2024

Conversation

trofi
Copy link
Contributor

@trofi trofi commented Nov 1, 2024

When gcc is cross-built (build != target && host == target) gcc assumes that it has a compatible cross-compiler in the environment that can build target libraries. Version of a cross-compiler has to match the compiler being cross-built as libraries frequently use fresh compiler features, like -std=c++26 or target-specific types like _Bfloat16.

Version mismatch causes build failures like:

https://github.com/NixOS/nixpkgs/issues/351905

Similar problems (but on a smaller scale) happen when a gcc cross-compiler is built (build == host && host != target) built by a mismatching version of a native compiler (build == host && host == target). That was worked around by forcing gcc9Stdenv for older compiler versions.

Let's fix both problems by requiring the same compiler version for cross-case.

Closes: #351905

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@trofi
Copy link
Contributor Author

trofi commented Nov 1, 2024

Tested builds successfully on:

  • pkgsCross.riscv64.gcc
  • pkgsCross.riscv64.gcc14
  • pkgs.pkgsCross.aarch64-multiplatform.gcc9

@trofi
Copy link
Contributor Author

trofi commented Nov 1, 2024

Rebuild counts are low:

$ ./maintainers/scripts/rebuild-amount.sh HEAD^

      1 release-checks
      7 x86_64-darwin
    229 x86_64-linux

@ofborg ofborg bot added 6.topic: cross-compilation Building packages on a different platform than they will be used on 10.rebuild-darwin: 1-10 10.rebuild-linux: 101-500 labels Nov 1, 2024
@trofi
Copy link
Contributor Author

trofi commented Nov 2, 2024

nixpkgs-review result

Generated using nixpkgs-review.

Command: nixpkgs-review pr 352821


x86_64-linux

⏩ 1 package marked as broken and skipped:
  • himitsu-firefox
⏩ 2 packages blacklisted:
  • nixos-install-tools
  • tests.nixos-functions.nixos-test
❌ 1 package failed to build:
  • gnuk
✅ 301 packages built:
  • appvm
  • armTrustedFirmwareTools
  • attic-client
  • attic-server
  • bonsai
  • bower2nix
  • bundix
  • busybox-sandbox-shell
  • busybox-sandbox-shell.debug
  • cabal2nix
  • cached-nix-shell
  • cachix (cachix.bin ,cachix.doc ,haskellPackages.cachix.bin)
  • colmena
  • common-updater-scripts
  • crate2nix
  • crystal2nix
  • devenv
  • disko
  • dub-to-nix
  • dxvk
  • dxvk.bin
  • dxvk.lib
  • dydisnix
  • exactaudiocopy
  • fusee-launcher
  • fusionInventory
  • getoptions
  • gns3-server
  • gns3-server.dist
  • hare
  • hare.man
  • hareHook
  • hareThirdParty.hare-compress
  • hareThirdParty.hare-ev
  • hareThirdParty.hare-json
  • hareThirdParty.hare-png
  • hareThirdParty.hare-ssh
  • hareThirdParty.hare-toml
  • haredo
  • haredo.man
  • haredoc
  • haredoc.man
  • harmonia
  • haskellPackages.cabal2nix-unstable
  • haskellPackages.cachix
  • haskellPackages.cachix.doc
  • haskellPackages.cli-nix
  • haskellPackages.cli-nix.doc
  • haskellPackages.hercules-ci-agent
  • haskellPackages.hercules-ci-agent.doc
  • haskellPackages.hercules-ci-cli
  • haskellPackages.hercules-ci-cli.doc
  • haskellPackages.hercules-ci-cnix-expr
  • haskellPackages.hercules-ci-cnix-expr.doc
  • haskellPackages.hercules-ci-cnix-store
  • haskellPackages.hercules-ci-cnix-store.doc
  • haskellPackages.niv
  • haskellPackages.niv.bin
  • haskellPackages.niv.data
  • haskellPackages.niv.doc
  • haskellPackages.nix-paths
  • haskellPackages.nix-paths.doc
  • haskellPackages.nix-serve-ng
  • haskellPackages.nix-serve-ng.doc
  • haskellPackages.nix-thunk
  • haskellPackages.nix-thunk.doc
  • haskellPackages.nvfetcher
  • haskellPackages.nvfetcher.doc
  • haskellPackages.update-nix-fetchgit
  • haskellPackages.update-nix-fetchgit.doc
  • hci
  • hercules-ci-agent
  • himitsu
  • home-manager
  • hydra
  • iscc
  • klipper-firmware
  • klipper-flash
  • libnixxml
  • lix (lixVersions.latest ,lixVersions.lix_2_91 ,lixVersions.stable)
  • lix.debug (lixVersions.latest.debug ,lixVersions.lix_2_91.debug ,lixVersions.stable.debug)
  • lix.dev (lixVersions.latest.dev ,lixVersions.lix_2_91.dev ,lixVersions.stable.dev)
  • lix.devdoc (lixVersions.latest.devdoc ,lixVersions.lix_2_91.devdoc ,lixVersions.stable.devdoc)
  • lix.doc (lixVersions.latest.doc ,lixVersions.lix_2_91.doc ,lixVersions.stable.doc)
  • lix.man (lixVersions.latest.man ,lixVersions.lix_2_91.man ,lixVersions.stable.man)
  • lixStatic
  • lixStatic.dev
  • lixVersions.lix_2_90
  • lixVersions.lix_2_90.debug
  • lixVersions.lix_2_90.dev
  • lixVersions.lix_2_90.devdoc
  • lixVersions.lix_2_90.doc
  • lixVersions.lix_2_90.man
  • lua51Packages.luarocks-nix
  • luarocks-nix (luaPackages.luarocks-nix)
  • lua53Packages.luarocks-nix
  • lua54Packages.luarocks-nix
  • luajitPackages.luarocks-nix
  • luarocks-packages-updater
  • luarocks-packages-updater.dist
  • nil
  • nim_lk
  • nitrokey-trng-rs232-firmware
  • niv (niv.bin ,niv.data)
  • nix (nixVersions.latest ,nixVersions.nix_2_24 ,nixVersions.stable)
  • nix-bundle
  • nix-direnv
  • nix-du
  • nix-eval-jobs
  • nix-fast-build
  • nix-fast-build.dist
  • nix-index
  • nix-init
  • nix-inspect
  • nix-pin
  • nix-plugin-pijul
  • nix-plugins
  • nix-prefetch
  • nix-prefetch-bzr
  • nix-prefetch-cvs
  • nix-prefetch-docker
  • nix-prefetch-git
  • nix-prefetch-hg
  • nix-prefetch-scripts
  • nix-prefetch-svn
  • nix-required-mounts
  • nix-required-mounts.dist
  • nix-serve
  • nix-serve-ng
  • nix-template
  • nix-unit
  • nix-update
  • nix-update-source
  • nix-update-source.dist
  • nix-update.dist
  • nix-visualize
  • nix-visualize.dist
  • nix-web
  • nix.debug (nixVersions.latest.debug ,nixVersions.nix_2_24.debug ,nixVersions.stable.debug)
  • nix.dev (nixVersions.latest.dev ,nixVersions.nix_2_24.dev ,nixVersions.stable.dev)
  • nix.doc (nixVersions.latest.doc ,nixVersions.nix_2_24.doc ,nixVersions.stable.doc)
  • nix.man (nixVersions.latest.man ,nixVersions.nix_2_24.man ,nixVersions.stable.man)
  • nixStatic
  • nixStatic.dev
  • nixStatic.doc
  • nixStatic.man
  • nixVersions.git
  • nixVersions.git.debug
  • nixVersions.git.dev
  • nixVersions.git.doc
  • nixVersions.git.man
  • nixVersions.minimum (nixVersions.nix_2_3)
  • nixVersions.minimum.debug (nixVersions.nix_2_3.debug)
  • nixVersions.minimum.dev (nixVersions.nix_2_3.dev)
  • nixVersions.minimum.doc (nixVersions.nix_2_3.doc)
  • nixVersions.minimum.man (nixVersions.nix_2_3.man)
  • nixVersions.nix_2_18
  • nixVersions.nix_2_18.debug
  • nixVersions.nix_2_18.dev
  • nixVersions.nix_2_18.doc
  • nixVersions.nix_2_18.man
  • nixVersions.nix_2_19
  • nixVersions.nix_2_19.debug
  • nixVersions.nix_2_19.dev
  • nixVersions.nix_2_19.doc
  • nixVersions.nix_2_19.man
  • nixVersions.nix_2_20
  • nixVersions.nix_2_20.debug
  • nixVersions.nix_2_20.dev
  • nixVersions.nix_2_20.doc
  • nixVersions.nix_2_20.man
  • nixVersions.nix_2_21
  • nixVersions.nix_2_21.debug
  • nixVersions.nix_2_21.dev
  • nixVersions.nix_2_21.doc
  • nixVersions.nix_2_21.man
  • nixVersions.nix_2_22
  • nixVersions.nix_2_22.debug
  • nixVersions.nix_2_22.dev
  • nixVersions.nix_2_22.doc
  • nixVersions.nix_2_22.man
  • nixVersions.nix_2_23
  • nixVersions.nix_2_23.debug
  • nixVersions.nix_2_23.dev
  • nixVersions.nix_2_23.doc
  • nixVersions.nix_2_23.man
  • nixci
  • nixd
  • nixos-anywhere
  • nixos-generators
  • nixos-install
  • nixos-option
  • nixos-rebuild
  • nixos-shell
  • nixpkgs-hammering
  • nixpkgs-manual
  • nixpkgs-review
  • nixpkgs-review.dist
  • nixt
  • nixt.dev
  • nixtract
  • node2nix
  • npins
  • nuget-to-nix
  • nurl
  • nvfetcher
  • opentrack
  • outline
  • pipelight
  • pkgsStatic.stdenv
  • playonlinux
  • prefetch-yarn-deps
  • python311Packages.nix-kernel
  • python311Packages.nix-kernel.dist
  • python311Packages.nixpkgs
  • python311Packages.nixpkgs.dist
  • python311Packages.pythonix
  • python312Packages.nix-kernel
  • python312Packages.nix-kernel.dist
  • python312Packages.nixpkgs
  • python312Packages.nixpkgs.dist
  • python312Packages.pythonix
  • q4wine
  • qmk
  • qmk.dist
  • sbomnix
  • sbomnix.dist
  • simavr
  • sonarr
  • spike
  • swiftpm2nix (swiftPackages.swiftpm2nix)
  • synthesia
  • terranix
  • tests.devShellTools.nixos
  • tests.haskell.cabalSdist.hercules-ci-cnix-store
  • tests.haskell.cabalSdist.hercules-ci-cnix-store.doc
  • tests.makeBinaryWrapper
  • tests.pkg-config.defaultPkgConfigPackages.nix-cmd
  • tests.pkg-config.defaultPkgConfigPackages.nix-expr
  • tests.pkg-config.defaultPkgConfigPackages.nix-main
  • tests.pkg-config.defaultPkgConfigPackages.nix-store
  • tests.testers.lycheeLinkCheck.network
  • tests.testers.nixosTest-example
  • tests.testers.runNixOSTest-example
  • tests.trivial-builders.references
  • treecat
  • treecat.man
  • typescript-language-server
  • update-nix-fetchgit
  • update-python-libraries
  • vimPluginsUpdater
  • virt-v2v
  • vkd3d
  • vkd3d-proton
  • vkd3d-proton.dev
  • vkd3d.dev
  • vkd3d.lib
  • vulnix
  • vulnix.dist
  • vulnix.doc
  • vulnix.man
  • winbox (winbox3)
  • wine (winePackages.full ,winePackages.stableFull)
  • wine-staging (winePackages.stagingFull)
  • wine-wayland (winePackages.waylandFull)
  • wine64 (wine64Packages.full ,wine64Packages.stableFull)
  • wine64Packages.base (wine64Packages.stable)
  • wine64Packages.staging
  • wine64Packages.stagingFull
  • wine64Packages.unstable
  • wine64Packages.unstableFull
  • wine64Packages.wayland
  • wine64Packages.waylandFull
  • winePackages.base (winePackages.stable)
  • winePackages.staging
  • winePackages.unstable
  • winePackages.unstableFull
  • winePackages.wayland
  • wineWow64Packages.base (wineWow64Packages.stable)
  • wineWow64Packages.full (wineWow64Packages.stableFull)
  • wineWow64Packages.minimal
  • wineWow64Packages.staging
  • wineWow64Packages.stagingFull
  • wineWow64Packages.unstable
  • wineWow64Packages.unstableFull
  • wineWow64Packages.wayland
  • wineWow64Packages.waylandFull
  • wineWowPackages.base (wineWowPackages.stable)
  • wineWowPackages.full (wineWowPackages.stableFull)
  • wineWowPackages.staging
  • wineWowPackages.stagingFull
  • wineWowPackages.unstable
  • wineWowPackages.unstableFull
  • wineWowPackages.wayland
  • wineWowPackages.waylandFull
  • wineasio
  • wp4nix
  • yabridge
  • yabridgectl
  • yarn2nix
  • zon2nix

#
# Let's fix both problems by requiring the same compiler version for
# cross-case.
stdenv = if (stdenv.targetPlatform != stdenv.buildPlatform) && stdenv.cc.isGNU then pkgs."gcc${majorVersion}Stdenv" else stdenv;
Copy link
Member

Choose a reason for hiding this comment

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

Do you think there’s a way to make it viable to do this as an assertion on the version instead, and wire things up so that the correct stdenv is used by default in all-packages.nix or similar? It seems like this would silently eat overridden stdenvs for cross‐compilers, which seems a little sad.

(And: We seem to build cross GCCs with Clang without issue on Darwin, is that just us getting lucky?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do you think there’s a way to make it viable to do this as an assertion on the version instead, and wire things up so that the correct stdenv is used by default in all-packages.nix or similar? It seems like this would silently eat overridden stdenvs for cross‐compilers, which seems a little sad.

I would prefer not to fiddle with asserts (they would need to be not just version-specific, but probably target-specific as well to avoid mixing cross vs native --build gcc, which is so easy to get wrong when passing things explicitly in all-packages.nix).

Note that current all-packages.nix is this entry:

  inherit (callPackage ../development/compilers/gcc/all.nix { inherit noSysDirs; })
    gcc7 gcc8 gcc9 gcc10 gcc11 gcc12 gcc13 gcc14;

It's not easy to inject version-specific overrides here.

(And: We seem to build cross GCCs with Clang without issue on Darwin, is that just us getting lucky?)

My guess is that gcc is present somewhere in the closure and it happens to work most of the time. Having said that pkgsCross.aarch64-multiplatform.gcc14 fails on x86_64-darwin for me (just like on x86_64-linux):

aarch64-unknown-linux-gnu-g++: error: unrecognized command-line option '-std=gnu++26'; did you mean '-std=gnu++20'?

It clearly pulls gcc13's cross-compiler from somewhere to build gcc-14.

Copy link
Member

@emilazy emilazy Nov 20, 2024

Choose a reason for hiding this comment

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

Alright, makes sense to me. Wouldn’t the stdenv.cc.isGNU case here break compiling GCC in a Clang‐based cross setting though? I’m probably just mixing up my offsets…

(BTW, I think callPackages would be correct for this, and would allow overrides.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At least by default gcc is used for cross-compilers on darwin.

$ nix eval --impure --expr 'with import ./. { system = "x86_64-darwin"; }; stdenv.cc.isGNU'
false

$ nix eval --impure --expr 'with import ./. { system = "x86_64-darwin"; }; pkgsCross.aarch64-multiplatform.stdenv.cc.isGNU'
true

$ nix eval --impure --expr 'with import ./. { system = "x86_64-darwin"; }; pkgsCross.aarch64-multiplatform.stdenv.cc'
«derivation /nix/store/3zr6clbyvsyi649073qlnxnjaa881xgw-aarch64-unknown-linux-gnu-gcc-wrapper-13.3.0.drv»

Looking at https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/cross/default.nix#L83 my guess is that nixpkgs only uses clang when it targets darwin.

Copy link
Member

Choose a reason for hiding this comment

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

Makes sense. Maybe pkgsLLVM could mess things up, but it’s probably an edge case. I’m happy to trust that you’ve thought this through better than I have.

@trofi
Copy link
Contributor Author

trofi commented Nov 25, 2024

Rebased past isl removal conflicts.

@emilazy
Copy link
Member

emilazy commented Nov 25, 2024

Sorry about that! This looks good to me and I’m happy to merge after eval. Do you know if the case where build == target but build != host is problematic?

@trofi
Copy link
Contributor Author

trofi commented Nov 25, 2024

Yes, I think it's problematic. I'm not sure if nixpkgs allows for an easy expression for Canadian crosses in general.

@emilazy
Copy link
Member

emilazy commented Nov 25, 2024

Would expanding the condition to (stdenv.buildPlatform != stdenv.hostPlatform || stdenv.hostPlatform != stdenv.targetPlatform) be more correct then?

When `gcc` is cross-built (`build` != `target` && `host` == `target`)
`gcc` assumes that it has a compatible cross-compiler in the environment
that can build target libraries. Version of a cross-compiler has to
match the compiler being cross-built as libraries frequently use fresh
compiler features, like `-std=c++26` or target-specific types like
`_Bfloat16`.

Version mismatch causes build failures like:

    NixOS#351905

Similar problems (but on a smaller scale) happen when a `gcc`
cross-compiler is built (`build` == `host` && `host` != `target`) built
by a mismatching version of a native compiler (`build` == `host` &&
`host` == `target`). That was worked around by forcing `gcc9Stdenv` for
older compiler versions.

Let's fix both problems by requiring the same compiler version for
cross-case.

Closes: NixOS#351905
@trofi
Copy link
Contributor Author

trofi commented Nov 25, 2024

Switched to stdenv.targetPlatform != stdenv.buildPlatform || stdenv.hostPlatform != stdenv.targetPlatform.

--- a/pkgs/development/compilers/gcc/all.nix
+++ b/pkgs/development/compilers/gcc/all.nix
@@ -42,7 +42,7 @@ let
         #
         # Let's fix both problems by requiring the same compiler version for
         # cross-case.
-        stdenv = if (stdenv.targetPlatform != stdenv.buildPlatform) && stdenv.cc.isGNU then pkgs."gcc${majorVersion}Stdenv" else stdenv;
+        stdenv = if (stdenv.targetPlatform != stdenv.buildPlatform || stdenv.hostPlatform != stdenv.targetPlatform) && stdenv.cc.isGNU then pkgs."gcc${majorVersion}Stdenv" else stdenv;
       }));
     in
       lib.nameValuePair attrName pkg;

@emilazy emilazy merged commit 504e3ec into NixOS:master Nov 25, 2024
16 of 17 checks passed
@trofi trofi deleted the gcc-cross-version-skew branch November 25, 2024 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: cross-compilation Building packages on a different platform than they will be used on 10.rebuild-darwin: 1-10 10.rebuild-linux: 101-500
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Build failure: pkgs.pkgsCross.riscv64.gcc14
2 participants