diff options
author | Tobias Bergkvist <tobias@bergkv.ist> | 2021-12-09 13:00:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-09 13:00:24 +0100 |
commit | df13841609b3247f18ce11478e974c3b241546e4 (patch) | |
tree | f34b66de95d68937c7a56d712138f14a6429c5cb /pkgs/build-support | |
parent | 177f0a6eedcf0b0ab74b845fd7cf77bde0997fbe (diff) | |
parent | 32d566e1b9d9ff55ec5b013d5420419649780e0d (diff) | |
download | nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar.gz nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar.bz2 nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar.lz nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar.xz nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.tar.zst nixpkgs-df13841609b3247f18ce11478e974c3b241546e4.zip |
Merge branch 'bergkvist/make-c-wrapper' into make-c-wrapper
Diffstat (limited to 'pkgs/build-support')
-rw-r--r-- | pkgs/build-support/setup-hooks/make-binary-wrapper.sh | 161 |
1 files changed, 120 insertions, 41 deletions
diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh index a0c8cf59501..2b6d316d81e 100644 --- a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh +++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh @@ -51,14 +51,14 @@ wrapProgram() { makeWrapper "$hidden" "$prog" --inherit-argv0 "${@:2}" } -# Generate source code for the wrapper in such a way that the wrapper source code +# Generate source code for the wrapper in such a way that the wrapper inputs # will still be readable even after compilation # makeDocumentedCWrapper EXECUTABLE ARGS # ARGS: same as makeWrapper makeDocumentedCWrapper() { local src docs src=$(makeCWrapper "$@") - docs=$(documentationString "$src") + docs=$(docstring "$@") printf '%s\n\n' "$src" printf '%s\n' "$docs" } @@ -66,7 +66,7 @@ makeDocumentedCWrapper() { # makeCWrapper EXECUTABLE ARGS # ARGS: same as makeWrapper makeCWrapper() { - local argv0 inherit_argv0 n params cmd main flagsBefore flags executable params length + local argv0 inherit_argv0 n params cmd main flagsBefore flags executable length local uses_prefix uses_suffix uses_assert uses_assert_success uses_stdio uses_asprintf executable=$(escapeStringLiteral "$1") params=("$@") @@ -76,82 +76,82 @@ makeCWrapper() { case $p in --set) cmd=$(setEnv "${params[n + 1]}" "${params[n + 2]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' n=$((n + 2)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n' ;; --set-default) cmd=$(setDefaultEnv "${params[n + 1]}" "${params[n + 2]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 2)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 2 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 2 arguments"$'\n' ;; --unset) cmd=$(unsetEnv "${params[n + 1]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --prefix) cmd=$(setEnvPrefix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_prefix=1 uses_asprintf=1 uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n' ;; --suffix) cmd=$(setEnvSuffix "${params[n + 1]}" "${params[n + 2]}" "${params[n + 3]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_suffix=1 uses_asprintf=1 uses_stdio=1 uses_assert_success=1 uses_assert=1 n=$((n + 3)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 3 arguments"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 3 arguments"$'\n' ;; --chdir) cmd=$(changeDir "${params[n + 1]}") - main="$main $cmd"$'\n' + main="$main$cmd"$'\n' uses_stdio=1 uses_assert_success=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --add-flags) flags="${params[n + 1]}" flagsBefore="$flagsBefore $flags" uses_assert=1 n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --argv0) argv0=$(escapeStringLiteral "${params[n + 1]}") inherit_argv0= n=$((n + 1)) - [ $n -ge "$length" ] && main="$main #error makeCWrapper: $p takes 1 argument"$'\n' + [ $n -ge "$length" ] && main="$main#error makeCWrapper: $p takes 1 argument"$'\n' ;; --inherit-argv0) # Whichever comes last of --argv0 and --inherit-argv0 wins inherit_argv0=1 ;; *) # Using an error macro, we will make sure the compiler gives an understandable error message - main="$main #error makeCWrapper: Unknown argument ${p}"$'\n' + main="$main#error makeCWrapper: Unknown argument ${p}"$'\n' ;; esac done # shellcheck disable=SC2086 [ -z "$flagsBefore" ] || main="$main"${main:+$'\n'}$(addFlags $flagsBefore)$'\n'$'\n' - [ -z "$inherit_argv0" ] && main="$main argv[0] = \"${argv0:-${executable}}\";"$'\n' - main="$main return execv(\"${executable}\", argv);"$'\n' + [ -z "$inherit_argv0" ] && main="${main}argv[0] = \"${argv0:-${executable}}\";"$'\n' + main="${main}return execv(\"${executable}\", argv);"$'\n' [ -z "$uses_asprintf" ] || printf '%s\n' "#define _GNU_SOURCE /* See feature_test_macros(7) */" printf '%s\n' "#include <unistd.h>" @@ -162,8 +162,8 @@ makeCWrapper() { [ -z "$uses_prefix" ] || printf '\n%s\n' "$(setEnvPrefixFn)" [ -z "$uses_suffix" ] || printf '\n%s\n' "$(setEnvSuffixFn)" printf '\n%s' "int main(int argc, char **argv) {" - printf '\n%s' "$main" - printf '%s\n' "}" + printf '\n%s' "$(indent4 "$main")" + printf '\n%s\n' "}" } addFlags() { @@ -172,17 +172,17 @@ addFlags() { flags=("$@") for ((n = 0; n < ${#flags[*]}; n += 1)); do flag=$(escapeStringLiteral "${flags[$n]}") - result="$result ${var}[$((n+1))] = \"$flag\";"$'\n' + result="$result${var}[$((n+1))] = \"$flag\";"$'\n' done - printf ' %s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));" - printf ' %s\n' "assert($var != NULL);" - printf ' %s\n' "${var}[0] = argv[0];" + printf '%s\n' "char **$var = calloc($((n+1)) + argc, sizeof(*$var));" + printf '%s\n' "assert($var != NULL);" + printf '%s\n' "${var}[0] = argv[0];" printf '%s' "$result" - printf ' %s\n' "for (int i = 1; i < argc; ++i) {" - printf ' %s\n' " ${var}[$n + i] = argv[i];" - printf ' %s\n' "}" - printf ' %s\n' "${var}[$n + argc] = NULL;" - printf ' %s\n' "argv = $var;" + printf '%s\n' "for (int i = 1; i < argc; ++i) {" + printf '%s\n' " ${var}[$n + i] = argv[i];" + printf '%s\n' "}" + printf '%s\n' "${var}[$n + argc] = NULL;" + printf '%s\n' "argv = $var;" } # chdir DIR @@ -238,14 +238,6 @@ unsetEnv() { assertValidEnvName "$1" } -# Put the entire source code into const char* SOURCE_CODE to make it readable after compilation. -# documentationString SOURCE_CODE -documentationString() { - local docs - docs=$(escapeStringLiteral $'\n----------\n// This binary wrapper was compiled from the following generated C-code:\n'"$1"$'\n----------\n') - printf '%s' "const char * SOURCE_CODE = \"$docs\";" -} - # Makes it safe to insert STRING within quotes in a C String Literal. # escapeStringLiteral STRING escapeStringLiteral() { @@ -257,10 +249,16 @@ escapeStringLiteral() { printf '%s' "$result" } +# Indents every non-empty line by 4 spaces. To avoid trailing whitespace, we don't indent empty lines +# indent4 TEXT_BLOCK +indent4() { + printf '%s' "$1" | awk '{ if ($0 != "") { print " "$0 } else { print $0 }}' +} + assertValidEnvName() { case "$1" in - *=*) printf '\n%s\n' " #error Illegal environment variable name \`$1\` (cannot contain \`=\`)";; - "") printf '\n%s\n' " #error Environment variable name can't be empty.";; + *=*) printf '\n%s\n' "#error Illegal environment variable name \`$1\` (cannot contain \`=\`)";; + "") printf '\n%s\n' "#error Environment variable name can't be empty.";; esac } @@ -295,3 +293,84 @@ void set_env_suffix(char *env, char *sep, char *suffix) { } " } + +# Embed a C string which shows up as readable text in the compiled binary wrapper +# documentationString ARGS +docstring() { + printf '%s' "const char * DOCSTRING = \"$(escapeStringLiteral " + + +# ------------------------------------------------------------------------------------ +# The C-code for this binary wrapper has been generated using the following command: + + +makeCWrapper $(formatArgs "$@") + + +# (Use \`nix-shell -p makeBinaryWrapper\` to get access to makeCWrapper in your shell) +# ------------------------------------------------------------------------------------ + + +")\";" +} + +# formatArgs EXECUTABLE ARGS +formatArgs() { + printf '%s' "$1" + shift + while [ $# -gt 0 ]; do + case "$1" in + --set) + formatArgsLine 2 "$@" + shift 2 + ;; + --set-default) + formatArgsLine 2 "$@" + shift 2 + ;; + --unset) + formatArgsLine 1 "$@" + shift 1 + ;; + --prefix) + formatArgsLine 3 "$@" + shift 3 + ;; + --suffix) + formatArgsLine 3 "$@" + shift 3 + ;; + --chdir) + formatArgsLine 1 "$@" + shift 1 + ;; + --add-flags) + formatArgsLine 1 "$@" + shift 1 + ;; + --argv0) + formatArgsLine 1 "$@" + shift 1 + ;; + --inherit-argv0) + formatArgsLine 0 "$@" + ;; + esac + shift + done + printf '%s\n' "" +} + +# formatArgsLine ARG_COUNT ARGS +formatArgsLine() { + local ARG_COUNT LENGTH + ARG_COUNT=$1 + LENGTH=$# + shift + printf '%s' $' \\\n '"$1" + shift + while [ "$ARG_COUNT" -gt $((LENGTH - $# - 2)) ]; do + printf ' %s' "${1@Q}" + shift + done +} |