Commit e3e57b8f authored by Alyssa Ross's avatar Alyssa Ross
Browse files

lib.systems: elaborate Rust metadata

We need this stuff to be available in lib so make-derivation.nix can
access it to construct the Meson cross file.

This has a couple of other advantages:

 - It makes Rust less special.  Now figuring out what Rust calls a
   platform is the same as figuring out what Linux or QEMU call it.

 - We can unify the schema used to define Rust targets, and the schema
   used to access those values later.  Just like you can set "config"
   or "system" in a platform definition, and then access those same
   keys on the elaborated platform, you can now set "rustcTarget" in
   your crossSystem, and then access "stdenv.hostPlatform.rustcTarget"
   in your code.

"rustcTarget", "rustcTargetSpec", "cargoShortTarget", and
"cargoEnvVarTarget" have the "rustc" and "cargo" prefixes because
these are not exposed to code by the compiler, and are not
standardized.  The arch/os/etc. variables are all named to match the
forms in the Rust target spec JSON.

The new rust.target-family only takes a list, since we don't need to
worry about backwards compatibility when that name is used.

The old APIs are all still functional with no warning for now, so that
it's possible for external code to use a single API on both 23.05 and
23.11.  We can introduce the warnings once 23.05 is EOL, and make them
hard errors when 23.11 is EOL.
parent fecd99b1
Loading
Loading
Loading
Loading
+98 −2
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@ rec {
  elaborate = args': let
    args = if lib.isString args' then { system = args'; }
           else args';

    # TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL.
    rust = assert !(args ? rust && args ? rustc); args.rust or args.rustc or {};

    final = {
      # Prefer to parse `config` as it is strictly more informative.
      parsed = parse.mkSystemFromString (if args ? config then args.config else args.system);
@@ -159,9 +163,101 @@ rec {
        ({
          linux-kernel = args.linux-kernel or {};
          gcc = args.gcc or {};
          rustc = args.rustc or {};
        } // platforms.select final)
        linux-kernel gcc rustc;
        linux-kernel gcc;

      # TODO: remove after 23.05 is EOL, with an error pointing to the rust.* attrs.
      rustc = args.rustc or {};

      rust = rust // {
        # Once args.rustc.platform.target-family is deprecated and
        # removed, there will no longer be any need to modify any
        # values from args.rust.platform, so we can drop all the
        # "args ? rust" etc. checks, and merge args.rust.platform in
        # /after/.
        platform = rust.platform or {} // {
          # https://doc.rust-lang.org/reference/conditional-compilation.html#target_arch
          arch =
            /**/ if rust ? platform then rust.platform.arch
            else if final.isAarch32 then "arm"
            else if final.isMips64  then "mips64"     # never add "el" suffix
            else if final.isPower64 then "powerpc64"  # never add "le" suffix
            else final.parsed.cpu.name;

          # https://doc.rust-lang.org/reference/conditional-compilation.html#target_os
          os =
            /**/ if rust ? platform then rust.platform.os or "none"
            else if final.isDarwin then "macos"
            else final.parsed.kernel.name;

          # https://doc.rust-lang.org/reference/conditional-compilation.html#target_family
          target-family =
            /**/ if args ? rust.platform.target-family then args.rust.platform.target-family
            else if args ? rustc.platform.target-family
            then
              (
                # Since https://github.com/rust-lang/rust/pull/84072
                # `target-family` is a list instead of single value.
                let
                  f = args.rustc.platform.target-family;
                in
                  if builtins.isList f then f else [ f ]
              )
            else lib.optional final.isUnix "unix"
                 ++ lib.optional final.isWindows "windows";

          # https://doc.rust-lang.org/reference/conditional-compilation.html#target_vendor
          vendor = let
            inherit (final.parsed) vendor;
          in rust.platform.vendor or {
            "w64" = "pc";
          }.${vendor.name} or vendor.name;
        };

        # The name of the rust target, even if it is custom. Adjustments are
        # because rust has slightly different naming conventions than we do.
        rustcTarget = let
          inherit (final.parsed) cpu kernel abi;
          cpu_ = rust.platform.arch or {
            "armv7a" = "armv7";
            "armv7l" = "armv7";
            "armv6l" = "arm";
            "armv5tel" = "armv5te";
            "riscv64" = "riscv64gc";
          }.${cpu.name} or cpu.name;
          vendor_ = final.rust.platform.vendor;
        in rust.config
          or "${cpu_}-${vendor_}-${kernel.name}${lib.optionalString (abi.name != "unknown") "-${abi.name}"}";

        # The name of the rust target if it is standard, or the json file
        # containing the custom target spec.
        rustcTargetSpec =
          /**/ if rust ? platform
          then builtins.toFile (final.rust.rustcTarget + ".json") (builtins.toJSON rust.platform)
          else final.rust.rustcTarget;

        # The name of the rust target if it is standard, or the
        # basename of the file containing the custom target spec,
        # without the .json extension.
        #
        # This is the name used by Cargo for target subdirectories.
        cargoShortTarget =
          lib.removeSuffix ".json" (baseNameOf "${final.rust.rustcTargetSpec}");

        # When used as part of an environment variable name, triples are
        # uppercased and have all hyphens replaced by underscores:
        #
        # https://github.com/rust-lang/cargo/pull/9169
        # https://github.com/rust-lang/cargo/issues/8285#issuecomment-634202431
        cargoEnvVarTarget =
          lib.strings.replaceStrings ["-"] ["_"]
            (lib.strings.toUpper final.rust.cargoShortTarget);

        # True if the target is no_std
        # https://github.com/rust-lang/rust/blob/2e44c17c12cec45b6a682b1e53a04ac5b5fcc9d2/src/bootstrap/config.rs#L415-L421
        isNoStdTarget =
          builtins.any (t: lib.hasInfix t final.rust.rustcTarget) ["-none" "nvptx" "switch" "-uefi"];
      };

      linuxArch =
        if final.isAarch32 then "arm"
+2 −2
Original line number Diff line number Diff line
{ autoreconfHook, boost180, cargo, coreutils, curl, cxx-rs, db62, fetchFromGitHub
, git, hexdump, lib, libevent, libsodium, makeWrapper, rust, rustPlatform
, git, hexdump, lib, libevent, libsodium, makeWrapper, rustPlatform
, pkg-config, Security, stdenv, testers, tl-expected, utf8cpp, util-linux, zcash, zeromq
}:

@@ -57,7 +57,7 @@ rustPlatform.buildRustPackage.override { inherit stdenv; } rec {
  configureFlags = [
    "--disable-tests"
    "--with-boost-libdir=${lib.getLib boost180}/lib"
    "RUST_TARGET=${rust.toRustTargetSpec stdenv.hostPlatform}"
    "RUST_TARGET=${stdenv.hostPlatform.rust.rustcTargetSpec}"
  ];

  enableParallelBuilding = true;
+1 −2
Original line number Diff line number Diff line
@@ -5,7 +5,6 @@
, openssl
, gtk3
, stdenv
, rust
}:

rustPlatform.buildRustPackage rec {
@@ -28,7 +27,7 @@ rustPlatform.buildRustPackage rec {
  # default installPhase don't install assets
  installPhase = ''
    runHook preInstall
    make install PREFIX="$out" TARGET="target/${rust.toRustTarget stdenv.hostPlatform}/release/effitask"
    make install PREFIX="$out" TARGET="target/${stdenv.hostPlatform.rust.rustcTarget}/release/effitask"
    runHook postInstall
  '';

+3 −3
Original line number Diff line number Diff line
{ lib, stdenv, fetchFromGitHub, rust, rustPlatform
{ lib, stdenv, fetchFromGitHub, rustPlatform
, cargo, just, pkg-config, util-linuxMinimal
, dbus, glib, libxkbcommon, pulseaudio, wayland
}:
@@ -41,11 +41,11 @@ rustPlatform.buildRustPackage {

  justFlags = [
    "--set" "prefix" (placeholder "out")
    "--set" "target" "${rust.lib.toRustTargetSpecShort stdenv.hostPlatform}/release"
    "--set" "target" "${stdenv.hostPlatform.rust.cargoShortTarget}/release"
  ];

  # Force linking to libwayland-client, which is always dlopen()ed.
  "CARGO_TARGET_${rust.toRustTargetForUseInEnvVars stdenv.hostPlatform}_RUSTFLAGS" =
  "CARGO_TARGET_${stdenv.hostPlatform.rust.cargoEnvVarTarget}_RUSTFLAGS" =
    map (a: "-C link-arg=${a}") [
      "-Wl,--push-state,--no-as-needed"
      "-lwayland-client"
+3 −3
Original line number Diff line number Diff line
{ lib, stdenv, fetchFromGitHub, cargo, just, pkg-config, rust, rustPlatform
{ lib, stdenv, fetchFromGitHub, cargo, just, pkg-config, rustPlatform
, libglvnd, libxkbcommon, wayland
}:

@@ -33,11 +33,11 @@ rustPlatform.buildRustPackage {

  justFlags = [
    "--set" "prefix" (placeholder "out")
    "--set" "bin-src" "target/${rust.lib.toRustTargetSpecShort stdenv.hostPlatform}/release/cosmic-panel"
    "--set" "bin-src" "target/${stdenv.hostPlatform.rust.cargoShortTarget}/release/cosmic-panel"
  ];

  # Force linking to libEGL, which is always dlopen()ed.
  "CARGO_TARGET_${rust.toRustTargetForUseInEnvVars stdenv.hostPlatform}_RUSTFLAGS" =
  "CARGO_TARGET_${stdenv.hostPlatform.rust.cargoEnvVarTarget}_RUSTFLAGS" =
    map (a: "-C link-arg=${a}") [
      "-Wl,--push-state,--no-as-needed"
      "-lEGL"
Loading