diff --git a/nix/pkgs/main/cross-compilation-env.nix b/nix/pkgs/main/cross-compilation-env.nix index 75b5862fc..a70ea9dbd 100644 --- a/nix/pkgs/main/cross-compilation-env.nix +++ b/nix/pkgs/main/cross-compilation-env.nix @@ -1,106 +1,99 @@ -{ lib -, pkgsBuildHost -, rust -, stdenv +{ + lib, + pkgsBuildHost, + rust, + stdenv, }: - lib.optionalAttrs stdenv.hostPlatform.isStatic { ROCKSDB_STATIC = ""; } -// -{ +// { CARGO_BUILD_RUSTFLAGS = lib.concatStringsSep - " " - ([] - ++ lib.optionals - stdenv.targetPlatform.isx86_64 - [ "-C" "target-cpu=x86-64-v2" ] - ++ lib.optionals - stdenv.targetPlatform.isAarch64 - [ "-C" "target-cpu=cortex-a55" ] # cortex-a55 == ARMv8.2-a - # This disables PIE for static builds, which isn't great in terms - # of security. Unfortunately, my hand is forced because nixpkgs' - # `libstdc++.a` is built without `-fPIE`, which precludes us from - # leaving PIE enabled. - ++ lib.optionals - stdenv.hostPlatform.isStatic - [ "-C" "relocation-model=static" ] - ++ lib.optionals - (stdenv.buildPlatform.config != stdenv.hostPlatform.config) - [ "-l" "c" ] - ++ lib.optionals - # This check has to match the one [here][0]. We only need to set - # these flags when using a different linker. Don't ask me why, - # though, because I don't know. All I know is it breaks otherwise. - # - # [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L37-L40 - ( - # Nixpkgs doesn't check for x86_64 here but we do, because I - # observed a failure building statically for x86_64 without - # including it here. Linkers are weird. - (stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isx86_64) - && stdenv.hostPlatform.isStatic - && !stdenv.isDarwin - && !stdenv.cc.bintools.isLLVM - ) - [ - "-l" - "stdc++" - "-L" - "${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib" - ] - ); + " " + ( + [] + ++ lib.optionals + stdenv.targetPlatform.isx86_64 + ["-C" "target-cpu=x86-64-v2"] + ++ lib.optionals + stdenv.targetPlatform.isAarch64 + ["-C" "target-cpu=cortex-a73"] # cortex-a73 == ARMv8-A + # This disables PIE for static builds, which isn't great in terms + # of security. Unfortunately, my hand is forced because nixpkgs' + # `libstdc++.a` is built without `-fPIE`, which precludes us from + # leaving PIE enabled. + ++ lib.optionals + stdenv.hostPlatform.isStatic + ["-C" "relocation-model=static"] + ++ lib.optionals + (stdenv.buildPlatform.config != stdenv.hostPlatform.config) + ["-l" "c"] + ++ lib.optionals + # This check has to match the one [here][0]. We only need to set + # these flags when using a different linker. Don't ask me why, + # though, because I don't know. All I know is it breaks otherwise. + # + # [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L37-L40 + ( + # Nixpkgs doesn't check for x86_64 here but we do, because I + # observed a failure building statically for x86_64 without + # including it here. Linkers are weird. + (stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isx86_64) + && stdenv.hostPlatform.isStatic + && !stdenv.isDarwin + && !stdenv.cc.bintools.isLLVM + ) + [ + "-l" + "stdc++" + "-L" + "${stdenv.cc.cc.lib}/${stdenv.hostPlatform.config}/lib" + ] + ); } - # What follows is stolen from [here][0]. Its purpose is to properly # configure compilers and linkers for various stages of the build, and # even covers the case of build scripts that need native code compiled and # run on the build platform (I think). # # [0]: https://github.com/NixOS/nixpkgs/blob/5cdb38bb16c6d0a38779db14fcc766bc1b2394d6/pkgs/build-support/rust/lib/default.nix#L57-L80 -// -( +// ( let inherit (rust.lib) envVars; in - lib.optionalAttrs + lib.optionalAttrs (stdenv.targetPlatform.rust.rustcTarget != stdenv.hostPlatform.rust.rustcTarget) ( let inherit (stdenv.targetPlatform.rust) cargoEnvVarTarget; - in - { + in { "CC_${cargoEnvVarTarget}" = envVars.ccForTarget; "CXX_${cargoEnvVarTarget}" = envVars.cxxForTarget; "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForTarget; } ) - // - ( - let - inherit (stdenv.hostPlatform.rust) cargoEnvVarTarget rustcTarget; - in - { - "CC_${cargoEnvVarTarget}" = envVars.ccForHost; - "CXX_${cargoEnvVarTarget}" = envVars.cxxForHost; - "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForHost; - CARGO_BUILD_TARGET = rustcTarget; - } - ) - // - ( - let - inherit (stdenv.buildPlatform.rust) cargoEnvVarTarget; - in - { - "CC_${cargoEnvVarTarget}" = envVars.ccForBuild; - "CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild; - "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForBuild; - HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc"; - HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++"; - } - ) + // ( + let + inherit (stdenv.hostPlatform.rust) cargoEnvVarTarget rustcTarget; + in { + "CC_${cargoEnvVarTarget}" = envVars.ccForHost; + "CXX_${cargoEnvVarTarget}" = envVars.cxxForHost; + "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForHost; + CARGO_BUILD_TARGET = rustcTarget; + } + ) + // ( + let + inherit (stdenv.buildPlatform.rust) cargoEnvVarTarget; + in { + "CC_${cargoEnvVarTarget}" = envVars.ccForBuild; + "CXX_${cargoEnvVarTarget}" = envVars.cxxForBuild; + "CARGO_TARGET_${cargoEnvVarTarget}_LINKER" = envVars.linkerForBuild; + HOST_CC = "${pkgsBuildHost.stdenv.cc}/bin/cc"; + HOST_CXX = "${pkgsBuildHost.stdenv.cc}/bin/c++"; + } + ) ) diff --git a/nix/pkgs/main/default.nix b/nix/pkgs/main/default.nix index 72d674650..d8142d511 100644 --- a/nix/pkgs/main/default.nix +++ b/nix/pkgs/main/default.nix @@ -1,205 +1,225 @@ # Dependencies (keep sorted) -{ craneLib -, inputs -, jq -, lib -, libiconv -, liburing -, pkgsBuildHost -, rocksdb -, rust -, rust-jemalloc-sys -, stdenv - -# Options (keep sorted) -, default_features ? true -, disable_release_max_log_level ? false -, all_features ? false -, disable_features ? [] -, features ? [] -, profile ? "release" -}: - -let -# We perform default-feature unification in nix, because some of the dependencies -# on the nix side depend on feature values. -crateFeatures = path: - let manifest = lib.importTOML "${path}/Cargo.toml"; in - lib.remove "default" (lib.attrNames manifest.features); -crateDefaultFeatures = path: - (lib.importTOML "${path}/Cargo.toml").features.default; -allDefaultFeatures = crateDefaultFeatures "${inputs.self}/src/main"; -allFeatures = crateFeatures "${inputs.self}/src/main"; -features' = lib.unique - (features ++ - lib.optionals default_features allDefaultFeatures ++ - lib.optionals all_features allFeatures); -disable_features' = disable_features ++ lib.optionals disable_release_max_log_level ["release_max_log_level"]; -features'' = lib.subtractLists disable_features' features'; - -featureEnabled = feature : builtins.elem feature features''; - -enableLiburing = featureEnabled "io_uring" && !stdenv.isDarwin; - -# This derivation will set the JEMALLOC_OVERRIDE variable, causing the -# tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's -# own. In order for this to work, we need to set flags on the build that match -# whatever flags tikv-jemalloc-sys was going to use. These are dependent on -# which features we enable in tikv-jemalloc-sys. -rust-jemalloc-sys' = (rust-jemalloc-sys.override { - # tikv-jemalloc-sys/unprefixed_malloc_on_supported_platforms feature - unprefixed = true; -}).overrideAttrs (old: { - configureFlags = old.configureFlags ++ - # we dont need docs - [ "--disable-doc" ] ++ - # we dont need cxx/C++ integration - [ "--disable-cxx" ] ++ - # tikv-jemalloc-sys/profiling feature - lib.optional (featureEnabled "jemalloc_prof") "--enable-prof"; -}); - -buildDepsOnlyEnv = - let - rocksdb' = (rocksdb.override { - jemalloc = rust-jemalloc-sys'; - # rocksdb fails to build with prefixed jemalloc, which is required on - # darwin due to [1]. In this case, fall back to building rocksdb with - # libc malloc. This should not cause conflicts, because all of the - # jemalloc symbols are prefixed. - # - # [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17 - enableJemalloc = featureEnabled "jemalloc" && !stdenv.isDarwin; - - # for some reason enableLiburing in nixpkgs rocksdb is default true - # which breaks Darwin entirely - enableLiburing = enableLiburing; - }).overrideAttrs (old: { - # TODO: static rocksdb fails to build on darwin, also see - # build log at - meta.broken = stdenv.hostPlatform.isStatic && stdenv.isDarwin; - - enableLiburing = enableLiburing; - - sse42Support = stdenv.targetPlatform.isx86_64; - - cmakeFlags = if stdenv.targetPlatform.isx86_64 - then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags - ++ lib.optionals stdenv.targetPlatform.isx86_64 [ - "-DPORTABLE=x86-64-v2" - "-DUSE_SSE=1" - "-DHAVE_SSE=1" - "-DHAVE_SSE42=1" - ] - else if stdenv.targetPlatform.isAarch64 - then lib.subtractLists [ "-DPORTABLE=1" ] old.cmakeFlags - ++ lib.optionals stdenv.targetPlatform.isAarch64 [ - # cortex-a55 == ARMv8.2-a - "-DPORTABLE=armv8.2-a" - ] - else old.cmakeFlags; - }); +{ + craneLib, + inputs, + jq, + lib, + libiconv, + liburing, + pkgsBuildHost, + rocksdb, + rust, + rust-jemalloc-sys, + stdenv, + # Options (keep sorted) + default_features ? true, + disable_release_max_log_level ? false, + all_features ? false, + disable_features ? [], + features ? [], + profile ? "release", +}: let + # We perform default-feature unification in nix, because some of the dependencies + # on the nix side depend on feature values. + crateFeatures = path: let + manifest = lib.importTOML "${path}/Cargo.toml"; in - { - # https://crane.dev/faq/rebuilds-bindgen.html - NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa"; - - CARGO_PROFILE = profile; - ROCKSDB_INCLUDE_DIR = "${rocksdb'}/include"; - ROCKSDB_LIB_DIR = "${rocksdb'}/lib"; - } - // - (import ./cross-compilation-env.nix { - # Keep sorted - inherit - lib - pkgsBuildHost - rust - stdenv; - }); - -buildPackageEnv = { - CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev or ""; -} // buildDepsOnlyEnv // { - # Only needed in static stdenv because these are transitive dependencies of rocksdb - CARGO_BUILD_RUSTFLAGS = buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS - + lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic) - " -L${lib.getLib liburing}/lib -luring" - + lib.optionalString stdenv.targetPlatform.isx86_64 - " -Ctarget-cpu=x86-64-v2" - + lib.optionalString stdenv.targetPlatform.isAarch64 - " -Ctarget-cpu=cortex-a55"; # cortex-a55 == ARMv8.2-a -}; - - - -commonAttrs = { - inherit - (craneLib.crateNameFromCargoToml { - cargoToml = "${inputs.self}/Cargo.toml"; + lib.remove "default" (lib.attrNames manifest.features); + crateDefaultFeatures = path: + (lib.importTOML "${path}/Cargo.toml").features.default; + allDefaultFeatures = crateDefaultFeatures "${inputs.self}/src/main"; + allFeatures = crateFeatures "${inputs.self}/src/main"; + features' = + lib.unique + (features + ++ lib.optionals default_features allDefaultFeatures + ++ lib.optionals all_features allFeatures); + disable_features' = disable_features ++ lib.optionals disable_release_max_log_level ["release_max_log_level"]; + features'' = lib.subtractLists disable_features' features'; + + featureEnabled = feature: builtins.elem feature features''; + + enableLiburing = featureEnabled "io_uring" && !stdenv.isDarwin; + + # This derivation will set the JEMALLOC_OVERRIDE variable, causing the + # tikv-jemalloc-sys crate to use the nixpkgs jemalloc instead of building it's + # own. In order for this to work, we need to set flags on the build that match + # whatever flags tikv-jemalloc-sys was going to use. These are dependent on + # which features we enable in tikv-jemalloc-sys. + rust-jemalloc-sys' = + (rust-jemalloc-sys.override { + # tikv-jemalloc-sys/unprefixed_malloc_on_supported_platforms feature + unprefixed = true; }) - pname - version; - - src = let filter = inputs.nix-filter.lib; in filter { - root = inputs.self; + .overrideAttrs (old: { + configureFlags = + old.configureFlags + ++ + # we dont need docs + ["--disable-doc"] + ++ + # we dont need cxx/C++ integration + ["--disable-cxx"] + ++ + # tikv-jemalloc-sys/profiling feature + lib.optional (featureEnabled "jemalloc_prof") "--enable-prof"; + }); + buildDepsOnlyEnv = let + rocksdb' = + (rocksdb.override { + jemalloc = rust-jemalloc-sys'; + # rocksdb fails to build with prefixed jemalloc, which is required on + # darwin due to [1]. In this case, fall back to building rocksdb with + # libc malloc. This should not cause conflicts, because all of the + # jemalloc symbols are prefixed. + # + # [1]: https://github.com/tikv/jemallocator/blob/ab0676d77e81268cd09b059260c75b38dbef2d51/jemalloc-sys/src/env.rs#L17 + enableJemalloc = featureEnabled "jemalloc" && !stdenv.isDarwin; + + # for some reason enableLiburing in nixpkgs rocksdb is default true + # which breaks Darwin entirely + enableLiburing = enableLiburing; + }) + .overrideAttrs (old: { + # TODO: static rocksdb fails to build on darwin, also see + # build log at + meta.broken = stdenv.hostPlatform.isStatic && stdenv.isDarwin; + + enableLiburing = enableLiburing; + + sse42Support = stdenv.targetPlatform.isx86_64; + + cmakeFlags = + if stdenv.targetPlatform.isx86_64 + then + lib.subtractLists ["-DPORTABLE=1"] old.cmakeFlags + ++ lib.optionals stdenv.targetPlatform.isx86_64 [ + "-DPORTABLE=x86-64-v2" + "-DUSE_SSE=1" + "-DHAVE_SSE=1" + "-DHAVE_SSE42=1" + ] + else if stdenv.targetPlatform.isAarch64 + then + lib.subtractLists ["-DPORTABLE=1"] old.cmakeFlags + ++ lib.optionals stdenv.targetPlatform.isAarch64 [ + # cortex-a73 == ARMv8-A + "-DPORTABLE=armv8-a" + ] + else old.cmakeFlags; + }); + in + { + # https://crane.dev/faq/rebuilds-bindgen.html + NIX_OUTPATH_USED_AS_RANDOM_SEED = "aaaaaaaaaa"; + + CARGO_PROFILE = profile; + ROCKSDB_INCLUDE_DIR = "${rocksdb'}/include"; + ROCKSDB_LIB_DIR = "${rocksdb'}/lib"; + } + // (import ./cross-compilation-env.nix { # Keep sorted - include = [ - "Cargo.lock" - "Cargo.toml" - "deps" - "src" - ]; + inherit + lib + pkgsBuildHost + rust + stdenv + ; + }); + + buildPackageEnv = + { + CONDUWUIT_VERSION_EXTRA = inputs.self.shortRev or inputs.self.dirtyShortRev or ""; + } + // buildDepsOnlyEnv + // { + # Only needed in static stdenv because these are transitive dependencies of rocksdb + CARGO_BUILD_RUSTFLAGS = + buildDepsOnlyEnv.CARGO_BUILD_RUSTFLAGS + + lib.optionalString (enableLiburing && stdenv.hostPlatform.isStatic) + " -L${lib.getLib liburing}/lib -luring" + + lib.optionalString stdenv.targetPlatform.isx86_64 + " -Ctarget-cpu=x86-64-v2" + + lib.optionalString stdenv.targetPlatform.isAarch64 + " -Ctarget-cpu=cortex-a73"; # cortex-a73 == ARMv8-a }; + commonAttrs = { + inherit + (craneLib.crateNameFromCargoToml { + cargoToml = "${inputs.self}/Cargo.toml"; + }) + pname + version + ; + + src = let + filter = inputs.nix-filter.lib; + in + filter { + root = inputs.self; + + # Keep sorted + include = [ + "Cargo.lock" + "Cargo.toml" + "deps" + "src" + ]; + }; + dontStrip = profile == "dev" || profile == "test"; buildInputs = lib.optional (featureEnabled "jemalloc") rust-jemalloc-sys'; - nativeBuildInputs = [ - # bindgen needs the build platform's libclang. Apparently due to "splicing - # weirdness", pkgs.rustPlatform.bindgenHook on its own doesn't quite do the - # right thing here. - pkgsBuildHost.rustPlatform.bindgenHook - - # We don't actually depend on `jq`, but crane's `buildPackage` does, but - # its `buildDepsOnly` doesn't. This causes those two derivations to have - # differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious - # rebuilds of bindgen and its depedents. - jq - ] - ++ lib.optionals stdenv.isDarwin [ - # https://github.com/NixOS/nixpkgs/issues/206242 - libiconv - - # https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell - # https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612 - pkgsBuildHost.darwin.apple_sdk.frameworks.Security - ]; - }; -in - -craneLib.buildPackage ( commonAttrs // { - cargoArtifacts = craneLib.buildDepsOnly (commonAttrs // { - env = buildDepsOnlyEnv; - }); - - cargoExtraArgs = "--no-default-features " - + lib.optionalString - (features'' != []) - "--features " + (builtins.concatStringsSep "," features''); - - # This is redundant with CI - cargoTestCommand = ""; - cargoCheckCommand = ""; - doCheck = false; - - env = buildPackageEnv; - - passthru = { - env = buildPackageEnv; + nativeBuildInputs = + [ + # bindgen needs the build platform's libclang. Apparently due to "splicing + # weirdness", pkgs.rustPlatform.bindgenHook on its own doesn't quite do the + # right thing here. + pkgsBuildHost.rustPlatform.bindgenHook + + # We don't actually depend on `jq`, but crane's `buildPackage` does, but + # its `buildDepsOnly` doesn't. This causes those two derivations to have + # differing values for `NIX_CFLAGS_COMPILE`, which contributes to spurious + # rebuilds of bindgen and its depedents. + jq + ] + ++ lib.optionals stdenv.isDarwin [ + # https://github.com/NixOS/nixpkgs/issues/206242 + libiconv + + # https://stackoverflow.com/questions/69869574/properly-adding-darwin-apple-sdk-to-a-nix-shell + # https://discourse.nixos.org/t/compile-a-rust-binary-on-macos-dbcrossbar/8612 + pkgsBuildHost.darwin.apple_sdk.frameworks.Security + ]; }; - - meta.mainProgram = commonAttrs.pname; -}) +in + craneLib.buildPackage (commonAttrs + // { + cargoArtifacts = craneLib.buildDepsOnly (commonAttrs + // { + env = buildDepsOnlyEnv; + }); + + cargoExtraArgs = + "--no-default-features " + + lib.optionalString + (features'' != []) + "--features " + + (builtins.concatStringsSep "," features''); + + # This is redundant with CI + cargoTestCommand = ""; + cargoCheckCommand = ""; + doCheck = false; + + env = buildPackageEnv; + + passthru = { + env = buildPackageEnv; + }; + + meta.mainProgram = commonAttrs.pname; + })