summary refs log tree commit diff
path: root/pkgs/build-support/setup-hooks/make-binary-wrapper.sh
diff options
context:
space:
mode:
authorTobias Bergkvist <tobias@bergkv.ist>2021-06-01 01:02:08 +0200
committerTobias Bergkvist <tobias@bergkv.ist>2021-06-01 01:02:08 +0200
commit8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973 (patch)
treee93ccd3604f6836730d783b220aebd1feafc9d83 /pkgs/build-support/setup-hooks/make-binary-wrapper.sh
parente8cedf381914d28e162810f567216f8c00f87edc (diff)
downloadnixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar.gz
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar.bz2
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar.lz
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar.xz
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.tar.zst
nixpkgs-8d2964a8e6ee63c31f54aa408a2ca3a0c4e1b973.zip
Rename make-c-wrapper.sh to make-binary-wrapper.sh. Refactor to match style of other setup-hooks. Add compilation step with gcc. Embed the entire generated source code into the binary for troubleshooting.
Diffstat (limited to 'pkgs/build-support/setup-hooks/make-binary-wrapper.sh')
-rwxr-xr-xpkgs/build-support/setup-hooks/make-binary-wrapper.sh108
1 files changed, 108 insertions, 0 deletions
diff --git a/pkgs/build-support/setup-hooks/make-binary-wrapper.sh b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh
new file mode 100755
index 00000000000..b77aca60a01
--- /dev/null
+++ b/pkgs/build-support/setup-hooks/make-binary-wrapper.sh
@@ -0,0 +1,108 @@
+# Generate a binary executable wrapper for wrapping an executable.
+# The binary is compiled from generated C-code using gcc.
+# makeBinaryWrapper EXECUTABLE OUT_PATH ARGS
+
+# ARGS:
+# --argv0       NAME    : set name of executed process to NAME
+#                         (defaults to EXECUTABLE)
+# --set         VAR VAL : add VAR with value VAL to the executable’s
+#                         environment
+# --set-default VAR VAL : like --set, but only adds VAR if not already set in
+#                         the environment
+# --unset       VAR     : remove VAR from the environment
+#
+# To troubleshoot a binary wrapper after you compiled it,
+# use the `strings` command or open the binary file in a text editor.
+makeBinaryWrapper() {
+    makeDocumentedCWrapper "$1" "${@:3}" | gcc -x c -o "$2" -
+}
+
+# Generate source code for the wrapper in such a way that the wrapper source code
+# will still be readable even after compilation
+# makeDocumentedCWrapper EXECUTABLE ARGS
+# ARGS: same as makeBinaryWrapper
+makeDocumentedCWrapper() {
+    local src=$(makeCWrapper "$@")
+    local docs=$(documentationString "$src")
+    printf "%s\n" "$src"
+    printf "\n%s\n" "$docs"
+}
+
+# makeCWrapper EXECUTABLE ARGS
+# ARGS: same as makeBinaryWrapper
+makeCWrapper() {
+    local argv0 n params cmd
+    local executable=$(escapeStringLiteral "$1")
+    local params=("$@")
+
+    printf "%s\n" "#include <unistd.h>"
+    printf "%s\n" "#include <stdlib.h>"
+    printf "\n%s\n" "int main(int argc, char **argv) {"
+
+    for ((n = 1; n < ${#params[*]}; n += 1)); do
+        p="${params[$n]}"
+        if [[ "$p" == "--set" ]]; then
+            cmd=$(setEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}")
+            n=$((n + 2))
+            printf "%s\n" "    $cmd"
+        elif [[ "$p" == "--set-default" ]]; then
+            cmd=$(setDefaultEnv "${params[$((n + 1))]}" "${params[$((n + 2))]}")
+            n=$((n + 2))
+            printf "%s\n" "    $cmd"
+        elif [[ "$p" == "--unset" ]]; then
+            cmd=$(unsetEnv "${params[$((n + 1))]}")
+            printf "%s\n" "    $cmd"
+            n=$((n + 1))
+        elif [[ "$p" == "--argv0" ]]; then
+            argv0=$(escapeStringLiteral "${params[$((n + 1))]}")
+            n=$((n + 1))
+        else
+            # Using an error macro, we will make sure the compiler gives an understandable error message
+            printf "%s\n" "    #error makeCWrapper did not understand argument ${p}"
+        fi
+    done
+
+    printf "%s\n" "    argv[0] = \"${argv0:-${executable}}\";"
+    printf "%s\n" "    return execv(\"${executable}\", argv);"
+    printf "%s\n" "}"
+}
+
+# setEnv KEY VALUE
+setEnv() {
+    local key=$(escapeStringLiteral "$1")
+    local value=$(escapeStringLiteral "$2")
+    printf "%s" "putenv(\"${key}=${value}\");"
+}
+
+# setDefaultEnv KEY VALUE
+setDefaultEnv() {
+    local key=$(escapeStringLiteral "$1")
+    local value=$(escapeStringLiteral "$2")
+    printf "%s" "setenv(\"$key\", \"$value\", 0);"
+}
+
+# unsetEnv KEY
+unsetEnv() {
+    local key=$(escapeStringLiteral "$1")
+    printf "%s" "unsetenv(\"$key\");"
+}
+
+# Put the entire source code into const char* SOURCE_CODE to make it readable after compilation.
+# documentationString SOURCE_CODE
+documentationString() {
+    local 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() {
+    local result
+    result=${1//$'\\'/$'\\\\'}
+    result=${result//\"/'\"'}
+    result=${result//$'\n'/"\n"}
+    result=${result//$'\r'/"\r"}
+    printf "%s" "$result"
+}
+
+makeBinaryWrapper "$@"