summary refs log tree commit diff
path: root/pkgs/build-support
diff options
context:
space:
mode:
authorTobias Bergkvist <tobias@bergkv.ist>2021-12-09 13:00:24 +0100
committerGitHub <noreply@github.com>2021-12-09 13:00:24 +0100
commitdf13841609b3247f18ce11478e974c3b241546e4 (patch)
treef34b66de95d68937c7a56d712138f14a6429c5cb /pkgs/build-support
parent177f0a6eedcf0b0ab74b845fd7cf77bde0997fbe (diff)
parent32d566e1b9d9ff55ec5b013d5420419649780e0d (diff)
downloadnixpkgs-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.sh161
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
+}