nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{
2 lib,
3 stdenv,
4 echo_colored,
5 noisily,
6 mkRustcDepArgs,
7 mkRustcFeatureArgs,
8}:
9{
10 build,
11 buildDependencies,
12 codegenUnits,
13 colors,
14 completeBuildDeps,
15 completeDeps,
16 crateAuthors,
17 crateDescription,
18 crateFeatures,
19 crateHomepage,
20 crateLicense,
21 crateLicenseFile,
22 crateLinks,
23 crateName,
24 crateType,
25 crateReadme,
26 crateRenames,
27 crateRepository,
28 crateRustVersion,
29 crateVersion,
30 extraLinkFlags,
31 extraRustcOptsForBuildRs,
32 libName,
33 libPath,
34 release,
35 verbose,
36 workspace_member,
37}:
38let
39 version_ = lib.splitString "-" crateVersion;
40 versionPre = lib.optionalString (lib.tail version_ != [ ]) (lib.elemAt version_ 1);
41 version = lib.splitVersion (lib.head version_);
42 rustcOpts = lib.foldl' (opts: opt: opts + " " + opt) (
43 if release then "-C opt-level=3" else "-C debuginfo=2"
44 ) ([ "-C codegen-units=${toString codegenUnits}" ] ++ extraRustcOptsForBuildRs);
45 buildDeps = mkRustcDepArgs buildDependencies crateRenames;
46 authors = lib.concatStringsSep ":" crateAuthors;
47 optLevel = if release then 3 else 0;
48 completeDepsDir = lib.concatStringsSep " " completeDeps;
49 completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps;
50 envFeatures = lib.concatStringsSep " " (
51 map (f: lib.replaceStrings [ "-" ] [ "_" ] (lib.toUpper f)) crateFeatures
52 );
53in
54''
55 ${echo_colored colors}
56 ${noisily colors verbose}
57 source ${./lib.sh}
58
59 ${lib.optionalString (workspace_member != null) ''
60 noisily cd "${workspace_member}"
61 ''}
62 ${lib.optionalString (workspace_member == null) ''
63 echo_colored "Searching for matching Cargo.toml (${crateName})"
64 local cargo_toml_dir=$(matching_cargo_toml_dir "${crateName}")
65 if [ -z "$cargo_toml_dir" ]; then
66 echo_error "ERROR configuring ${crateName}: No matching Cargo.toml in $(pwd) found." >&2
67 exit 23
68 fi
69 noisily cd "$cargo_toml_dir"
70 ''}
71
72 runHook preConfigure
73
74 symlink_dependency() {
75 # $1 is the nix-store path of a dependency
76 # $2 is the target path
77 i=$1
78 ln -s -f $i/lib/*.rlib $2 #*/
79 ln -s -f $i/lib/*.so $i/lib/*.dylib $2 #*/
80 if [ -e $i/env ]; then
81 source $i/env
82 fi
83 }
84
85 # The following steps set up the dependencies of the crate. Two
86 # kinds of dependencies are distinguished: build dependencies
87 # (used by the build script) and crate dependencies. For each
88 # dependency we have to:
89 #
90 # - Make its Rust library available to rustc. This is done by
91 # symlinking all library dependencies into a directory that
92 # can be provided to rustc.
93 # - Accumulate linking flags. These flags are largely used for
94 # linking native libraries.
95 #
96 # The crate link flags are added to the `link` and `link.final`
97 # files. The `link` file is used for linkage in the current
98 # crate. The `link.final` file will be copied to the output and can
99 # be used by downstream crates to get the linker flags of this
100 # crate.
101
102 mkdir -p target/{deps,lib,build,buildDeps}
103 chmod uga+w target -R
104 echo ${extraLinkFlags} > target/link
105 echo ${extraLinkFlags} > target/link.final
106
107 # Prepare crate dependencies
108 for i in ${completeDepsDir}; do
109 symlink_dependency $i target/deps
110 if [ -e "$i/lib/link" ]; then
111 cat $i/lib/link >> target/link
112 cat $i/lib/link >> target/link.final
113 fi
114 done
115
116 # Prepare crate build dependencies that are used for the build script.
117 for i in ${completeBuildDepsDir}; do
118 symlink_dependency $i target/buildDeps
119 if [ -e "$i/lib/link" ]; then
120 cat $i/lib/link >> target/link.build
121 fi
122 done
123
124 # Remove duplicate linker flags from the build dependencies.
125 if [[ -e target/link.build ]]; then
126 sort -uo target/link.build target/link.build
127 fi
128
129 # Remove duplicate linker flags from the dependencies.
130 sort -uo target/link target/link
131 tr '\n' ' ' < target/link > target/link_
132
133 # Remove duplicate linker flags from the that are written
134 # to the derivation's output.
135 sort -uo target/link.final target/link.final
136
137 EXTRA_BUILD=""
138 BUILD_OUT_DIR=""
139
140 # Set up Cargo Environment variables: https://doc.rust-lang.org/cargo/reference/environment-variables.html
141 export CARGO_PKG_NAME=${crateName}
142 export CARGO_PKG_VERSION=${crateVersion}
143 export CARGO_PKG_AUTHORS="${authors}"
144 export CARGO_PKG_DESCRIPTION="${crateDescription}"
145
146 export CARGO_CFG_TARGET_ARCH=${stdenv.hostPlatform.rust.platform.arch}
147 export CARGO_CFG_TARGET_OS=${stdenv.hostPlatform.rust.platform.os}
148 export CARGO_CFG_TARGET_FAMILY="unix"
149 export CARGO_CFG_UNIX=1
150 export CARGO_CFG_TARGET_ENV="gnu"
151 export CARGO_CFG_TARGET_ENDIAN=${
152 if stdenv.hostPlatform.parsed.cpu.significantByte.name == "littleEndian" then "little" else "big"
153 }
154 export CARGO_CFG_TARGET_POINTER_WIDTH=${
155 with stdenv.hostPlatform; toString (if isILP32 then 32 else parsed.cpu.bits)
156 }
157 export CARGO_CFG_TARGET_VENDOR=${stdenv.hostPlatform.parsed.vendor.name}
158
159 export CARGO_MANIFEST_DIR=$(pwd)
160 export CARGO_MANIFEST_LINKS=${crateLinks}
161 export DEBUG="${toString (!release)}"
162 export OPT_LEVEL="${toString optLevel}"
163 export TARGET="${stdenv.hostPlatform.rust.rustcTargetSpec}"
164 export HOST="${stdenv.buildPlatform.rust.rustcTargetSpec}"
165 export PROFILE=${if release then "release" else "debug"}
166 export OUT_DIR=$(pwd)/target/build/${crateName}.out
167 export CARGO_PKG_VERSION_MAJOR=${lib.elemAt version 0}
168 export CARGO_PKG_VERSION_MINOR=${lib.elemAt version 1}
169 export CARGO_PKG_VERSION_PATCH=${lib.elemAt version 2}
170 export CARGO_PKG_VERSION_PRE="${versionPre}"
171 export CARGO_PKG_HOMEPAGE="${crateHomepage}"
172 export CARGO_PKG_LICENSE="${crateLicense}"
173 export CARGO_PKG_LICENSE_FILE="${crateLicenseFile}"
174 export CARGO_PKG_README="${crateReadme}"
175 export CARGO_PKG_REPOSITORY="${crateRepository}"
176 export CARGO_PKG_RUST_VERSION="${crateRustVersion}"
177 export NUM_JOBS=$NIX_BUILD_CORES
178 export RUSTC="rustc"
179 export RUSTDOC="rustdoc"
180
181 BUILD=""
182 if [[ ! -z "${build}" ]] ; then
183 BUILD=${build}
184 elif [[ -e "build.rs" ]]; then
185 BUILD="build.rs"
186 fi
187
188 # Compile and run the build script, when available.
189 if [[ ! -z "$BUILD" ]] ; then
190 echo_build_heading "$BUILD" ${libName}
191 mkdir -p target/build/${crateName}
192 EXTRA_BUILD_FLAGS=""
193 if [ -e target/link.build ]; then
194 EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(tr '\n' ' ' < target/link.build)"
195 fi
196 noisily rustc --crate-name build_script_build $BUILD --crate-type bin ${rustcOpts} \
197 ${mkRustcFeatureArgs crateFeatures} --out-dir target/build/${crateName} --emit=dep-info,link \
198 -L dependency=target/buildDeps ${buildDeps} --cap-lints allow $EXTRA_BUILD_FLAGS --color ${colors}
199
200 mkdir -p target/build/${crateName}.out
201 export RUST_BACKTRACE=1
202 BUILD_OUT_DIR="-L $OUT_DIR"
203 mkdir -p $OUT_DIR
204
205 (
206 # Features should be set as environment variable for build scripts:
207 # https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
208 for feature in ${envFeatures}; do
209 export CARGO_FEATURE_$feature=1
210 done
211
212 target/build/${crateName}/build_script_build | tee target/build/${crateName}.opt
213 )
214
215 set +e
216 # We want to support the new prefix invocation syntax which uses two colons
217 # See https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
218
219 EXTRA_BUILD=$(sed -n "s/^cargo::\{0,1\}rustc-flags=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u)
220 EXTRA_FEATURES=$(sed -n "s/^cargo::\{0,1\}rustc-cfg=\(.*\)/--cfg \1/p" target/build/${crateName}.opt | tr '\n' ' ')
221 EXTRA_LINK_ARGS=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
222 EXTRA_LINK_ARGS_BINS=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg-bins=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
223 EXTRA_LINK_ARGS_LIB=$(sed -n "s/^cargo::\{0,1\}rustc-link-arg-lib=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
224 EXTRA_LINK_LIBS=$(sed -n "s/^cargo::\{0,1\}rustc-link-lib=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ')
225 EXTRA_LINK_SEARCH=$(sed -n "s/^cargo::\{0,1\}rustc-link-search=\(.*\)/\1/p" target/build/${crateName}.opt | tr '\n' ' ' | sort -u)
226
227 ${lib.optionalString (lib.elem "cdylib" crateType) ''
228 CRATE_TYPE_IS_CDYLIB="true"
229 EXTRA_CDYLIB_LINK_ARGS=$(sed -n "s/^cargo::\{0,1\}rustc-cdylib-link-arg=\(.*\)/-C link-arg=\1/p" target/build/${crateName}.opt | tr '\n' ' ')
230 ''}
231
232 # We want to read part of every line that has cargo:rustc-env= prefix and
233 # export it as environment variables. This turns out tricky if the lines
234 # have spaces: we can't wrap the command in double quotes as that captures
235 # all the lines in single output. We can't use while read loop because
236 # exporting from inside of it doesn't make it to the outside scope. We
237 # can't use xargs as export is a built-in and does not work from it. As a
238 # last resort then, we change the IFS so that the for loop does not split
239 # on spaces and reset it after we are done. See ticket #199298.
240 #
241 _OLDIFS="$IFS"
242 IFS=$'\n'
243 for env in $(sed -n "s/^cargo::\{0,1\}rustc-env=\(.*\)/\1/p" target/build/${crateName}.opt); do
244 export "$env"
245 done
246 IFS="$_OLDIFS"
247
248 CRATENAME=$(echo ${crateName} | sed -e "s/\(.*\)-sys$/\U\1/" -e "s/-/_/g")
249 # SemVer allows version numbers to contain alphanumeric characters and `.+-`
250 # which aren't legal bash identifiers.
251 # https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions
252 CRATEVERSION=$(echo ${crateVersion} | sed -e "s/[\.\+-]/_/g")
253 grep -P "^cargo:(?!:?(rustc-|warning=|rerun-if-changed=|rerun-if-env-changed))" target/build/${crateName}.opt \
254 | awk -F= "/^cargo::metadata=/ { gsub(/-/, \"_\", \$2); print \"export \" toupper(\"DEP_$(echo $CRATENAME)_\" \$2) \"=\" \"\\\"\"\$3\"\\\"\"; next }
255 /^cargo:/ { sub(/^cargo::?/, \"\", \$1); gsub(/-/, \"_\", \$1); print \"export \" toupper(\"DEP_$(echo $CRATENAME)_\" \$1) \"=\" \"\\\"\"\$2\"\\\"\"; print \"export \" toupper(\"DEP_$(echo $CRATENAME)_$(echo $CRATEVERSION)_\" \$1) \"=\" \"\\\"\"\$2\"\\\"\"; next }" > target/env
256 set -e
257 fi
258 runHook postConfigure
259''