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.
This commit is contained in:
parent
e8cedf3819
commit
8d2964a8e6
108
pkgs/build-support/setup-hooks/make-binary-wrapper.sh
Executable file
108
pkgs/build-support/setup-hooks/make-binary-wrapper.sh
Executable file
@ -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 "$@"
|
@ -1,73 +0,0 @@
|
||||
#!/bin/bash
|
||||
# make-c-wrapper.sh EXECUTABLE 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 debug a binary wrapper after you compiled it, use the `strings` command
|
||||
|
||||
escape_string_literal() {
|
||||
# We need to make sure that special characters are escaped
|
||||
# before trying to create C string literals
|
||||
result=${1//$'\\'/$'\\\\'}
|
||||
result=${result//\"/'\"'}
|
||||
result=${result//$'\n'/"\n"}
|
||||
result=${result//$'\r'/"\r"}
|
||||
}
|
||||
|
||||
escape_string_literal "$1"
|
||||
executable="${result}"
|
||||
args=("$@")
|
||||
|
||||
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 < ${#args[*]}; n += 1)); do
|
||||
p="${args[$n]}"
|
||||
if [[ "$p" == "--set" ]]; then
|
||||
escape_string_literal "${args[$((n + 1))]}"
|
||||
key="${result}"
|
||||
escape_string_literal "${args[$((n + 2))]}"
|
||||
value="${result}"
|
||||
n=$((n + 2))
|
||||
printf "%s\n" " putenv(\"${key}=${value}\");"
|
||||
docs="${docs:+$docs$'\n'}putenv(\"${key}=${value}\");"
|
||||
elif [[ "$p" == "--set-default" ]]; then
|
||||
escape_string_literal "${args[$((n + 1))]}"
|
||||
key="${result}"
|
||||
escape_string_literal "${args[$((n + 2))]}"
|
||||
value="${result}"
|
||||
n=$((n + 2))
|
||||
printf "%s\n" " setenv(\"${key}\", \"${value}\", 0);"
|
||||
docs="${docs:+$docs$'\n'}setenv(\"${key}=${value}\", 0);"
|
||||
elif [[ "$p" == "--unset" ]]; then
|
||||
escape_string_literal "${args[$((n + 1))]}"
|
||||
key="${result}"
|
||||
printf "%s\n" " unsetenv(\"$key\");"
|
||||
docs="${docs:+$docs$'\n'}unsetenv(\"${key}\");"
|
||||
n=$((n + 1))
|
||||
elif [[ "$p" == "--argv0" ]]; then
|
||||
escape_string_literal "${args[$((n + 1))]}"
|
||||
argv0="${result}"
|
||||
n=$((n + 1))
|
||||
else
|
||||
# Using an error macro, we will make sure the compiler gives an understandable error message
|
||||
printf "%s\n" " #error make-c-wrapper.sh did not understand argument ${p}"
|
||||
fi
|
||||
done
|
||||
printf "%s\n" " argv[0] = \"${argv0:-${executable}}\";"
|
||||
printf "%s\n" " return execv(\"${executable}\", argv);"
|
||||
printf "%s\n" "}"
|
||||
|
||||
docs="${docs:+$docs$'\n'}argv[0] = \"${argv0:-${executable}}\";"
|
||||
docs="${docs:+$docs$'\n'}execv(\"${executable}\", argv);"
|
||||
docs="----------"$'\n'"This binary wrapper (created from generated C-code) is configured with the following settings:${docs:+$'\n'$docs}"
|
||||
escape_string_literal "$docs"
|
||||
docs=$result
|
||||
printf "\n%s\n" "const char* DOCS = \"$docs\";"
|
Loading…
Reference in New Issue
Block a user