Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

Merge pull request #83601 from andir/20.03-buildRustCrate-fixes

[20.03] buildRustCrate fixes backports

authored by

Florian Klink and committed by
GitHub
e46f456d aa3c504e

+440 -71
+3 -5
pkgs/build-support/rust/build-rust-crate/build-crate.nix
··· 1 - { lib, stdenv, echo_build_heading, noisily, mkRustcDepArgs, rust }: 1 + { lib, stdenv, mkRustcDepArgs, rust }: 2 2 { crateName, 3 3 dependencies, 4 4 crateFeatures, crateRenames, libName, release, libPath, ··· 11 11 baseRustcOpts = 12 12 [(if release then "-C opt-level=3" else "-C debuginfo=2")] 13 13 ++ ["-C codegen-units=$NIX_BUILD_CORES"] 14 + ++ ["--remap-path-prefix=$NIX_BUILD_TOP=/" ] 14 15 ++ [(mkRustcDepArgs dependencies crateRenames)] 15 16 ++ [crateFeatures] 16 17 ++ extraRustcOpts ··· 34 35 build_bin = if buildTests then "build_bin_test" else "build_bin"; 35 36 in '' 36 37 runHook preBuild 37 - ${echo_build_heading colors} 38 - ${noisily colors verbose} 39 - 38 + 40 39 # configure & source common build functions 41 40 LIB_RUSTC_OPTS="${libRustcOpts}" 42 41 BIN_RUSTC_OPTS="${binRustcOpts}" 43 42 LIB_EXT="${stdenv.hostPlatform.extensions.sharedLibrary}" 44 43 LIB_PATH="${libPath}" 45 44 LIB_NAME="${libName}" 46 - source ${./lib.sh} 47 45 48 46 CRATE_NAME='${lib.replaceStrings ["-"] ["_"] libName}' 49 47
+65 -20
pkgs/build-support/rust/build-rust-crate/configure-crate.nix
··· 1 - { lib, stdenv, echo_build_heading, noisily, mkRustcDepArgs }: 1 + { lib, stdenv, echo_colored, noisily, mkRustcDepArgs }: 2 2 { build 3 3 , buildDependencies 4 4 , colors ··· 31 31 completeDepsDir = lib.concatStringsSep " " completeDeps; 32 32 completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps; 33 33 in '' 34 - cd ${workspace_member} 34 + ${echo_colored colors} 35 + ${noisily colors verbose} 36 + source ${./lib.sh} 37 + 38 + ${lib.optionalString (workspace_member != null) '' 39 + noisily cd "${workspace_member}" 40 + ''} 41 + ${lib.optionalString (workspace_member == null) '' 42 + echo_colored "Searching for matching Cargo.toml (${crateName})" 43 + local cargo_toml_dir=$(matching_cargo_toml_dir "${crateName}") 44 + if [ -z "$cargo_toml_dir" ]; then 45 + echo_error "ERROR configuring ${crateName}: No matching Cargo.toml in $(pwd) found." >&2 46 + exit 23 47 + fi 48 + noisily cd "$cargo_toml_dir" 49 + ''} 50 + 35 51 runHook preConfigure 36 - ${echo_build_heading colors} 37 - ${noisily colors verbose} 52 + 38 53 symlink_dependency() { 39 54 # $1 is the nix-store path of a dependency 40 55 # $2 is the target path 41 56 i=$1 42 57 ln -s -f $i/lib/*.rlib $2 #*/ 43 58 ln -s -f $i/lib/*.so $i/lib/*.dylib $2 #*/ 44 - if [ -e "$i/lib/link" ]; then 45 - cat $i/lib/link >> target/link 46 - cat $i/lib/link >> target/link.final 47 - fi 48 59 if [ -e $i/env ]; then 49 60 source $i/env 50 61 fi 51 62 } 52 63 64 + # The following steps set up the dependencies of the crate. Two 65 + # kinds of dependencies are distinguished: build dependencies 66 + # (used by the build script) and crate dependencies. For each 67 + # dependency we have to: 68 + # 69 + # - Make its Rust library available to rustc. This is done by 70 + # symlinking all library dependencies into a directory that 71 + # can be provided to rustc. 72 + # - Accumulate linking flags. These flags are largely used for 73 + # linking native libraries. 74 + # 75 + # The crate link flags are added to the `link` and `link.final` 76 + # files. The `link` file is used for linkage in the current 77 + # crate. The `link.final` file will be copied to the output and can 78 + # be used by downstream crates to get the linker flags of this 79 + # crate. 80 + 53 81 mkdir -p target/{deps,lib,build,buildDeps} 54 82 chmod uga+w target -R 55 83 echo ${extraLinkFlags} > target/link 56 84 echo ${extraLinkFlags} > target/link.final 85 + 86 + # Prepare crate dependencies 57 87 for i in ${completeDepsDir}; do 58 88 symlink_dependency $i target/deps 89 + if [ -e "$i/lib/link" ]; then 90 + cat $i/lib/link >> target/link 91 + cat $i/lib/link >> target/link.final 92 + fi 59 93 done 94 + 95 + # Prepare crate build dependencies that are used for the build script. 60 96 for i in ${completeBuildDepsDir}; do 61 - symlink_dependency $i target/buildDeps 97 + symlink_dependency $i target/buildDeps 98 + if [ -e "$i/lib/link" ]; then 99 + cat $i/lib/link >> target/link.build 100 + fi 62 101 done 63 - if [[ -e target/link ]]; then 64 - sort -u target/link > target/link.sorted 65 - mv target/link.sorted target/link 66 - sort -u target/link.final > target/link.final.sorted 67 - mv target/link.final.sorted target/link.final 68 - tr '\n' ' ' < target/link > target/link_ 102 + 103 + # Remove duplicate linker flags from the build dependencies. 104 + if [[ -e target/link.build ]]; then 105 + sort -uo target/link.build target/link.build 69 106 fi 107 + 108 + # Remove duplicate linker flags from the dependencies. 109 + sort -uo target/link target/link 110 + tr '\n' ' ' < target/link > target/link_ 111 + 112 + # Remove duplicate linker flags from the that are written 113 + # to the derivation's output. 114 + sort -uo target/link.final target/link.final 115 + 70 116 EXTRA_BUILD="" 71 117 BUILD_OUT_DIR="" 72 118 export CARGO_PKG_NAME=${crateName} ··· 105 151 elif [[ -e "build.rs" ]]; then 106 152 BUILD="build.rs" 107 153 fi 154 + 155 + # Compile and run the build script, when available. 108 156 if [[ ! -z "$BUILD" ]] ; then 109 157 echo_build_heading "$BUILD" ${libName} 110 158 mkdir -p target/build/${crateName} 111 159 EXTRA_BUILD_FLAGS="" 112 - if [ -e target/link_ ]; then 113 - EXTRA_BUILD_FLAGS=$(cat target/link_) 114 - fi 115 160 if [ -e target/link.build ]; then 116 - EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(cat target/link.build)" 161 + EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(tr '\n' ' ' < target/link.build)" 117 162 fi 118 163 noisily rustc --crate-name build_script_build $BUILD --crate-type bin ${rustcOpts} \ 119 164 ${crateFeatures} --out-dir target/build/${crateName} --emit=dep-info,link \ ··· 127 172 set +e 128 173 EXTRA_BUILD=$(sed -n "s/^cargo:rustc-flags=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u) 129 174 EXTRA_FEATURES=$(sed -n "s/^cargo:rustc-cfg=\(.*\)/--cfg \1/p" target/build/${crateName}.opt | tr '\n' ' ') 130 - EXTRA_LINK=$(sed -n "s/^cargo:rustc-link-lib=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u) 175 + EXTRA_LINK=$(sed -n "s/^cargo:rustc-link-lib=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ') 131 176 EXTRA_LINK_SEARCH=$(sed -n "s/^cargo:rustc-link-search=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u) 132 177 133 178 for env in $(sed -n "s/^cargo:rustc-env=\(.*\)/\1/p" target/build/${crateName}.opt); do
+10 -11
pkgs/build-support/rust/build-rust-crate/default.nix
··· 4 4 # This can be useful for deploying packages with NixOps, and to share 5 5 # binary dependencies between projects. 6 6 7 - { lib, stdenv, defaultCrateOverrides, fetchCrate, rustc, rust }: 7 + { lib, stdenv, defaultCrateOverrides, fetchCrate, rustc, rust, cargo, jq }: 8 8 9 9 let 10 10 # This doesn't appear to be officially documented anywhere yet. ··· 29 29 " --extern ${name}=${dep.lib}/lib/lib${extern}-${dep.metadata}${stdenv.hostPlatform.extensions.sharedLibrary}") 30 30 ) dependencies; 31 31 32 - inherit (import ./log.nix { inherit lib; }) noisily echo_build_heading; 32 + inherit (import ./log.nix { inherit lib; }) noisily echo_colored; 33 33 34 34 configureCrate = import ./configure-crate.nix { 35 - inherit lib stdenv echo_build_heading noisily mkRustcDepArgs; 35 + inherit lib stdenv echo_colored noisily mkRustcDepArgs; 36 36 }; 37 37 38 38 buildCrate = import ./build-crate.nix { 39 - inherit lib stdenv echo_build_heading noisily mkRustcDepArgs rust; 39 + inherit lib stdenv mkRustcDepArgs rust; 40 40 }; 41 41 42 42 installCrate = import ./install-crate.nix { inherit stdenv; }; ··· 61 61 buildInputs_ = buildInputs; 62 62 extraRustcOpts_ = extraRustcOpts; 63 63 buildTests_ = buildTests; 64 - 65 - # take a list of crates that we depend on and override them to fit our overrides, rustc, release, … 66 - makeDependencies = map (dep: lib.getLib (dep.override { inherit release verbose crateOverrides; })); 67 64 68 65 # crate2nix has a hack for the old bash based build script that did split 69 66 # entries at `,`. No we have to work around that hack. ··· 91 88 92 89 src = crate.src or (fetchCrate { inherit (crate) crateName version sha256; }); 93 90 name = "rust_${crate.crateName}-${crate.version}${lib.optionalString buildTests_ "-test"}"; 94 - depsBuildBuild = [ rust stdenv.cc ]; 91 + depsBuildBuild = [ rust stdenv.cc cargo jq ]; 95 92 buildInputs = (crate.buildInputs or []) ++ buildInputs_; 96 - dependencies = makeDependencies dependencies_; 97 - buildDependencies = makeDependencies buildDependencies_; 93 + dependencies = map lib.getLib dependencies_; 94 + buildDependencies = map lib.getLib buildDependencies_; 98 95 99 96 completeDeps = lib.unique (dependencies ++ lib.concatMap (dep: dep.completeDeps) dependencies); 100 97 completeBuildDeps = lib.unique ( ··· 103 100 ); 104 101 105 102 crateFeatures = lib.optionalString (crate ? features) 106 - (lib.concatMapStringsSep " " (f: "--cfg feature=\\\"${f}\\\"") (crate.features ++ features)); 103 + (lib.concatMapStringsSep " " (f: ''--cfg feature=\"${f}\"'') (crate.features ++ features)); 107 104 108 105 libName = if crate ? libName then crate.libName else crate.crateName; 109 106 libPath = if crate ? libPath then crate.libPath else ""; ··· 117 114 in lib.substring 0 10 hashedMetadata; 118 115 119 116 build = crate.build or ""; 117 + # Either set to a concrete sub path to the crate root 118 + # or use `null` for auto-detect. 120 119 workspace_member = crate.workspace_member or "."; 121 120 crateVersion = crate.version; 122 121 crateDescription = crate.description or "";
+2 -2
pkgs/build-support/rust/build-rust-crate/install-crate.nix
··· 14 14 fi 15 15 if [[ "$(ls -A target/lib)" ]]; then 16 16 mkdir -p $lib/lib 17 - cp target/lib/* $lib/lib #*/ 17 + cp -r target/lib/* $lib/lib #*/ 18 18 for library in $lib/lib/*.so $lib/lib/*.dylib; do #*/ 19 19 ln -s $library $(echo $library | sed -e "s/-${metadata}//") 20 20 done ··· 26 26 if [[ -d target/bin ]]; then 27 27 if [[ "$(ls -A target/bin)" ]]; then 28 28 mkdir -p $out/bin 29 - cp -P target/bin/* $out/bin # */ 29 + cp -rP target/bin/* $out/bin # */ 30 30 fi 31 31 fi 32 32 runHook postInstall
+44 -8
pkgs/build-support/rust/build-rust-crate/lib.sh
··· 1 + echo_build_heading() { 2 + if (( $# == 1 )); then 3 + echo_colored "Building $1" 4 + else 5 + echo_colored "Building $1 ($2)" 6 + fi 7 + } 8 + 1 9 build_lib() { 2 10 lib_src=$1 3 11 echo_build_heading $lib_src ${libName} ··· 6 14 --crate-name $CRATE_NAME \ 7 15 $lib_src \ 8 16 --out-dir target/lib \ 9 - --emit=dep-info,link \ 10 17 -L dependency=target/deps \ 11 18 --cap-lints allow \ 12 19 $LIB_RUSTC_OPTS \ ··· 37 44 --crate-type bin \ 38 45 $BIN_RUSTC_OPTS \ 39 46 --out-dir target/bin \ 40 - --emit=dep-info,link \ 41 47 -L dependency=target/deps \ 42 48 $LINK \ 43 49 $EXTRA_LIB \ ··· 71 77 build_bin_test "$derived_crate_name" "$file" 72 78 } 73 79 80 + # Add additional link options that were provided by the build script. 74 81 setup_link_paths() { 75 82 EXTRA_LIB="" 76 83 if [[ -e target/link_ ]]; then ··· 96 103 done 97 104 98 105 if [[ -e target/link ]]; then 99 - sort -u target/link.final > target/link.final.sorted 100 - mv target/link.final.sorted target/link.final 101 - sort -u target/link > target/link.sorted 102 - mv target/link.sorted target/link 103 - 104 106 tr '\n' ' ' < target/link > target/link_ 105 107 LINK=$(cat target/link_) 106 108 fi ··· 132 134 done 133 135 134 136 if [[ -z "$BIN_PATH" ]]; then 135 - echo "failed to find file for binary target: $BIN_NAME" >&2 137 + echo_error "ERROR: failed to find file for binary target: $BIN_NAME" >&2 136 138 exit 1 137 139 fi 138 140 } 141 + 142 + # Extracts cargo_toml_path of the matching crate. 143 + matching_cargo_toml_path() { 144 + local manifest_path="$1" 145 + local expected_crate_name="$2" 146 + 147 + # If the Cargo.toml is not a workspace root, 148 + # it will only contain one package in ".packages" 149 + # because "--no-deps" suppressed dependency resolution. 150 + # 151 + # But to make it more general, we search for a matching 152 + # crate in all packages and use the manifest path that 153 + # is referenced there. 154 + cargo metadata --no-deps --format-version 1 \ 155 + --manifest-path "$manifest_path" \ 156 + | jq -r '.packages[] 157 + | select( .name == "'$expected_crate_name'") 158 + | .manifest_path' 159 + } 160 + 161 + # Find a Cargo.toml in the current or any sub directory 162 + # with a matching crate name. 163 + matching_cargo_toml_dir() { 164 + local expected_crate_name="$1" 165 + 166 + find -L -name Cargo.toml | sort | while read manifest_path; do 167 + echo "...checking manifest_path $manifest_path" >&2 168 + local matching_path="$(matching_cargo_toml_path "$manifest_path" "$expected_crate_name")" 169 + if [ -n "${matching_path}" ]; then 170 + echo "$(dirname $matching_path)" 171 + break 172 + fi 173 + done 174 + }
+48 -22
pkgs/build-support/rust/build-rust-crate/log.nix
··· 1 1 { lib }: 2 - { 3 - echo_build_heading = colors: '' 4 - echo_build_heading() { 5 - start="" 6 - end="" 7 - ${lib.optionalString (colors == "always") '' 8 - start="$(printf '\033[0;1;32m')" #set bold, and set green. 9 - end="$(printf '\033[0m')" #returns to "normal" 10 - ''} 11 - if (( $# == 1 )); then 12 - echo "$start""Building $1""$end" 13 - else 14 - echo "$start""Building $1 ($2)""$end" 15 - fi 2 + 3 + let echo_colored_body = start_escape: 4 + # Body of a function that behaves like "echo" but 5 + # has the output colored by the given start_escape 6 + # sequence. E.g. 7 + # 8 + # * echo_x "Building ..." 9 + # * echo_x -n "Running " 10 + # 11 + # This is more complicated than apparent at first sight 12 + # because: 13 + # * The color markers and the text must be print 14 + # in the same echo statement. Otherise, other 15 + # intermingled text from concurrent builds will 16 + # be colored as well. 17 + # * We need to preserve the trailing newline of the 18 + # echo if and only if it is present. Bash likes 19 + # to strip those if we capture the output of echo 20 + # in a variable. 21 + # * Leading "-" will be interpreted by test as an 22 + # option for itself. Therefore, we prefix it with 23 + # an x in `[[ "x$1" =~ ^x- ]]`. 24 + '' 25 + local echo_args=""; 26 + while [[ "x$1" =~ ^x- ]]; do 27 + echo_args+=" $1" 28 + shift 29 + done 30 + 31 + local start_escape="$(printf '${start_escape}')" 32 + local reset="$(printf '\033[0m')" 33 + echo $echo_args $start_escape"$@"$reset 34 + ''; 35 + echo_conditional_colored_body = colors: start_escape: 36 + if colors == "always" 37 + then (echo_colored_body start_escape) 38 + else ''echo "$@"''; 39 + in { 40 + echo_colored = colors: '' 41 + echo_colored() { 42 + ${echo_conditional_colored_body colors ''\033[0;1;32m''} 16 43 } 17 - ''; 44 + 45 + echo_error() { 46 + ${echo_conditional_colored_body colors ''\033[0;1;31m''} 47 + } 48 + ''; 49 + 18 50 noisily = colors: verbose: '' 19 51 noisily() { 20 - start="" 21 - end="" 22 - ${lib.optionalString (colors == "always") '' 23 - start="$(printf '\033[0;1;32m')" #set bold, and set green. 24 - end="$(printf '\033[0m')" #returns to "normal" 25 - ''} 26 52 ${lib.optionalString verbose '' 27 - echo -n "$start"Running "$end" 53 + echo_colored -n "Running " 28 54 echo $@ 29 55 ''} 30 56 $@
+268 -3
pkgs/build-support/rust/build-rust-crate/test/default.nix
··· 1 - { lib, buildRustCrate, runCommand, writeTextFile, symlinkJoin, callPackage, releaseTools }: 1 + { lib 2 + , buildRustCrate 3 + , callPackage 4 + , releaseTools 5 + , runCommand 6 + , runCommandCC 7 + , stdenv 8 + , symlinkJoin 9 + , writeTextFile 10 + }: 11 + 2 12 let 3 13 mkCrate = args: let 4 14 p = { ··· 7 17 authors = [ "Test <test@example.com>" ]; 8 18 } // args; 9 19 in buildRustCrate p; 20 + 21 + mkCargoToml = 22 + { name, crateVersion ? "0.1.0", path ? "Cargo.toml" }: 23 + mkFile path '' 24 + [package] 25 + name = ${builtins.toJSON name} 26 + version = ${builtins.toJSON crateVersion} 27 + ''; 10 28 11 29 mkFile = destination: text: writeTextFile { 12 30 name = "src"; ··· 86 104 '' 87 105 ); 88 106 107 + /* Returns a derivation that asserts that the crate specified by `crateArgs` 108 + has the specified files as output. 109 + 110 + `name` is used as part of the derivation name that performs the checking. 111 + 112 + `crateArgs` is passed to `mkCrate` to build the crate with `buildRustCrate`. 113 + 114 + `expectedFiles` contains a list of expected file paths in the output. E.g. 115 + `[ "./bin/my_binary" ]`. 116 + 117 + `output` specifies the name of the output to use. By default, the default 118 + output is used but e.g. `output = "lib";` will cause the lib output 119 + to be checked instead. You do not need to specify any directories. 120 + */ 121 + assertOutputs = { name, crateArgs, expectedFiles, output? null }: 122 + assert (builtins.isString name); 123 + assert (builtins.isAttrs crateArgs); 124 + assert (builtins.isList expectedFiles); 125 + 126 + let 127 + crate = mkCrate (builtins.removeAttrs crateArgs ["expectedTestOutput"]); 128 + crateOutput = if output == null then crate else crate."${output}"; 129 + expectedFilesFile = writeTextFile { 130 + name = "expected-files-${name}"; 131 + text = 132 + let sorted = builtins.sort (a: b: a<b) expectedFiles; 133 + concatenated = builtins.concatStringsSep "\n" sorted; 134 + in "${concatenated}\n"; 135 + }; 136 + in 137 + runCommand "assert-outputs-${name}" { 138 + } '' 139 + local actualFiles=$(mktemp) 140 + 141 + cd "${crateOutput}" 142 + find . -type f | sort >$actualFiles 143 + diff -q ${expectedFilesFile} $actualFiles >/dev/null || { 144 + echo -e "\033[0;1;31mERROR: Difference in expected output files in ${crateOutput} \033[0m" >&2 145 + echo === Got: 146 + sed -e 's/^/ /' $actualFiles 147 + echo === Expected: 148 + sed -e 's/^/ /' ${expectedFilesFile} 149 + echo === Diff: 150 + diff -u ${expectedFilesFile} $actualFiles |\ 151 + tail -n +3 |\ 152 + sed -e 's/^/ /' 153 + exit 1 154 + } 155 + touch $out 156 + '' 157 + ; 158 + 89 159 in rec { 90 160 91 161 tests = let 92 - cases = { 162 + cases = rec { 93 163 libPath = { libPath = "src/my_lib.rs"; src = mkLib "src/my_lib.rs"; }; 94 164 srcLib = { src = mkLib "src/lib.rs"; }; 95 165 ··· 199 269 }) 200 270 ]; 201 271 }; 272 + buildScriptDeps = let 273 + depCrate = boolVal: mkCrate { 274 + crateName = "bar"; 275 + src = mkFile "src/lib.rs" '' 276 + pub const baz: bool = ${boolVal}; 277 + ''; 278 + }; 279 + in { 280 + crateName = "foo"; 281 + src = symlinkJoin { 282 + name = "build-script-and-main"; 283 + paths = [ 284 + (mkFile "src/main.rs" '' 285 + extern crate bar; 286 + #[cfg(test)] 287 + #[test] 288 + fn baz_false() { assert!(!bar::baz); } 289 + fn main() { } 290 + '') 291 + (mkFile "build.rs" '' 292 + extern crate bar; 293 + fn main() { assert!(bar::baz); } 294 + '') 295 + ]; 296 + }; 297 + buildDependencies = [ (depCrate "true") ]; 298 + dependencies = [ (depCrate "false") ]; 299 + buildTests = true; 300 + expectedTestOutputs = [ "test baz_false ... ok" ]; 301 + }; 202 302 # Regression test for https://github.com/NixOS/nixpkgs/issues/74071 203 303 # Whenevever a build.rs file is generating files those should not be overlayed onto the actual source dir 204 304 buildRsOutDirOverlay = { ··· 220 320 ]; 221 321 }; 222 322 }; 323 + # Regression test for https://github.com/NixOS/nixpkgs/pull/83379 324 + # link flag order should be preserved 325 + linkOrder = { 326 + src = symlinkJoin { 327 + name = "buildrs-out-dir-overlay"; 328 + paths = [ 329 + (mkFile "build.rs" '' 330 + fn main() { 331 + // in the other order, linkage will fail 332 + println!("cargo:rustc-link-lib=b"); 333 + println!("cargo:rustc-link-lib=a"); 334 + } 335 + '') 336 + (mkFile "src/main.rs" '' 337 + extern "C" { 338 + fn hello_world(); 339 + } 340 + fn main() { 341 + unsafe { 342 + hello_world(); 343 + } 344 + } 345 + '') 346 + ]; 347 + }; 348 + buildInputs = let 349 + compile = name: text: let 350 + src = writeTextFile { 351 + name = "${name}-src.c"; 352 + inherit text; 353 + }; 354 + in runCommandCC name {} '' 355 + mkdir -p $out/lib 356 + # Note: On darwin (which defaults to clang) we have to add 357 + # `-undefined dynamic_lookup` as otherwise the compilation fails. 358 + cc -shared \ 359 + ${lib.optionalString stdenv.isDarwin "-undefined dynamic_lookup"} \ 360 + -o $out/lib/${name}${stdenv.hostPlatform.extensions.sharedLibrary} ${src} 361 + ''; 362 + b = compile "libb" '' 363 + #include <stdio.h> 364 + 365 + void hello(); 366 + 367 + void hello_world() { 368 + hello(); 369 + printf(" world!\n"); 370 + } 371 + ''; 372 + a = compile "liba" '' 373 + #include <stdio.h> 374 + 375 + void hello() { 376 + printf("hello"); 377 + } 378 + ''; 379 + in [ a b ]; 380 + }; 381 + rustCargoTomlInSubDir = { 382 + # The "workspace_member" can be set to the sub directory with the crate to build. 383 + # By default ".", meaning the top level directory is assumed. 384 + # Using null will trigger a search. 385 + workspace_member = null; 386 + src = symlinkJoin rec { 387 + name = "find-cargo-toml"; 388 + paths = [ 389 + (mkCargoToml { name = "ignoreMe"; }) 390 + (mkTestFileWithMain "src/main.rs" "ignore_main") 391 + 392 + (mkCargoToml { name = "rustCargoTomlInSubDir"; path = "subdir/Cargo.toml"; }) 393 + (mkTestFileWithMain "subdir/src/main.rs" "src_main") 394 + (mkTestFile "subdir/tests/foo/main.rs" "tests_foo") 395 + (mkTestFile "subdir/tests/bar/main.rs" "tests_bar") 396 + ]; 397 + }; 398 + buildTests = true; 399 + expectedTestOutputs = [ 400 + "test src_main ... ok" 401 + "test tests_foo ... ok" 402 + "test tests_bar ... ok" 403 + ]; 404 + }; 405 + 406 + rustCargoTomlInTopDir = 407 + let 408 + withoutCargoTomlSearch = builtins.removeAttrs rustCargoTomlInSubDir [ "workspace_member" ]; 409 + in 410 + withoutCargoTomlSearch // { 411 + expectedTestOutputs = [ 412 + "test ignore_main ... ok" 413 + ]; 414 + }; 223 415 }; 224 416 brotliCrates = (callPackage ./brotli-crates.nix {}); 225 - in lib.mapAttrs (key: value: mkTest (value // lib.optionalAttrs (!value?crateName) { crateName = key; })) cases // { 417 + tests = lib.mapAttrs (key: value: mkTest (value // lib.optionalAttrs (!value?crateName) { crateName = key; })) cases; 418 + in tests // rec { 419 + 420 + crateBinWithPathOutputs = assertOutputs { 421 + name="crateBinWithPath"; 422 + crateArgs = { 423 + crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }]; 424 + src = mkBin "src/foobar.rs"; 425 + }; 426 + expectedFiles = [ 427 + "./bin/test_binary1" 428 + ]; 429 + }; 430 + 431 + crateBinWithPathOutputsDebug = assertOutputs { 432 + name="crateBinWithPath"; 433 + crateArgs = { 434 + release = false; 435 + crateBin = [{ name = "test_binary1"; path = "src/foobar.rs"; }]; 436 + src = mkBin "src/foobar.rs"; 437 + }; 438 + expectedFiles = [ 439 + "./bin/test_binary1" 440 + ] ++ lib.optionals stdenv.isDarwin [ 441 + # On Darwin, the debug symbols are in a seperate directory. 442 + "./bin/test_binary1.dSYM/Contents/Info.plist" 443 + "./bin/test_binary1.dSYM/Contents/Resources/DWARF/test_binary1" 444 + ]; 445 + }; 446 + 447 + crateBinNoPath1Outputs = assertOutputs { 448 + name="crateBinNoPath1"; 449 + crateArgs = { 450 + crateBin = [{ name = "my-binary2"; }]; 451 + src = mkBin "src/my_binary2.rs"; 452 + }; 453 + expectedFiles = [ 454 + "./bin/my-binary2" 455 + ]; 456 + }; 457 + 458 + crateLibOutputs = assertOutputs { 459 + name="crateLib"; 460 + output="lib"; 461 + crateArgs = { 462 + libName = "test_lib"; 463 + type = [ "rlib" ]; 464 + libPath = "src/lib.rs"; 465 + src = mkLib "src/lib.rs"; 466 + }; 467 + expectedFiles = [ 468 + "./nix-support/propagated-build-inputs" 469 + "./lib/libtest_lib-042a1fdbef.rlib" 470 + "./lib/link" 471 + ]; 472 + }; 473 + 474 + crateLibOutputsDebug = assertOutputs { 475 + name="crateLib"; 476 + output="lib"; 477 + crateArgs = { 478 + release = false; 479 + libName = "test_lib"; 480 + type = [ "rlib" ]; 481 + libPath = "src/lib.rs"; 482 + src = mkLib "src/lib.rs"; 483 + }; 484 + expectedFiles = [ 485 + "./nix-support/propagated-build-inputs" 486 + "./lib/libtest_lib-042a1fdbef.rlib" 487 + "./lib/link" 488 + ]; 489 + }; 490 + 226 491 brotliTest = let 227 492 pkg = brotliCrates.brotli_2_5_0 {}; 228 493 in runCommand "run-brotli-test-cmd" {