Created
December 1, 2017 17:38
-
-
Save boxofrox/7285293d9a552dbf98c421f41838e7ea to your computer and use it in GitHub Desktop.
Example result for extracting shell code from rust-utils.nix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Code for buildRustCrate, a Nix function that builds Rust code, just | |
# like Cargo, but using Nix instead. | |
# | |
# This can be useful for deploying packages with NixOps, and to share | |
# binary dependencies between projects. | |
{ lib, buildPlatform, stdenv, defaultCrateOverrides, fetchCrate, ncurses, rustc }: | |
let buildCrate = { crateName, crateVersion, crateAuthors, buildDependencies, | |
dependencies, completeDeps, completeBuildDeps, | |
crateFeatures, libName, build, release, libPath, | |
crateType, metadata, crateBin, finalBins, | |
verbose, colors }: | |
let depsDir = lib.concatStringsSep " " dependencies; | |
completeDepsDir = lib.concatStringsSep " " completeDeps; | |
completeBuildDepsDir = lib.concatStringsSep " " completeBuildDeps; | |
makeDeps = dependencies: | |
(lib.concatMapStringsSep " " (dep: | |
let extern = lib.strings.replaceStrings ["-"] ["_"] dep.libName; in | |
(if dep.crateType == "lib" then | |
" --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}.rlib" | |
else | |
" --extern ${extern}=${dep.out}/lib/lib${extern}-${dep.metadata}${buildPlatform.extensions.sharedLibrary}") | |
) dependencies); | |
deps = makeDeps dependencies; | |
buildDeps = makeDeps buildDependencies; | |
optLevel = if release then 3 else 0; | |
rustcOpts = (if release then "-C opt-level=3" else "-C debuginfo=2"); | |
rustcMeta = "-C metadata=${metadata} -C extra-filename=-${metadata}"; | |
version_ = lib.splitString "-" crateVersion; | |
versionPre = if lib.tail version_ == [] then "" else builtins.elemAt version_ 1; | |
version = lib.splitString "." (lib.head version_); | |
authors = lib.concatStringsSep ":" crateAuthors; | |
in '' | |
COLORS=${colors} | |
VERBOSE=${lib.optionalString verbose ""} | |
LIB_NAME=${libName} | |
LIB_PATH=${libPath} | |
CRATE_BIN=${crateBin} | |
CRATE_NAME=${crateName} | |
CRATE_VERSION=${crateVersion} | |
CRATE_AUTHORS=${authors} | |
CRATE_TYPE=${crateType} | |
CRATE_FEATURES=${crateFeatures} | |
METADATA=${metadata} | |
RUSTC_OPTS=${rustcOpts} | |
RUSTC_META=${rustcMeta} | |
DEPS=${deps} | |
BUILD_DEPS=${buildDeps} | |
SHAREDLIB_EXT=${buildPlatform.extensions.sharedLibrary} | |
COMPLETE_DEPS_DIR=${completeDepsDir} | |
COMPLETE_BUILD_DEPS_DIR=${completeBuildDepsDir} | |
export CARGO_PKG_NAME=${crateName} | |
export CARGO_PKG_VERSION=${crateVersion} | |
export CARGO_PKG_AUTHORS="${authors}" | |
export CARGO_CFG_TARGET_ARCH=${buildPlatform.parsed.cpu.name} | |
export CARGO_CFG_TARGET_OS=${buildPlatform.parsed.kernel.name} | |
export CARGO_CFG_TARGET_ENV="gnu" | |
export CARGO_MANIFEST_DIR="." | |
export DEBUG="${toString (!release)}" | |
export OPT_LEVEL="${toString optLevel}" | |
export TARGET="${buildPlatform.config}" | |
export HOST="${buildPlatform.config}" | |
export PROFILE=${if release then "release" else "debug"} | |
export OUT_DIR=$(pwd)/target/build/${crateName}.out | |
export CARGO_PKG_VERSION_MAJOR=${builtins.elemAt version 0} | |
export CARGO_PKG_VERSION_MINOR=${builtins.elemAt version 1} | |
export CARGO_PKG_VERSION_PATCH=${builtins.elemAt version 2} | |
export CARGO_PKG_VERSION_PRE="${versionPre}" | |
source ${./scripts/buildPhase.sh} | |
start_build "${build}" | |
'' + finalBins; | |
installCrate = crateName: '' | |
mkdir -p $out | |
if [ -s target/env ]; then | |
cp target/env $out/env | |
fi | |
if [ -s target/link.final ]; then | |
mkdir -p $out/lib | |
cp target/link.final $out/lib/link | |
fi | |
if [ "$(ls -A target/lib)" ]; then | |
mkdir -p $out/lib | |
cp target/lib/* $out/lib #*/ | |
fi | |
if [ "$(ls -A target/build)" ]; then # */ | |
mkdir -p $out/lib | |
cp -r target/build/* $out/lib # */ | |
fi | |
if [ "$(ls -A target/bin)" ]; then | |
mkdir -p $out/bin | |
cp -P target/bin/* $out/bin # */ | |
fi | |
''; | |
in | |
crate_: lib.makeOverridable ({ rust, release, verbose, crateOverrides }: | |
let crate = crate_ // (lib.attrByPath [ crate_.crateName ] (attr: {}) crateOverrides crate_); in | |
stdenv.mkDerivation rec { | |
inherit (crate) crateName; | |
src = if lib.hasAttr "src" crate then | |
crate.src | |
else | |
fetchCrate { inherit (crate) crateName version sha256; }; | |
name = "rust_${crate.crateName}-${crate.version}"; | |
buildInputs = [ rust ncurses ] ++ (crate.buildInputs or []); | |
dependencies = | |
builtins.map | |
(dep: dep.override { rust = rust; release = release; verbose = verbose; crateOverrides = crateOverrides; }) | |
(crate.dependencies or []); | |
buildDependencies = | |
builtins.map | |
(dep: dep.override { rust = rust; release = release; verbose = verbose; crateOverrides = crateOverrides; }) | |
(crate.buildDependencies or []); | |
completeDeps = lib.lists.unique (dependencies ++ lib.lists.concatMap (dep: dep.completeDeps) dependencies); | |
completeBuildDeps = lib.lists.unique ( | |
buildDependencies | |
++ lib.lists.concatMap (dep: dep.completeBuildDeps ++ dep.completeDeps) buildDependencies | |
); | |
crateFeatures = if crate ? features then | |
lib.concatMapStringsSep " " (f: "--cfg feature=\\\"${f}\\\"") crate.features | |
else ""; | |
libName = if crate ? libName then crate.libName else crate.crateName; | |
libPath = if crate ? libPath then crate.libPath else ""; | |
metadata = builtins.substring 0 10 (builtins.hashString "sha256" (crateName + "-" + crateVersion)); | |
crateBin = if crate ? crateBin then | |
builtins.foldl' (bins: bin: | |
let name = | |
lib.strings.replaceStrings ["-"] ["_"] | |
(if bin ? name then bin.name else crateName); | |
path = if bin ? path then bin.path else "src/main.rs"; | |
in | |
bins + (if bin == "" then "" else ",") + "${name} ${path}" | |
) "" crate.crateBin | |
else ""; | |
finalBins = if crate ? crateBin then | |
builtins.foldl' (bins: bin: | |
let name = lib.strings.replaceStrings ["-"] ["_"] | |
(if bin ? name then bin.name else crateName); | |
new_name = if bin ? name then bin.name else crateName; | |
in | |
if name == new_name then bins else | |
(bins + "mv target/bin/${name} target/bin/${new_name};") | |
) "" crate.crateBin | |
else ""; | |
build = if crate ? build then crate.build else ""; | |
crateVersion = crate.version; | |
crateAuthors = if crate ? authors && lib.isList crate.authors then crate.authors else []; | |
crateType = | |
if lib.attrByPath ["procMacro"] false crate then "proc-macro" else | |
if lib.attrByPath ["plugin"] false crate then "dylib" else "lib"; | |
colors = lib.attrByPath [ "colors" ] "always" crate; | |
buildPhase = buildCrate { | |
inherit crateName dependencies buildDependencies completeDeps completeBuildDeps | |
crateFeatures libName build release libPath crateType crateVersion | |
crateAuthors metadata crateBin finalBins verbose colors; | |
}; | |
installPhase = installCrate crateName; | |
}) { | |
rust = rustc; | |
release = true; | |
verbose = true; | |
crateOverrides = defaultCrateOverrides; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# external environment variables as arguments | |
# | |
# COLORS=${colors} | |
# VERBOSE=${lib.optionalString verbose ""} | |
# LIB_NAME=${libName} | |
# LIB_PATH=${libPath} | |
# | |
# CRATE_BIN=${crateBin} | |
# CRATE_NAME=${crateName} | |
# CRATE_VERSION=${crateVersion} | |
# CRATE_AUTHORS=${authors} | |
# CRATE_TYPE=${crateType} | |
# CRATE_FEATURES=${crateFeatures} | |
# METADATA=${metadata} | |
# | |
# RUSTC_OPTS=${rustcOpts} | |
# RUSTC_META=${rustcMeta} | |
# | |
# DEPS=${deps} | |
# BUILD_DEPS=${buildDeps} | |
# | |
# SHAREDLIB_EXT=${buildPlatform.extensions.sharedLibrary} | |
# COMPLETE_DEPS_DIR=${completeDepsDir} | |
# COMPLETE_BUILD_DEPS_DIR=${completeBuildDepsDir} | |
norm="" | |
bold="" | |
green="" | |
boldgreen="" | |
if [[ "$COLORS" -eq "always" ]]; then | |
norm="$(printf '\033[0m')" #returns to "normal" | |
bold="$(printf '\033[0;1m')" #set bold | |
green="$(printf '\033[0;32m')" #set green | |
boldgreen="$(printf '\033[0;1;32m')" #set bold, and set green. | |
fi | |
echo_build_heading() { | |
local start="" | |
local end="" | |
if [[ x"$COLORS" -eq x"always" ]]; then | |
start="$(printf '\033[0;1;32m')" #set bold, and set green. | |
end="$(printf '\033[0m')" #returns to "normal" | |
fi | |
if (( $# == 1 )); then | |
echo "$start""Building $1""$end" | |
else | |
echo "$start""Building $1 ($2)""$end" | |
fi | |
} | |
noisily() { | |
local start="" | |
local end="" | |
if [[ x"$COLORS" -eq x"always" ]]; then | |
start="$(printf '\033[0;1;32m')" #set bold, and set green. | |
end="$(printf '\033[0m')" #returns to "normal" | |
fi | |
if [[ -n "$VERBOSE" ]]; then | |
echo -n "$start"Running "$end" | |
echo $@ | |
fi | |
"$@" | |
} | |
symlink_dependency() { | |
# $1 is the nix-store path of a dependency | |
local i=$1 | |
local dest=target/deps | |
if [[ "$2" = "--buildDep" ]]; then | |
dest=target/buildDeps | |
fi | |
ln -s -f $i/lib/*.rlib $dest #*/ | |
ln -s -f $i/lib/*.so $i/lib/*.dylib $dest #*/ | |
if [[ -e "$i/lib/link" ]]; then | |
cat $i/lib/link >> target/link | |
cat $i/lib/link >> target/link.final | |
fi | |
if [[ -e $i/env ]]; then | |
source $i/env | |
fi | |
} | |
build_lib() { | |
local lib_name=$1 lib_src=$2 | |
echo_build_heading $lib_src "$lib_name" | |
noisily rustc --crate-name $CRATE_NAME $lib_src --crate-type $CRATE_TYPE \ | |
$RUSTC_OPTS $RUSTC_META $CRATE_FEATURES --out-dir target/lib \ | |
--emit=dep-info,link -L dependency=target/deps $DEPS --cap-lints allow \ | |
$BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color $COLORS | |
EXTRA_LIB=" --extern $CRATE_NAME=target/lib/lib${CRATE_NAME}-${METADATA}.rlib" | |
if [[ -e target/deps/lib${CRATE_NAME}-${METADATA}${SHAREDLIB_EXT} ]]; then | |
EXTRA_LIB="$EXTRA_LIB --extern $CRATE_NAME=target/lib/lib${CRATE_NAME}-${METADATA}${SHAREDLIB_EXT}" | |
fi | |
} | |
build_bin() { | |
local crate_name=$1 | |
local crate_name_=$(echo $crate_name | sed -e "s/-/_/g") | |
local main_file="$2" | |
echo_build_heading $@ | |
noisily rustc --crate-name $crate_name_ $main_file --crate-type bin $RUSTC_OPTS \ | |
$CRATE_FEATURES --out-dir target/bin --emit=dep-info,link -L dependency=target/deps \ | |
$LINK ${DEPS}$EXTRA_LIB --cap-lints allow \ | |
$BUILD_OUT_DIR $EXTRA_BUILD $EXTRA_FEATURES --color $COLORS | |
if [[ "$crate_name_" -ne "$crate_name" ]]; then | |
mv target/bin/$crate_name_ target/bin/$crate_name | |
fi | |
} | |
start_build() { | |
local BUILD="$1" | |
runHook preBuild | |
mkdir -p target/{deps,lib,build,buildDeps} | |
chmod uga+w target -R | |
for i in $COMPLETE_DEPS_DIR; do | |
symlink_dependency $i | |
done | |
for i in $COMPLETE_BUILD_DEPS_DIR; do | |
symlink_dependency $i --buildDep | |
done | |
if [[ -e target/link ]]; then | |
sort -u target/link > target/link.sorted | |
mv target/link.sorted target/link | |
sort -u target/link.final > target/link.final.sorted | |
mv target/link.final.sorted target/link.final | |
tr '\n' ' ' < target/link > target/link_ | |
fi | |
# clear global vars | |
EXTRA_BUILD="" # updated by build_lib | |
BUILD_OUT_DIR="" # used by build_{lib,bin} | |
if [[ -z "$BUILD" && -e "build.rs" ]]; then | |
BUILD="build.rs" | |
fi | |
if [[ -n "$BUILD" ]] ; then | |
echo_build_heading "$BUILD" "$LIB_NAME" | |
mkdir -p target/build/$CRATE_NAME | |
local EXTRA_BUILD_FLAGS="" | |
if [[ -e target/link_ ]]; then | |
EXTRA_BUILD_FLAGS=$(cat target/link_) | |
fi | |
if [[ -e target/link.build ]]; then | |
EXTRA_BUILD_FLAGS="$EXTRA_BUILD_FLAGS $(cat target/link.build)" | |
fi | |
noisily rustc --crate-name build_script_build $BUILD --crate-type bin $RUSTC_OPTS \ | |
$CRATE_FEATURES --out-dir target/build/$CRATE_NAME --emit=dep-info,link \ | |
-L dependency=target/buildDeps $BUILD_DEPS --cap-lints allow $EXTRA_BUILD_FLAGS --color $COLORS | |
mkdir -p target/build/$CRATE_NAME.out | |
export RUST_BACKTRACE=1 | |
BUILD_OUT_DIR="-L $OUT_DIR" | |
mkdir -p $OUT_DIR | |
target/build/$CRATE_NAME/build_script_build > target/build/$CRATE_NAME.opt | |
set +e | |
EXTRA_BUILD=$(sed -n "s/^cargo:rustc-flags=\(.*\)/\1/p" target/build/$CRATE_NAME.opt | tr '\n' ' ') | |
EXTRA_FEATURES=$(sed -n "s/^cargo:rustc-cfg=\(.*\)/--cfg \1/p" target/build/$CRATE_NAME.opt | tr '\n' ' ') | |
EXTRA_LINK=$(sed -n "s/^cargo:rustc-link-lib=\(.*\)/\1/p" target/build/$CRATE_NAME.opt | tr '\n' ' ') | |
EXTRA_LINK_SEARCH=$(sed -n "s/^cargo:rustc-link-search=\(.*\)/\1/p" target/build/$CRATE_NAME.opt | tr '\n' ' ') | |
BASE_CRATE_NAME=$(echo $CRATE_NAME | sed -e "s/\(.*\)-sys$/\U\1/") | |
grep -P "^cargo:(?!(rustc-|warning=|rerun-if-changed=|rerun-if-env-changed))" target/build/$CRATE_NAME.opt \ | |
| sed -e "s/cargo:\([^=]*\)=\(.*\)/export DEP_${BASE_CRATE_NAME}_\U\1\E=\2/" > target/env | |
set -e | |
if [[ -n "$(ls target/build/$CRATE_NAME.out)" ]]; then | |
if [[ -e "$LIB_PATH" ]] ; then | |
cp -r target/build/$CRATE_NAME.out/* $(dirname "$LIB_PATH") #*/ | |
else | |
cp -r target/build/$CRATE_NAME.out/* src #*/ | |
fi | |
fi | |
fi | |
EXTRA_LIB="" | |
PROPER_CRATE_NAME=$(echo $LIB_NAME | sed -e "s/-/_/g") | |
if [[ -e target/link_ ]]; then | |
EXTRA_BUILD="$(cat target/link_) $EXTRA_BUILD" | |
fi | |
if [[ -e "$LIB_PATH" ]] ; then | |
build_lib $LIB_NAME "$LIB_PATH" | |
elif [ -e src/lib.rs ] ; then | |
build_lib $LIB_NAME src/lib.rs | |
elif [ -e src/$LIB_NAME.rs ] ; then | |
build_lib $LIB_NAME src/$LIB_NAME.rs | |
fi | |
echo "$EXTRA_LINK_SEARCH" | while read i; do | |
if [[ -n "$i" ]]; then | |
for lib in $i; do | |
echo "-L $lib" >> target/link | |
L=$(echo $lib | sed -e "s#$(pwd)/target/build#$out/lib#") | |
echo "-L $L" >> target/link.final | |
done | |
fi | |
done | |
echo "$EXTRA_LINK" | while read i; do | |
if [[ -n "$i" ]]; then | |
for lib in $i; do | |
echo "-l $lib" >> target/link | |
echo "-l $lib" >> target/link.final | |
done | |
fi | |
done | |
if [[ -e target/link ]]; then | |
sort -u target/link.final > target/link.final.sorted | |
mv target/link.final.sorted target/link.final | |
sort -u target/link > target/link.sorted | |
mv target/link.sorted target/link | |
tr '\n' ' ' < target/link > target/link_ | |
LINK=$(cat target/link_) | |
fi | |
mkdir -p target/bin | |
echo "$CRATE_BIN" | sed -n 1'p' | tr ',' '\n' | while read BIN; do | |
if [[ ! -z "$BIN" ]]; then | |
build_bin $BIN | |
fi | |
done | |
if [[ (-z "$CRATE_BIN") && (-e src/main.rs) ]]; then | |
build_bin $PROPER_CRATE_NAME src/main.rs | |
fi | |
# Remove object files to avoid "wrong ELF type" | |
find target -type f -name "*.o" -print0 | xargs -0 rm -f | |
runHook postBuild | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment