redox/src/cook/script.rs

529 lines
17 KiB
Rust

// Scripts here is executed using "cookbook_redoxer env" where CC, RUSTFLAGS, etc. defined.
// Look up redoxer env script if you want to see how they work.
pub(crate) static SHARED_PRESCRIPT: &str = r#"
# Build dynamically
function DYNAMIC_INIT {
case "${TARGET}" in
"riscv64gc-unknown-redox" | "wasm32-wasip1")
[ -z "${COOKBOOK_VERBOSE}" ] || echo "WARN: ${TARGET} does not support dynamic linking." >&2
return
;;
esac
[ -z "${COOKBOOK_VERBOSE}" ] || echo "DEBUG: Program is being compiled dynamically."
COOKBOOK_CONFIGURE_FLAGS=(
--host="${GNU_TARGET}"
--prefix="/usr"
--enable-shared
--disable-static
)
COOKBOOK_CMAKE_FLAGS=(
-DBUILD_SHARED_LIBS=True
-DENABLE_SHARED=True
-DENABLE_STATIC=False
)
COOKBOOK_MESON_FLAGS=(
--buildtype release
--wrap-mode nofallback
-Ddefault_library=shared
-Dprefix=/usr
)
# TODO: check paths for spaces
export LDFLAGS="${USER_LDFLAGS}-Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib -L${COOKBOOK_SYSROOT}/lib -Wl,--export-dynamic"
rustflags="-C target-feature=-crt-static -L native=${COOKBOOK_SYSROOT}/lib -C link-arg=-Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib"
REDOXER_RUSTFLAGS_KEY=${REDOXER_RUSTFLAGS_KEY:-RUSTFLAGS}
export "${REDOXER_RUSTFLAGS_KEY}=${!REDOXER_RUSTFLAGS_KEY} ${rustflags}"
export COOKBOOK_DYNAMIC=1
if [ "function" = "$(type -t reexport_flags)" ]; then
reexport_flags
fi
}
COOKBOOK_AUTORECONF="autoreconf"
autotools_recursive_regenerate() {
for f in $(find . -name configure.ac -o -name configure.in -type f | sort); do
echo "* autotools regen in '$(dirname $f)'..."
( cd "$(dirname "$f")" && "${COOKBOOK_AUTORECONF}" -fvi "$@" -I${COOKBOOK_LIBTOOL_DIR:-$COOKBOOK_HOST_SYSROOT}/share/aclocal )
done
}
# Build both dynamically and statically
function DYNAMIC_STATIC_INIT {
DYNAMIC_INIT
if [ "${COOKBOOK_DYNAMIC}" == "1" ]
then
COOKBOOK_CONFIGURE_FLAGS=(
--host="${GNU_TARGET}"
--prefix="/usr"
--enable-shared
--enable-static
)
COOKBOOK_CMAKE_FLAGS=(
-DBUILD_SHARED_LIBS=True
-DENABLE_SHARED=True
-DENABLE_STATIC=True
)
COOKBOOK_MESON_FLAGS=(
--buildtype release
--wrap-mode nofallback
-Ddefault_library=both
-Dprefix=/usr
)
fi
}
function GNU_CONFIG_GET {
wget -O "$1" "https://gitlab.redox-os.org/redox-os/gnu-config/-/raw/master/config.sub?inline=false"
}
# Bash error hook
error_hook() {
local ec=$?;
echo "Cookbook error : failed at line $1 with code $ec" >&2;
echo "Error command : $BASH_COMMAND" >&2;
[ -z "${COOKBOOK_VERBOSE_CMD}" ] && echo "Add 'export COOKBOOK_VERBOSE_CMD=1' in .config to see more" >&2;
exit "$ec";
}
trap 'error_hook $LINENO' ERR
"#;
pub(crate) static BUILD_PRESCRIPT: &str = r#"
# Add cookbook bins to path
export PATH="${COOKBOOK_ROOT}/bin:${PATH}"
# Add toolchain dir to path if exists
if [ ! -z "${COOKBOOK_TOOLCHAIN}" ]
then
export PATH="${COOKBOOK_TOOLCHAIN}/bin:${PATH}"
export LD_LIBRARY_PATH="${COOKBOOK_TOOLCHAIN}/lib:${LD_LIBRARY_PATH}"
fi
# This puts cargo build artifacts in the build directory
export CARGO_TARGET_DIR="${COOKBOOK_BUILD}/target"
# This adds the sysroot includes for most C compilation
#TODO: check paths for spaces!
export CPPFLAGS="${CPPFLAGS:+$CPPFLAGS }-I${COOKBOOK_SYSROOT}/include"
# This adds the sysroot libraries and compiles binaries statically for most C compilation
#TODO: check paths for spaces!
USER_LDFLAGS="${LDFLAGS:+$LDFLAGS }"
export LDFLAGS="${USER_LDFLAGS}-L${COOKBOOK_SYSROOT}/lib --static"
# This reexport C variables into custom build script that can be consumed by cc crate
function reexport_flags {
target=${TARGET//-/_}
export CFLAGS_${target}="${CFLAGS:+$CFLAGS }${CPPFLAGS}"
export CXXFLAGS_${target}="${CXXFLAGS:+$CXXFLAGS }${CPPFLAGS}"
export LDFLAGS_${target}="${LDFLAGS}"
}
# These ensure that pkg-config gets the right flags from the sysroot
if [ "${TARGET}" != "${COOKBOOK_HOST_TARGET}" ]
then
export PKG_CONFIG_ALLOW_CROSS=1
export PKG_CONFIG_PATH=
export PKG_CONFIG_LIBDIR="${COOKBOOK_SYSROOT}/lib/pkgconfig"
export PKG_CONFIG_SYSROOT_DIR="${COOKBOOK_SYSROOT}"
fi
# To build the debug version of a Cargo program, add COOKBOOK_DEBUG=true, and
# to not strip symbols from the final package, add COOKBOOK_NOSTRIP=true to the recipe
# (or to your environment) before calling cookbook_cargo or cookbook_cargo_packages
build_type=release
install_flags=--no-track
build_flags=--release
if [ ! -z "${COOKBOOK_DEBUG}" ]
then
install_flags+=" --debug"
build_flags=
build_type=debug
export CPPFLAGS="${CPPFLAGS} -g"
fi
if [ ! -z "${COOKBOOK_OFFLINE}" ]
then
build_flags+=" --offline"
install_flags+=" --offline"
fi
reexport_flags
COOKBOOK_CARGO="${COOKBOOK_REDOXER}"
COOKBOOK_CARGO_FLAGS=(
--locked
)
# cargo template using cargo install
function cookbook_cargo {
"${COOKBOOK_CARGO}" install \
--path "${COOKBOOK_SOURCE}${COOKBOOK_CARGO_PATH:+/$COOKBOOK_CARGO_PATH}" \
--root "${COOKBOOK_STAGE}/usr" \
-j "${COOKBOOK_MAKE_JOBS}" ${install_flags} \
${COOKBOOK_CARGO_FLAGS[@]} "$@"
}
# cargo template using cargo build (prefixed name)
function cookbook_cargo_build {
recipe="${recipe:-$(basename "${COOKBOOK_RECIPE}")}"
bin_dir="${bin_dir:-.}"
bin_flags="${bin_flags:-}"
bin_name="${bin_name:-$(basename "${COOKBOOK_CARGO_PATH}")}"
bin_final_name="${bin_final_name:-${recipe}_${bin_name//_/-}}"
mkdir -pv "${COOKBOOK_STAGE}/usr/bin"
"${COOKBOOK_CARGO}" build \
--manifest-path "${COOKBOOK_SOURCE}${COOKBOOK_CARGO_PATH:+/$COOKBOOK_CARGO_PATH}/Cargo.toml" \
${bin_flags} ${build_flags} -j "${COOKBOOK_MAKE_JOBS}" ${COOKBOOK_CARGO_FLAGS[@]}
cp -v \
"target/${TARGET}/${build_type}/${bin_dir}/${bin_name}" \
"${COOKBOOK_STAGE}/usr/bin/${bin_final_name}"
unset bin_name bin_flags bin_dir bin_final_name
}
# helper for installing binaries that are cargo examples
function cookbook_cargo_examples {
recipe="$(basename "${COOKBOOK_RECIPE}")"
for example in "$@"
do
bin_dir="examples" bin_name="${example}" bin_flags="--example ${example}" cookbook_cargo_build
done
}
# helper for installing binaries that are cargo packages
function cookbook_cargo_packages {
recipe="$(basename "${COOKBOOK_RECIPE}")"
mkdir -pv "${COOKBOOK_STAGE}/usr/bin"
for package in "$@"
do
bin_name="${package}" bin_flags="--package ${package}" bin_final_name="${package//_/-}" cookbook_cargo_build
done
}
# helper for installing binaries that are cargo packages that are prefixed
function cookbook_cargo_packages_prefixed {
recipe="$(basename "${COOKBOOK_RECIPE}")"
mkdir -pv "${COOKBOOK_STAGE}/usr/bin"
for package in "$@"
do
bin_name="${package}" bin_flags="--package ${package}" cookbook_cargo_build
done
}
# configure template
COOKBOOK_CONFIGURE="${COOKBOOK_SOURCE}/configure"
COOKBOOK_CONFIGURE_FLAGS=(
--host="${GNU_TARGET}"
--prefix="/usr"
--disable-shared
--enable-static
)
COOKBOOK_MAKE_FLAGS=()
if [ -n "${COOKBOOK_VERBOSE_CMD}" ]; then
COOKBOOK_MAKE_FLAGS+=(V=1)
else
COOKBOOK_MAKE_FLAGS+=(V=0)
fi
COOKBOOK_NINJA_FLAGS=()
if [ -n "${COOKBOOK_VERBOSE_CMD}" ]; then
COOKBOOK_NINJA_FLAGS+=(--verbose)
fi
COOKBOOK_MAKE="make"
function cookbook_configure {
"${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}" "$@"
"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" "${COOKBOOK_MAKE_FLAGS[@]}"
"${COOKBOOK_MAKE}" install DESTDIR="${COOKBOOK_STAGE}"
}
COOKBOOK_CMAKE="cmake"
COOKBOOK_NINJA="ninja"
COOKBOOK_CMAKE_FLAGS=(
-DBUILD_SHARED_LIBS=False
-DENABLE_SHARED=False
-DENABLE_STATIC=True
)
function generate_cookbook_cmake_file {
target=$1
gcc_prefix=$2
sysroot=$3
file=$4
arch=$(echo "$target" | cut -d - -f1)
if [[ "$target" == *"-linux-"* ]]; then
system_name="Linux"
else
system_name="UnixPaths"
fi
if [[ "$REDOXER_USE_CLANG" != "1" && "$REDOXER_USE_CLANG" != "true" ]]; then
cat > $file <<EOF
set(CMAKE_AR ${gcc_prefix}gcc-ar)
set(CMAKE_CXX_COMPILER ${gcc_prefix}g++)
set(CMAKE_C_COMPILER ${gcc_prefix}gcc)
set(CMAKE_NM ${gcc_prefix}gcc-nm)
set(CMAKE_RANLIB ${gcc_prefix}gcc-ranlib)
EOF
else
cat > $file <<EOF
set(CMAKE_AR llvm-ar)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_C_COMPILER clang)
set(CMAKE_NM llvm-nm)
set(CMAKE_RANLIB llvm-ranlib)
EOF
if [ "$target" != "$COOKBOOK_HOST_TARGET" ]; then
cat >> $file <<EOF
set(CMAKE_C_COMPILER_TARGET ${target})
set(CMAKE_CXX_COMPILER_TARGET ${target})
set(CMAKE_ASM_COMPILER_TARGET ${target})
EOF
# redox clang workaround (see redoxer env)
CXXFLAGS="${CXXFLAGS:+$CXXFLAGS }-stdlib=libstdc++"
fi
fi
cat >> $file <<EOF
set(CMAKE_FIND_ROOT_PATH ${sysroot})
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME 1)
set(CMAKE_PREFIX_PATH, ${sysroot})
set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
set(CMAKE_SYSTEM_NAME ${system_name})
set(CMAKE_SYSTEM_PROCESSOR ${arch})
EOF
if [ "$target" = "$GNU_TARGET" ]
then
echo "set(CMAKE_C_FLAGS \"${CFLAGS} ${CPPFLAGS}\")" >> $file
echo "set(CMAKE_CXX_FLAGS \"${CXXFLAGS} ${CPPFLAGS}\")" >> $file
fi
if [ -n "${CC_WRAPPER}" ]
then
echo "set(CMAKE_C_COMPILER_LAUNCHER ${CC_WRAPPER})" >> $file
echo "set(CMAKE_CXX_COMPILER_LAUNCHER ${CC_WRAPPER})" >> $file
fi
}
function cookbook_cmake {
if [ "$TARGET" = "$COOKBOOK_HOST_TARGET" ]; then
GCC_PREFIX=
else
GCC_PREFIX=$GNU_TARGET-
fi
generate_cookbook_cmake_file "$GNU_TARGET" "$GCC_PREFIX" "$COOKBOOK_SYSROOT" cross_file.cmake
"${COOKBOOK_CMAKE}" "${COOKBOOK_SOURCE}" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CROSSCOMPILING=True \
-DCMAKE_INSTALL_INCLUDEDIR=include \
-DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_INSTALL_OLDINCLUDEDIR=/include \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_SBINDIR=bin \
-DCMAKE_TOOLCHAIN_FILE=cross_file.cmake \
-GNinja \
-Wno-dev \
"${COOKBOOK_CMAKE_FLAGS[@]}" \
"$@"
"${COOKBOOK_NINJA}" "${COOKBOOK_NINJA_FLAGS[@]}" -j"${COOKBOOK_MAKE_JOBS}"
DESTDIR="${COOKBOOK_STAGE}" "${COOKBOOK_NINJA}" install -j"${COOKBOOK_MAKE_JOBS}"
}
COOKBOOK_MESON="meson"
COOKBOOK_MESON_FLAGS=(
--buildtype release
--wrap-mode nofallback
-Ddefault_library=static
-Dprefix=/usr
)
function cookbook_meson {
# TODO: do this in rust, to handle path spaces as well
function format_flags {
local flags=($1)
local formatted=""
for i in "${!flags[@]}"; do
formatted+="'${flags[$i]}'"
if [ $i -lt $((${#flags[@]} - 1)) ]; then
formatted+=", "
fi
done
echo "$formatted"
}
echo "[binaries]" > cross_file.txt
echo "c = [$(printf "'%s', " $CC | sed 's/, $//')]" >> cross_file.txt
echo "cpp = [$(printf "'%s', " $CXX | sed 's/, $//')]" >> cross_file.txt
echo "ar = '${AR}'" >> cross_file.txt
echo "strip = '${STRIP}'" >> cross_file.txt
echo "pkg-config = '${PKG_CONFIG}'" >> cross_file.txt
echo "llvm-config = '${TARGET}-llvm-config'" >> cross_file.txt
echo "glib-compile-resources = 'glib-compile-resources'" >> cross_file.txt
echo "glib-compile-schemas = 'glib-compile-schemas'" >> cross_file.txt
echo "[host_machine]" >> cross_file.txt
echo "system = '$(echo "${TARGET}" | cut -d - -f3)'" >> cross_file.txt
echo "cpu_family = '$(echo "${TARGET}" | cut -d - -f1)'" >> cross_file.txt
echo "cpu = '$(echo "${TARGET}" | cut -d - -f1)'" >> cross_file.txt
echo "endian = 'little'" >> cross_file.txt
echo "[built-in options]" >> cross_file.txt
echo "prefix = '/usr'" >> cross_file.txt
echo "libdir = 'lib'" >> cross_file.txt
echo "bindir = 'bin'" >> cross_file.txt
echo "c_args = [$(format_flags "$CFLAGS $CPPFLAGS")]" >> cross_file.txt
echo "cpp_args = [$(format_flags "$CXXFLAGS $CPPFLAGS")]" >> cross_file.txt
echo "c_link_args = [$(format_flags "$LDFLAGS")]" >> cross_file.txt
echo "[properties]" >> cross_file.txt
echo "needs_exe_wrapper = true" >> cross_file.txt
echo "sys_root = '${COOKBOOK_SYSROOT}'" >> cross_file.txt
unset AR AS CC CXX LD NM OBJCOPY OBJDUMP PKG_CONFIG RANLIB READELF STRIP
"${COOKBOOK_MESON}" setup \
"${COOKBOOK_SOURCE}" \
. \
--cross-file cross_file.txt \
"${COOKBOOK_MESON_FLAGS[@]}" \
"$@"
"${COOKBOOK_NINJA}" "${COOKBOOK_NINJA_FLAGS[@]}" -j"${COOKBOOK_MAKE_JOBS}"
DESTDIR="${COOKBOOK_STAGE}" "${COOKBOOK_NINJA}" install -j"${COOKBOOK_MAKE_JOBS}"
}
COOKBOOK_PYTHON="${COOKBOOK_TOOLCHAIN}/bin/python3"
COOKBOOK_PYTHON_V="python3.12"
function PYTHON_INIT {
ARCH="${TARGET%%-*}"
OS=$(echo "${TARGET}" | cut -d - -f3-4)
SYSTEM=$(echo "${TARGET}" | cut -d - -f3)
export PYTHONPYCACHEPREFIX="${COOKBOOK_BUILD}" _PYTHON_HOST_PLATFORM="$OS-$ARCH"
export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}${COOKBOOK_SYSROOT}/usr/lib/${COOKBOOK_PYTHON_V}"
export PYTHONPATH="${PYTHONPATH:+$PYTHONPATH:}${COOKBOOK_SYSROOT}/usr/lib/${COOKBOOK_PYTHON_V}/site-packages"
export _PYTHON_SYSCONFIGDATA_NAME="_sysconfigdata__${SYSTEM}_${ARCH}-${OS}"
}
COOKBOOK_PYTHON_PIP_FLAGS=(
--ignore-installed --no-index --no-build-isolation
)
function cookbook_python {
PYTHON_INIT
# no way to do out-of-tree build: https://github.com/pypa/setuptools/issues/3237
rsync -a "${COOKBOOK_SOURCE}/" ./source
if [ -n "${COOKBOOK_PYTHON_LEGACY_SETUP}" ]; then
pushd ./source
python3 ./setup.py install
popd
fi
"${COOKBOOK_PYTHON}" -m pip install --prefix="${COOKBOOK_STAGE}/usr" \
"./source${COOKBOOK_PYTHON_PYPROJECT_PATH:+/$COOKBOOK_PYTHON_PYPROJECT_PATH}" \
"${COOKBOOK_PYTHON_PIP_FLAGS[@]}" "$@"
rsync -av "${COOKBOOK_BUILD}/${COOKBOOK_STAGE}/usr/" "${COOKBOOK_STAGE}/usr"
}
"#;
pub(crate) static BUILD_POSTSCRIPT: &str = r#"
STRIP="${GNU_TARGET}-strip"
STRIP_ARGS=""
if [ -n "${COOKBOOK_VERBOSE_CMD}" ]; then
STRIP_ARGS="-v"
fi
if [[ "$REDOXER_USE_CLANG" = "1" || "$REDOXER_USE_CLANG" = "true" ]]; then
STRIP="llvm-strip"
# clang 21 does not support verbose flag, only 23 or above
# [ -n "${COOKBOOK_VERBOSE_CMD}" ] && STRIP_ARGS="--verbose"
elif [[ "$REDOXER_USE_LTO" = "1" || "$REDOXER_USE_LTO" = "true" ]]; then
GCC_BIN=$(command -v "${GNU_TARGET}-gcc")
GCC_VER=$("${GNU_TARGET}-gcc" -dumpfullversion)
PLUGIN_PATH=$(realpath "$(dirname "$GCC_BIN")/../libexec/gcc/${GNU_TARGET}/${GCC_VER}/liblto_plugin.so")
# binutils 2.41 does not support strip plugins, only 2.44 or above
# [ -f "$PLUGIN_PATH" ] && STRIP_ARGS="--plugin=${PLUGIN_PATH} -v" || echo "DEBUG: $PLUGIN_PATH not found"
fi
strip_directory() {
local target_dir="$1"
local strip_cmd="${STRIP}"
local strip_flags="${STRIP_ARGS:-}"
find "$target_dir" -type f -print0 | while IFS= read -r -d '' file; do
if [ "$(od -An -t x1 -N 4 "$file" | tr -d ' \n')" = "7f454c46" ]; then
"${STRIP}" ${STRIP_ARGS} "$file"
fi
done
}
# Strip binaries
for dir in "${COOKBOOK_STAGE}/bin" "${COOKBOOK_STAGE}/usr/bin" "${COOKBOOK_STAGE}/libexec" "${COOKBOOK_STAGE}/usr/libexec"
do
if [ -d "${dir}" ] && [ -z "${COOKBOOK_NOSTRIP}" ]
then
strip_directory "${dir}"
fi
done
# do not strip symbols for libraries
STRIP_ARGS+=" --strip-debug"
# Remove libtool files and strip debugging information
for dir in "${COOKBOOK_STAGE}/lib" "${COOKBOOK_STAGE}/usr/lib"
do
if [ -d "${dir}" ]
then
find "${dir}" -type f -name '*.la' -exec rm -fv {} ';'
if [ -z "${COOKBOOK_NOSTRIP}" ]
then
strip_directory "${dir}"
fi
fi
done
# Remove cargo install files
for file in .crates.toml .crates2.json
do
if [ -f "${COOKBOOK_STAGE}/${file}" ]
then
rm -v "${COOKBOOK_STAGE}/${file}"
fi
done
# Add pkgname to appstream metadata
for dir in "${COOKBOOK_STAGE}/share/metainfo" "${COOKBOOK_STAGE}/usr/share/metainfo"
do
if [ -d "${dir}" ]
then
find "${dir}" -type f -name '*.xml' -exec sed -i 's|</component>|<pkgname>'"${COOKBOOK_NAME}"'</pkgname></component>|g' {} ';'
fi
done
"#;
pub static KILL_ALL_PID: &str = r#"
THISPID=$$
CHILDREN=$(ps -o pid= --ppid $PID | grep -v $THISPID);
ALL_DESCENDANTS='';
while [ -n "$CHILDREN" ]; do
ALL_DESCENDANTS="$ALL_DESCENDANTS $CHILDREN";
CHILDREN=$(ps -o pid= --ppid $(echo $CHILDREN) | tr '\n' ' ');
done;
if [ -n "$ALL_DESCENDANTS" ]; then
kill $ALL_DESCENDANTS;
fi
killall sccache
"#;