// 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 "i586-unknown-redox" | "riscv64gc-unknown-redox") [ -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" # Re-add prefix toolchain sysroot libs for dynamic builds. # DYNAMIC_INIT resets LDFLAGS from USER_LDFLAGS, so the -L added by # BUILD_PRESCRIPT is lost. Add it back here. REDBEAR_PREFIX_SYSROOT="${COOKBOOK_ROOT}/prefix/${TARGET}/sysroot" if [ -d "${REDBEAR_PREFIX_SYSROOT}/${TARGET}/lib" ]; then export LDFLAGS="${LDFLAGS} -L${REDBEAR_PREFIX_SYSROOT}/${TARGET}/lib" fi export RUSTFLAGS="-C target-feature=-crt-static -L native=${COOKBOOK_SYSROOT}/lib -C link-arg=-Wl,-rpath-link,${COOKBOOK_SYSROOT}/lib" export COOKBOOK_DYNAMIC=1 if [ "$(type -t reexport_flags)" = function ]; 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_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" } "#; 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 # Add redoxer toolchain to path if exists REDOXER_TOOLCHAIN="${HOME}/.redoxer/${TARGET}/toolchain" if [ -d "${REDOXER_TOOLCHAIN}/bin" ] then export PATH="${REDOXER_TOOLCHAIN}/bin:${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" # Default C dialect: gnu17. # # GCC 13.2.0 defaulted to gnu17 (__STDC_VERSION__ 201710L); GCC 16.1.0 # defaults to gnu23 (202311L). The recipe tree is C17-era code, and C23 # makes several previously-legal constructs hard errors -- most notably an # empty parameter list, which used to mean "unspecified arguments" and now # means "no arguments". libiconv's lib/loop_wchar.h has # `extern size_t mbrtowc ();`, which under C23 conflicts with relibc's real # four-argument prototype and fails the build. # # This pin states the dialect these sources were written against; it is not # a workaround for a defect, and it does not suppress any diagnostic. It is # also what the distributions did for the same GCC 14/15 transition. # Individual packages are migrated to C23 as they are touched; when the tree # is clean, drop this line and the default becomes whatever the compiler # ships. Per-recipe `-std=` in CFLAGS still wins, since it is appended after. # C++ is deliberately NOT pinned: kwin and plasma-workspace require C++23 # (std::ranges::to), which is the reason for the GCC 16 upgrade. export CFLAGS="${CFLAGS:+$CFLAGS }-std=gnu17" # -fhardened is a host-glibc hardening bundle that x86_64-unknown-redox # cannot implement. GCC still *accepts* the flag on the command line, so a # meson project's cc.has_argument('-fhardened') probe answers YES and meson # adds it to every compile; GCC then refuses it for real: # cc1: error: '-fhardened' not supported for this target [-Werror] # and the project's -Werror makes it fatal. seatd died on this 24 times. # # Note the diagnostic is tagged [-Werror], not [-Werror=hardened]: it is an # unconditional warning, so -Wno-hardened does NOT silence it (verified). # The flag itself has to be cancelled, and -fno-hardened does that cleanly. # The cookbook's flags are appended after the project's own, so this wins. # # This does not weaken anything: -fhardened is inert on this target by # construction — the compiler is telling us it cannot honour it. export CFLAGS="${CFLAGS} -fno-hardened" export CXXFLAGS="${CXXFLAGS:+$CXXFLAGS }-fno-hardened" # 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" # Belt-and-suspenders: explicitly add the prefix toolchain sysroot to the # linker search path so the fresh relibc libc.a is always found, regardless # of which GCC binary the redoxer ends up invoking. See the companion sync # step in mk/prefix.mk ($(PREFIX)/sysroot target) for the full explanation. REDBEAR_PREFIX_SYSROOT="${COOKBOOK_ROOT}/prefix/${TARGET}/sysroot" if [ -d "${REDBEAR_PREFIX_SYSROOT}/${TARGET}/lib" ]; then export LDFLAGS="${LDFLAGS} -L${REDBEAR_PREFIX_SYSROOT}/${TARGET}/lib" fi # 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" \ --force \ -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 } # configure template COOKBOOK_CONFIGURE="${COOKBOOK_SOURCE}/configure" COOKBOOK_CONFIGURE_FLAGS=( --host="${GNU_TARGET}" --prefix="/usr" --disable-shared --enable-static ) COOKBOOK_MAKE="make" function cookbook_configure { # Defeat autotools maintainer-mode regeneration. Release tarballs ship a # complete, consistent build system, but extraction timestamp skew makes # make think aclocal.m4/configure/Makefile.in are stale and re-run the # version-pinned aclocal-/automake- the tarball was generated with — # which the host (a different automake) lacks, aborting with "aclocal-1.NN: # command not found". Force the generated files newer than their sources so # the regen rules never fire. Harmless for recipes with no autotools files, # and for recipes that intentionally regenerated in their [source] script # (that fresh configure just gets forward-dated). if [ -n "${COOKBOOK_SOURCE}" ] && [ -d "${COOKBOOK_SOURCE}" ]; then # Stagger timestamps so each generated file is strictly newer than its # prerequisites: sources (2000) < aclocal.m4 (2001) < configure/ # config.h.in/Makefile.in (2002). Equal mtimes make GNU make rebuild. find "${COOKBOOK_SOURCE}" '(' -name 'configure.ac' -o -name 'configure.in' -o -name 'Makefile.am' -o -name 'acinclude.m4' ')' -exec touch -t 200001010000 {} + 2>/dev/null || true find "${COOKBOOK_SOURCE}" -name '*.m4' -path '*/m4/*' -exec touch -t 200001010000 {} + 2>/dev/null || true find "${COOKBOOK_SOURCE}" -name 'aclocal.m4' -exec touch -t 200101010000 {} + 2>/dev/null || true find "${COOKBOOK_SOURCE}" '(' -name 'configure' -o -name 'config.h.in' -o -name 'Makefile.in' ')' -exec touch -t 200201010000 {} + 2>/dev/null || true fi # Safety net: if make still triggers a maintainer-mode regen rule (e.g. a # nested Makefile.in whose prereqs include host-installed m4 macros with # newer mtimes), no-op the version-pinned autotools instead of invoking the # absent aclocal-1.NN/automake-1.NN. configure's AM_MISSING_PROG honors these # pre-set values, so the generated Makefiles inherit the no-ops. The shipped # build files are already correct, so skipping regeneration is safe. export ACLOCAL="${ACLOCAL:-true}" export AUTOMAKE="${AUTOMAKE:-true}" export AUTOCONF="${AUTOCONF:-true}" export AUTOHEADER="${AUTOHEADER:-true}" export AUTORECONF="${AUTORECONF:-true}" "${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}" "$@" "${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" "${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) os=$(echo "$target" | cut -d - -f3) if [ "$os" = "linux" ]; then SYSTEM_NAME="Linux" else SYSTEM_NAME="UnixPaths" fi cat > $file <> $file # CMAKE_CXX_FLAGS must come from CXXFLAGS, not CFLAGS. Feeding the C # flags to the C++ compiler was always wrong -- the meson path already # keeps them apart (cpp_args uses CXXFLAGS) -- and it became visible # once CFLAGS gained -std=gnu17, which g++ reports as "valid for C/ObjC # but not for C++" on every single file. CPPFLAGS (the sysroot -I) is # still appended to both, which is what carries the include paths. 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 "$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}" -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}" -j"${COOKBOOK_MAKE_JOBS}" DESTDIR="${COOKBOOK_STAGE}" "${COOKBOOK_NINJA}" install -j"${COOKBOOK_MAKE_JOBS}" } "#; pub(crate) static BUILD_POSTSCRIPT: &str = r#" # 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 while IFS= read -r file do if "${GNU_TARGET}-readelf" -h "${file}" >/dev/null 2>&1 then "${GNU_TARGET}-strip" -v "${file}" fi done < <(find "${dir}" -type f) fi done # Remove libtool files for dir in "${COOKBOOK_STAGE}/lib" "${COOKBOOK_STAGE}/usr/lib" do if [ -d "${dir}" ] then find "${dir}" -type f -name '*.la' -exec rm -fv {} ';' 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||'"${COOKBOOK_NAME}"'|g' {} ';' fi done "#; pub(crate) static GIT_RESET_BRANCH: &str = r#" ORIGIN_BRANCH="$(git branch --remotes | grep '^ origin/HEAD -> ' | cut -d ' ' -f 5-)" if [ -n "$BRANCH" ] then ORIGIN_BRANCH="origin/$BRANCH" fi if [ "$(git rev-parse HEAD)" != "$(git rev-parse $ORIGIN_BRANCH)" ] then git checkout -B "$(echo "$ORIGIN_BRANCH" | cut -d / -f 2-)" "$ORIGIN_BRANCH" fi"#; 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 -9 $ALL_DESCENDANTS; fi "#;