From 04cfde15ea3d92b54a0ad0d0658359633722b0e3 Mon Sep 17 00:00:00 2001 From: JeremyStarTM Date: Sun, 10 Mar 2024 21:58:24 +0100 Subject: [PATCH] Add logging functions (with colors!) --- buildtool.sh | 248 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 103 deletions(-) diff --git a/buildtool.sh b/buildtool.sh index 3883fda..96559e7 100755 --- a/buildtool.sh +++ b/buildtool.sh @@ -1,20 +1,62 @@ #!/bin/bash set -eo pipefail -# Banner -echo " _ _ _ _ _ _ _ _ " -echo " (_)___| |_ _ __ ___ | | _____ _ __ _ __ ___| | ___ _ __ | |_(_)_ __ ___ (_)_______ __| |" -echo " | / __| __| '_ \` _ \\ _____| |/ / _ \\ '__| '_ \\ / _ \\ |_____ / _ \\| '_ \\| __| | '_ \` _ \\| |_ / _ \\/ _\` |" -echo " | \\__ \\ |_| | | | | |_____| < __/ | | | | | __/ |_____| (_) | |_) | |_| | | | | | | |/ / __/ (_| |" -echo " _/ |___/\\__|_| |_| |_| |_|\\_\\___|_| |_| |_|\\___|_| \\___/| .__/ \\__|_|_| |_| |_|_/___\\___|\\__,_|" -echo "|__/ |_|" -echo "" - # Variables +## Cloning (update these if you fork this project) export "BUILDTOOL_REPOSITORY=https://git.staropensource.de/JeremyStarTM/kernel-optimized.git" -export "BUILDTOOL_PACKAGES=base-devel git rustup" -export "BUILDTOOL_BUILDCMDLINE=nice -20 env MAKEFLAGS=-j$(nproc)" export "BUILDTOOL_CLONEDIR=jstm-kernel-optimized" +## Base packages to install, packages will be added by questions +export "BUILDTOOL_PACKAGES=base-devel git rustup" +## Building command line stuff +export "BUILDTOOL_BUILDCMDLINE=nice -20 env MAKEFLAGS=-j$(nproc)" +## OOOOoooo colors! (not true color tho) +export "BUILDTOOL_COLOR_SPECIAL=\e[0;35m" +export "BUILDTOOL_COLOR_WARN=\e[0;33m" +export "BUILDTOOL_COLOR_ERROR=\e[0;31m" +export "BUILDTOOL_COLOR_RESET=\e[0m" + +# Logging +## Empty +function empty() { + echo "" +} +## Special +function special() { + echo -e "${BUILDTOOL_COLOR_SPECIAL}${*}${BUILDTOOL_COLOR_RESET}" +} +## Informational (header) +function infoh() { + echo -e "${BUILDTOOL_COLOR_RESET}:: ${*}" +} +## Informational (extension) +function infoe() { + echo -e "${BUILDTOOL_COLOR_RESET} ${*}" +} +## Warning (header) +function warnh() { + echo -e "${BUILDTOOL_COLOR_WARN}:: Warning: ${*}${BUILDTOOL_COLOR_RESET}" +} +## Warning (extension) +function warne() { + echo -e "${BUILDTOOL_COLOR_WARN} : ${*}${BUILDTOOL_COLOR_RESET}" +} +## Error (header) +function errorh() { + echo -e "${BUILDTOOL_COLOR_ERROR}:: Error: ${*}${BUILDTOOL_COLOR_RESET}" +} +## Error (extension) +function errore() { + echo -e "${BUILDTOOL_COLOR_ERROR} : ${*}${BUILDTOOL_COLOR_RESET}" +} + +# Banner +special "${BUILDTOOL_COLOR_RESET}${BUILDTOOL_COLOR_SPECIAL} _ _ _ _ _ _ _ _ " +special " (_)___| |_ _ __ ___ | | _____ _ __ _ __ ___| | ___ _ __ | |_(_)_ __ ___ (_)_______ __| |" +special " | / __| __| '_ \` _ \\ _____| |/ / _ \\ '__| '_ \\ / _ \\ |_____ / _ \\| '_ \\| __| | '_ \` _ \\| |_ / _ \\/ _\` |" +special " | \\__ \\ |_| | | | | |_____| < __/ | | | | | __/ |_____| (_) | |_) | |_| | | | | | | |/ / __/ (_| |" +special " _/ |___/\\__|_| |_| |_| |_|\\_\\___|_| |_| |_|\\___|_| \\___/| .__/ \\__|_|_| |_| |_|_/___\\___|\\__,_|${BUILDTOOL_COLOR_RESET}" +special "|__/ |_|" +empty # Checks ## Check for Arch Linux @@ -23,33 +65,33 @@ export "BUILDTOOL_CLONEDIR=jstm-kernel-optimized" source "/etc/os-release" if [ "${NAME}" != "Arch Linux" ] || [ "${PRETTY_NAME}" != "Arch Linux" ] || [ "${ID}" != "arch" ]; then if [ "${BUILDTOOL_COMPILE_NONARCH}" != "true" ]; then - echo ":: Error: Not running on Arch Linux." - echo " This kernel can only compile on Arch Linux." - echo " If you are sure that you want to compile this kernel on other distributions" - echo " set the \$BUILDTOOL_COMPILE_NONARCH environment variable to \"true\"" + errorh "Not running on Arch Linux" + errore "This kernel can only compile on Arch Linux" + errore "If you are sure that you want to compile this kernel on other distributions" + errore "set the \$BUILDTOOL_COMPILE_NONARCH environment variable to \"true\"" exit 1 else - echo ":: Warning: Compiling on a non-arch distribution. This may lead to unexpected errors!" + warnh "Compiling on a non-arch distribution. This may lead to unexpected errors!" fi fi ) ## Check for root if [ "${UID}" == "0" ]; then - echo ":: Error: Can't build kernel as root." - echo " Please create a new user for building the kernel." + errorh "Can't build kernel as root" + errore "Please create a new user for building the kernel" exit 1 fi ## Check for sudo if ! which sudo &> /dev/null; then - echo ":: Error: Could not find sudo in \$PATH." - echo " Please ensure that you have sudo installed." + errorh "Could not find sudo in \$PATH" + errore "Please ensure that you have sudo installed" exit 1 fi # Questions ## Ask if mold should replace ld/lld function ask_mold() { - read -rp ":: Do you want to use mold as your linker (much faster) [Y/n]? " BUILDTOOL_MOLD + read -rp "$(infoh "Do you want to use mold as your linker (much faster) [Y/n]? ")" BUILDTOOL_MOLD case "${BUILDTOOL_MOLD}" in "y"|"Y"|"") export "BUILDTOOL_PACKAGES=${BUILDTOOL_PACKAGES} mold" @@ -57,26 +99,26 @@ function ask_mold() { ;; "n"|"N") ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_mold esac } ## Ask if the governor should be adjusted function ask_cpupower() { - read -rp ":: Do you want to adjust the cpu governor (improves build performance) [Y/n]? " BUILDTOOL_CPUPOWER + read -rp "$(infoh "Do you want to adjust the cpu governor (improves build performance) [Y/n]? ")" BUILDTOOL_CPUPOWER case "${BUILDTOOL_CPUPOWER}" in "y"|"Y"|"") export "BUILDTOOL_PACKAGES=${BUILDTOOL_PACKAGES} cpupower" ;; "n"|"N") ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_cpupower esac } ## Ask for building in tmpfs function ask_tmpfs() { - read -rp ":: Do you want to build in a tmpfs (improves build performance, protects your disk from wearing out faster, ~32 GiB memory required) [Y/n]? " BUILDTOOL_TMPFS + read -rp "$(infoh "Do you want to build in a tmpfs (improves build performance, protects your disk from wearing out faster, ~32 GiB memory required) [Y/n]? ")" BUILDTOOL_TMPFS case "${BUILDTOOL_TMPFS}" in "y"|"Y"|"") export "BUILDTOOL_CLONEDIR=/tmp/${BUILDTOOL_CLONEDIR}" @@ -85,13 +127,13 @@ function ask_tmpfs() { export "BUILDTOOL_CLONEDIR=$(pwd)/${BUILDTOOL_CLONEDIR}" ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_tmpfs esac } ## Ask for kernel config modification using xconfig function ask_xconfig() { - read -rp ":: Do you want to configure the kernel using xconfig before build [y/N]? " BUILDTOOL_XCONFIG + read -rp "$(infoh "Do you want to configure the kernel using xconfig before build [y/N]? ")" BUILDTOOL_XCONFIG case "${BUILDTOOL_XCONFIG}" in "y"|"Y") export "BUILDTOOL_PKGBUILD_XCONFIG=_makexconfig=SET" @@ -100,13 +142,13 @@ function ask_xconfig() { export "BUILDTOOL_PKGBUILD_XCONFIG=_makexconfig=" ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_xconfig esac } ## Ask for kernel config modification using xconfig function ask_nconfig() { - read -rp ":: Do you want to configure the kernel using nconfig before build [y/N]? " BUILDTOOL_NCONFIG + read -rp "$(infoh "Do you want to configure the kernel using nconfig before build [y/N]? ")" BUILDTOOL_NCONFIG case "${BUILDTOOL_NCONFIG}" in "y"|"Y") export "BUILDTOOL_PKGBUILD_NCONFIG=_makenconfig=SET" @@ -115,13 +157,13 @@ function ask_nconfig() { export "BUILDTOOL_PKGBUILD_NCONFIG=_makenconfig=" ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_nconfig esac } ## Ask if the final kernel configuration should be copied function ask_cpfinalconfig() { - read -rp ":: Do you want to copy the final kernel configuration before build [y/N]? " BUILDTOOL_CPFINALCONFIG + read -rp "$(infoh "Do you want to copy the final kernel configuration before build [y/N]? ")" BUILDTOOL_CPFINALCONFIG case "${BUILDTOOL_CPFINALCONFIG}" in "y"|"Y") export "BUILDTOOL_PKGBUILD_CPFINALCONFIG=_copyfinalconfig=SET" @@ -130,18 +172,18 @@ function ask_cpfinalconfig() { export "BUILDTOOL_PKGBUILD_CPFINALCONFIG=_copyfinalconfig=" ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_cpfinalconfig esac } ## Ask if only active modules should be compiled into the kernel function ask_modprobeddb() { - read -rp ":: Do you want to only build active kernel modules (modprobed-db must be installed, read \"https://wiki.archlinux.org/index.php/Modprobed-db\" first) [y/N]? " BUILDTOOL_MODPROBEDDB + read -rp "$(infoh "Do you want to only build active kernel modules (modprobed-db must be installed, read \"https://wiki.archlinux.org/index.php/Modprobed-db\" first) [y/N]? ")" BUILDTOOL_MODPROBEDDB case "${BUILDTOOL_MODPROBEDDB}" in "y"|"Y") if ! which modprobed-db &> /dev/null; then - echo ":: Error: Could not find modprobed-db in \$PATH." - echo " Please ensure that you have modprobed-db installed." + errorh "Could not find modprobed-db in \$PATH." + errore "Please ensure that you have modprobed-db installed." ask_modprobeddb return 1 fi @@ -152,71 +194,71 @@ function ask_modprobeddb() { export "BUILDTOOL_PKGBUILD_MODPROBEDDB=_localmodcfg=" ;; *) - echo "Invalid answer. Please answer with Y or N." + errorh "Invalid answer. Please answer with Y or N" ask_modprobeddb esac } ## Ask for sub architecture function ask_subarchitecture() { - echo ":: Displaying sub architecture list" - echo " 1. AMD Opteron/Athlon64/Hammer/K8 (MK8)" - echo " 2. AMD Opteron/Athlon64/Hammer/K8 with SSE3 (MK8SSE3)" - echo " 3. AMD 61xx/7x50/PhenomX3/X4/II/K10 (MK10)" - echo " 4. AMD Barcelona (MBARCELONA)" - echo " 5. AMD Bobcat (MBOBCAT)" - echo " 6. AMD Jaguar (MJAGUAR)" - echo " 7. AMD Bulldozer (MBULLDOZER)" - echo " 8. AMD Piledriver (MPILEDRIVER)" - echo " 9. AMD Steamroller (MSTEAMROLLER)" - echo " 10. AMD Excavator (MEXCAVATOR)" - echo " 11. AMD Zen (MZEN)" - echo " 12. AMD Zen 2 (MZEN2)" - echo " 13. AMD Zen 3 (MZEN3)" - echo " 14. AMD Zen 4 (MZEN4)" - echo " 15. Intel P4 / older Netburst based Xeon (MPSC)" - echo " 16. Intel Core 2 (MCORE2)" - echo " 17. Intel Atom (MATOM)" - echo " 18. Intel Nehalem (MNEHALEM)" - echo " 19. Intel Westmere (MWESTMERE)" - echo " 20. Intel Silvermont (MSILVERMONT)" - echo " 21. Intel Goldmont (MGOLDMONT)" - echo " 22. Intel Goldmont Plus (MGOLDMONTPLUS)" - echo " 23. Intel Sandy Bridge (MSANDYBRIDGE)" - echo " 24. Intel Ivy Bridge (MIVYBRIDGE)" - echo " 25. Intel Haswell (MHASWELL)" - echo " 26. Intel Broadwell (MBROADWELL)" - echo " 27. Intel Skylake (MSKYLAKE)" - echo " 28. Intel Skylake X (MSKYLAKEX)" - echo " 29. Intel Cannon Lake (MCANNONLAKE)" - echo " 30. Intel Ice Lake (MICELAKE)" - echo " 31. Intel Cascade Lake (MCASCADELAKE)" - echo " 32. Intel Cooper Lake (MCOOPERLAKE)" - echo " 33. Intel Tiger Lake (MTIGERLAKE)" - echo " 34. Intel Sapphire Rapids (MSAPPHIRERAPIDS)" - echo " 35. Intel Rocket Lake (MROCKETLAKE)" - echo " 36. Intel Alder Lake (MALDERLAKE)" - echo " 37. Intel Raptor Lake (MRAPTORLAKE)" - echo " 38. Intel Meteor Lake (MMETEORLAKE)" - echo " 39. Intel Emerald Rapids (MEMERALDRAPIDS)" - echo " 40. Generic-x86-64 (GENERIC_CPU)" - echo " 41. Generic-x86-64-v2 (GENERIC_CPU2)" - echo " 42. Generic-x86-64-v3 (GENERIC_CPU3)" - echo " 43. Generic-x86-64-v4 (GENERIC_CPU4)" - echo " 44. Intel-Native optimizations autodetected by the compiler (MNATIVE_INTEL)" - echo " 45. AMD-Native optimizations autodetected by the compiler (MNATIVE_AMD)" + infoh "Displaying sub architecture list" + infoe " 1. AMD Opteron/Athlon64/Hammer/K8 (MK8)" + infoe " 2. AMD Opteron/Athlon64/Hammer/K8 with SSE3 (MK8SSE3)" + infoe " 3. AMD 61xx/7x50/PhenomX3/X4/II/K10 (MK10)" + infoe " 4. AMD Barcelona (MBARCELONA)" + infoe " 5. AMD Bobcat (MBOBCAT)" + infoe " 6. AMD Jaguar (MJAGUAR)" + infoe " 7. AMD Bulldozer (MBULLDOZER)" + infoe " 8. AMD Piledriver (MPILEDRIVER)" + infoe " 9. AMD Steamroller (MSTEAMROLLER)" + infoe "10. AMD Excavator (MEXCAVATOR)" + infoe "11. AMD Zen (MZEN)" + infoe "12. AMD Zen 2 (MZEN2)" + infoe "13. AMD Zen 3 (MZEN3)" + infoe "14. AMD Zen 4 (MZEN4)" + infoe "15. Intel P4 / older Netburst based Xeon (MPSC)" + infoe "16. Intel Core 2 (MCORE2)" + infoe "17. Intel Atom (MATOM)" + infoe "18. Intel Nehalem (MNEHALEM)" + infoe "19. Intel Westmere (MWESTMERE)" + infoe "20. Intel Silvermont (MSILVERMONT)" + infoe "21. Intel Goldmont (MGOLDMONT)" + infoe "22. Intel Goldmont Plus (MGOLDMONTPLUS)" + infoe "23. Intel Sandy Bridge (MSANDYBRIDGE)" + infoe "24. Intel Ivy Bridge (MIVYBRIDGE)" + infoe "25. Intel Haswell (MHASWELL)" + infoe "26. Intel Broadwell (MBROADWELL)" + infoe "27. Intel Skylake (MSKYLAKE)" + infoe "28. Intel Skylake X (MSKYLAKEX)" + infoe "29. Intel Cannon Lake (MCANNONLAKE)" + infoe "30. Intel Ice Lake (MICELAKE)" + infoe "31. Intel Cascade Lake (MCASCADELAKE)" + infoe "32. Intel Cooper Lake (MCOOPERLAKE)" + infoe "33. Intel Tiger Lake (MTIGERLAKE)" + infoe "34. Intel Sapphire Rapids (MSAPPHIRERAPIDS)" + infoe "35. Intel Rocket Lake (MROCKETLAKE)" + infoe "36. Intel Alder Lake (MALDERLAKE)" + infoe "37. Intel Raptor Lake (MRAPTORLAKE)" + infoe "38. Intel Meteor Lake (MMETEORLAKE)" + infoe "39. Intel Emerald Rapids (MEMERALDRAPIDS)" + infoe "40. Generic-x86-64 (GENERIC_CPU)" + infoe "41. Generic-x86-64-v2 (GENERIC_CPU2)" + infoe "42. Generic-x86-64-v3 (GENERIC_CPU3)" + infoe "43. Generic-x86-64-v4 (GENERIC_CPU4)" + infoe "44. Intel-Native optimizations autodetected by the compiler (MNATIVE_INTEL)" + infoe "45. AMD-Native optimizations autodetected by the compiler (MNATIVE_AMD)" read -rp ":: Which sub architecture do you want to build Linux for (see above, enter 40 if unsure) [40]? " BUILDTOOL_SUBARCHITECTURE case "${BUILDTOOL_SUBARCHITECTURE}" in "") export "BUILDTOOL_PKGBUILD_SUBARCHITECTURE=_subarch=40" ;; *[!0-9]*) - echo ":: Error: Invalid subarchitecture" + errorh "Invalid subarchitecture" ask_subarchitecture return 1 ;; *) if [ ! "${BUILDTOOL_SUBARCHITECTURE}" -gt 0 ] || [ ! "${BUILDTOOL_SUBARCHITECTURE}" -lt 46 ]; then - echo ":: Error: Invalid subarchitecture." + errorh "Invalid subarchitecture" ask_subarchitecture else export "BUILDTOOL_PKGBUILD_SUBARCHITECTURE=_subarch=${BUILDTOOL_SUBARCHITECTURE}" @@ -226,7 +268,7 @@ function ask_subarchitecture() { } ## Ask for kernel debug mode function ask_debug() { - read -rp ":: Do you want to enable kernel debug mode [y/N/i(gnore)]? " BUILDTOOL_DEBUG + read -rp "$(infoh "Do you want to enable kernel debug mode [y/N/i(gnore)]? ")" BUILDTOOL_DEBUG case "${BUILDTOOL_DEBUG}" in "y"|"Y") export "BUILDTOOL_PKGBUILD_DEBUG=_debug=y" @@ -238,7 +280,7 @@ function ask_debug() { export "BUILDTOOL_PKGBUILD_DEBUG=_debug=" ;; *) - echo "Invalid answer. Please answer with Y, N or I." + errorh "Invalid answer. Please answer with Y, N or I" ask_debug esac } @@ -247,21 +289,21 @@ function ask_clonedir_conflictresolution() { if [ ! -d "${BUILDTOOL_CLONEDIR}" ]; then return elif [ -a "${BUILDTOOL_CLONEDIR}" ] && [ ! -d "${BUILDTOOL_CLONEDIR}" ]; then - echo ":: Warning: Something that isn't a directory exists at location \"${BUILDTOOL_CLONEDIR}\"" + warnh "Something that isn't a directory exists at location \"${BUILDTOOL_CLONEDIR}\"" fi - read -rp ":: Warning: \"${BUILDTOOL_CLONEDIR}\" already exists. What should be done to resolve the conflict [A(bort)/r(ecompile)/f(resh)]? " BUILDTOOL_CLONEDIR_CONFLICT + read -rp "$(infoh "Warning: \"${BUILDTOOL_CLONEDIR}\" already exists. What should be done to resolve the conflict [A(bort)/r(ecompile)/f(resh)]? ")" BUILDTOOL_CLONEDIR_CONFLICT case "${BUILDTOOL_CLONEDIR_CONFLICT}" in "a"|"A"|"") - echo ":: Error: Conflict resolution failed." + errorh "Conflict resolution failed" exit 1 ;; "r"|"R") ;; "f"|"F") - echo ":: Removing existing \$BUILDTOOL_CLONEDIR directory" + infoh "Removing existing \$BUILDTOOL_CLONEDIR directory" #rm -rf "${BUILDTOOL_CLONEDIR}" ;; *) - echo "Invalid answer. Please answer with Y, N or I." + errorh "Invalid answer. Please answer with Y, N or I." ask_debug esac } @@ -278,45 +320,45 @@ ask_clonedir_conflictresolution # Pre-building ## Install dependencies -echo ":: Installing dependencies" +infoh "Installing dependencies" if ! sudo pacman -Syu --asdeps --needed ${BUILDTOOL_PACKAGES}; then - echo ":: Error: Installing dependencies failed: pacman returned with non-zero exit code" + errorh "Installing dependencies failed: pacman returned with non-zero exit code" exit 1 fi if ! rustup default nightly; then - echo ":: Error: Installing dependencies failed: rustup returned with non-zero exit code" + errorh "Installing dependencies failed: rustup returned with non-zero exit code" exit 1 fi ## Adjust cpu governor case "${BUILDTOOL_CPUPOWER}" in "y"|"Y"|"") - echo ":: Adjusting cpu governor" + infoh "Adjusting cpu governor" if ! sudo cpupower frequency-set -g performance; then - echo ":: Error: Adjusting cpu governor failed: cpupower returned with non-zero exit code" + errorh "Adjusting cpu governor failed: cpupower returned with non-zero exit code" return 1 fi ;; "n"|"N") ;; *) - echo ":: Error: Internal inconsistency detected: Value of \$BUILDTOOL_CPUPOWER is not a valid boolean answer" + errorh "Internal inconsistency detected: Value of \$BUILDTOOL_CPUPOWER is not a valid boolean answer" exit 2 ;; esac # Clone repository -echo ":: Cloning repository" +infoh "Cloning repository" git clone "${BUILDTOOL_REPOSITORY}" "${BUILDTOOL_CLONEDIR}" cd "${BUILDTOOL_CLONEDIR}" # Print debug information if [ "${BUILDTOOL_DEBUG}" == "true" ]; then - echo ":: Printing debug information" - echo "++ env ++" + infoh "Printing debug information" + echo "+++ env +++" env|grep "BUILDTOOL_"|sort - echo "++ env ++" + echo "+++ env +++" echo "build cmdline: ${BUILDTOOL_BUILDCMDLINE} "${BUILDTOOL_PKGBUILD_XCONFIG}" "${BUILDTOOL_PKGBUILD_NCONFIG}" "${BUILDTOOL_PKGBUILD_CPFINALCONFIG}" "${BUILDTOOL_PKGBUILD_MODPROBEDDB}" "${BUILDTOOL_PKGBUILD_SUBARCHITECTURE}" "${BUILDTOOL_PKGBUILD_DEBUG}" makepkg --syncdeps -p PKGBUILD.buildtool" fi -# Build kernel -echo ":: Building kernel" ${BUILDTOOL_BUILDCMDLINE} "${BUILDTOOL_PKGBUILD_XCONFIG}" "${BUILDTOOL_PKGBUILD_NCONFIG}" "${BUILDTOOL_PKGBUILD_CPFINALCONFIG}" "${BUILDTOOL_PKGBUILD_MODPROBEDDB}" "${BUILDTOOL_PKGBUILD_SUBARCHITECTURE}" "${BUILDTOOL_PKGBUILD_DEBUG}" makepkg --syncdeps -p PKGBUILD.buildtool +# Build package +infoh "Building package"