#!/bin/sh
#
# Shell command language linker
#
# Copyright (C) 2015, 2019 Patrick "P. J." McDermott
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
set -u
VERSION='0.3.0'
die()
{
local fmt="${1}"
shift 1
printf "shld: ${fmt}\n" "${@}" >&2
exit 2
}
link()
{
local make_executable="${1}"
local interpreter="${2}"
local entry_point="${3}"
local libs="${4}"
local output="${5}"
shift 5
local input=
# Open output file.
if ! exec 3>"${output}~"; then
die 'Cannot open file "%s"' "${output}~"
fi
# Write magic number and interpreter path.
if ${make_executable}; then
printf '#!%s\n' "${interpreter}" >&3
fi
# Write __init() function.
cat >&3 <<-'EOF'
__init_funcs=''
__init()
{
__init_funcs="${__init_funcs} ${1}"
}
EOF
# Write __DT_NEEDED list and basic RTLD.
printf "__DT_NEEDED='%s'\n" "${libs}" >&3
cat >&3 <<-'EOF'
: ${SHLD_LIBRARY_PATH:=${LIBDATADIR}}
for __lib in ${__DT_NEEDED}; do
__found=false
IFS=':'
for __el in ${SHLD_LIBRARY_PATH}; do
if __f="$(cat "${__el}/${__lib}" 2>/dev/null)"
then
eval "${__f}"
__found=true
break
fi
done
unset IFS
if ! ${__found}; then
printf "%s: error while loading shell $(: \
)shared libraries: %s: cannot open $(: \
)shell shared object file\n" \
"${0}" "${__lib}" >&2
exit 127
fi
done
unset __lib __el __found __f
EOF
# Read input files.
for input in "${@}"; do
if ! cat "${input}" >&3; then
die 'Cannot read file "%s"' "${input}"
fi
done
# Add call to init functions.
cat >&3 <<-'EOF'
unset IFS
for __func in ${__init_funcs}; do
${__func}
done
EOF
# Add call to entry point.
if ${make_executable}; then
printf '%s "${@}"\n' "${entry_point}" >&3
fi
# Close output file, make it executable, and set its name.
exec 3>&-
if ${make_executable}; then
if ! chmod a+x "${output}~"; then
die 'Cannot set mode of file "%s"' "${output}~"
fi
fi
if ! mv "${output}~" "${output}"; then
die 'Cannot rename file to "%s"' "${output}"
fi
}
usage()
{
printf 'Usage: %s [option ...] ...\n' "${0}"
}
help()
{
usage
cat < Add to the list of libraries to load at run time
-I Make an executable and use as the interpreter for your
program, instead of the default of "/bin/sh"
-e Make an executable and use as the function for beginning
execution of your program, instead of the default of "main"
-o