treesls/chbuild

265 lines
6.6 KiB
Bash
Executable File

#!/bin/bash
set -e
self=$0
defconfig_command="$self defconfig"
clean_command="$self clean"
cmake_build_dir="build"
cmake_cache_file="build/CMakeCache.txt"
cmake_user_build_dir="user/build"
cmake_kernel_build_dir="kernel/build"
cmake_libc_build_dirs="user/musl-1.1.24/build user/musl-1.1.24/obj"
cmake_script_dir="scripts/build/cmake"
cmake_init_cache_default="$cmake_script_dir/LoadConfigDefault.cmake"
cmake_init_cache_ask="$cmake_script_dir/LoadConfigAsk.cmake"
cmake_init_cache_abort="$cmake_script_dir/LoadConfigAbort.cmake"
cmake_init_cache_dump="$cmake_script_dir/DumpConfig.cmake"
config_file=".config"
defconfig_dir="scripts/build/defconfigs"
RED='\033[0;31m'
BLUE='\033[0;34m'
GREEN='\033[0;32m'
ORANGE='\033[0;33m'
BOLD='\033[1m'
NONE='\033[0m'
_echo_info() {
echo -e "${BOLD}$@${NONE}"
}
_echo_succ() {
echo -e "${GREEN}${BOLD}$@${NONE}"
}
_echo_warn() {
echo -e "${ORANGE}${BOLD}$@${NONE}"
}
_echo_err() {
echo -e "${RED}${BOLD}$@${NONE}"
}
defconfig() {
if [ -d $cmake_build_dir ]; then
_echo_err "There exists a build directory, please run \`$clean_command\` first"
exit 1
fi
if [ -z "$1" ]; then
plat="raspi3"
else
plat="$1"
fi
_echo_info "Generating default config file for \`$plat\` platform..."
cp $defconfig_dir/${plat}.config $config_file
_config_default
_sync_config_with_cache
_echo_succ "Default config written to \`$config_file\` file."
}
_check_config_file() {
if [ ! -f $config_file ]; then
_echo_err "There is no \`.config\` file, please run \`$defconfig_command\` first"
exit 1
fi
}
_config_default() {
_echo_info "Configuring CMake..."
cmake -B $cmake_build_dir -C $cmake_init_cache_default
}
_config_ask() {
_echo_info "Configuring CMake..."
cmake -B $cmake_build_dir -C $cmake_init_cache_ask
}
_sync_config_with_cache() {
cmake -N -B $cmake_build_dir -C $cmake_init_cache_dump >/dev/null
}
config() {
_check_config_file
_config_ask
_sync_config_with_cache
_echo_succ "Config syned to \`$config_file\` file."
}
menuconfig() {
_check_config_file
_config_default
echo
_echo_warn "Note: In the menu config view, press C to save, Q to quit."
read -p "Now press Enter to continue..."
ccmake -B $cmake_build_dir
_sync_config_with_cache
_echo_succ "Config saved to \`$config_file\` file."
}
build() {
_check_config_file
_config_ask
_sync_config_with_cache
_echo_succ "Config syned to \`$config_file\` file."
if [ -z "$1" ]; then
build_target="all"
else
build_target="$1"
fi
_echo_info "Building..."
cmake --build $cmake_build_dir --target $build_target --parallel $(nproc)
if [ -z "$1" ]; then
_echo_succ "Succeeded to build all targets"
else
_echo_succ "Succeeded to build \`$build_target\`"
fi
}
clean() {
_echo_info "Cleaning..."
if [ -z "$1" ]; then
if [ -f $cmake_cache_file ]; then
rm -rf $cmake_build_dir
_config_default
cmake --build $cmake_build_dir --target clean-all
rm -rf $cmake_build_dir
_echo_succ "Succeeded to clean all targets"
elif [ -d $cmake_build_dir ]; then
rm -rf $cmake_build_dir $cmake_user_build_dir $cmake_kernel_build_dir $cmake_libc_build_dirs
_echo_warn "Succeeded to clean all targets, but some object files may be left"
else
_echo_info "Nothing to clean"
fi
else
if [ -f $cmake_cache_file ]; then
cmake --build $cmake_build_dir --target $1-clean
_echo_succ "Succeeded to clean \`$1\`"
else
_echo_err "Cannot clean \`$1\`, please try \`$self clean\` to clean all"
fi
fi
}
distclean() {
clean
_echo_info "Removing config file..."
rm -rf $config_file
_echo_succ "Succeeded to distclean"
}
_print_help() {
echo -e "\
${BOLD}USAGE:${NONE}
${BOLD}$self [options] [command]${NONE}
${BOLD}OPTIONS:${NONE}
${BOLD}--local, -l${NONE} run command in local environment (rather than docker)
${BOLD}COMMANDS:${NONE}
Local:
${BOLD}help, --help, -h${NONE} print this help text
${BOLD}update-submodules${NONE} update Git submodules according to config file
Local or Docker:
${BOLD}defconfig [platform]${NONE} generate default config (\`raspi3\` if \`platform\` is not specified)
${BOLD}config${NONE} run configuration step (interactively ask for config value if not set)
${BOLD}menuconfig${NONE} use TUI menu to edit config
${BOLD}build [target]${NONE} build the project (\`target\` can be \`libc\`, \`user\`, \`kernel\` or empty)
${BOLD}clean [target]${NONE} clean the project (\`target\` can be \`libc\`, \`user\`, \`kernel\` or empty)
${BOLD}distclean${NONE} clean the project and remove config file
"
}
_update_submodules() {
if [ -d $cmake_build_dir/local ]; then
rm -rf $cmake_build_dir/local
fi
_echo_info "Configuring CMake in local environment..."
cmake -B $cmake_build_dir/local -C $cmake_init_cache_abort
_echo_info "Updating Git submodules..."
cmake --build $cmake_build_dir/local --target update-submodules
rm -rf $cmake_build_dir/local
_echo_succ "Succeeded to update submodules"
}
_docker_run() {
if [ -f /.dockerenv ]; then
# we are already in docker container
$@
else
test -t 1 && use_tty="-t"
docker run -i $use_tty --rm \
-u $(id -u ${USER}):$(id -g ${USER}) \
-v $(pwd):/chos -w /chos \
promisivia/treesls_chcore_builder:v2.2 \
$self $@
fi
}
_main() {
run_in_docker=true
while [ $# -gt 0 ]; do
case $1 in
help | --help | -h)
_print_help
exit
;;
--local | -l)
run_in_docker=false
;;
-*)
_echo_err "$self: invalid option \`$1\`\n"
break
;;
update-submodules)
# need Git SSH key authentication, so must run in local env
_update_submodules
exit
;;
*)
if [[ "$1" == "_"* || $(type -t "$1") != function ]]; then
_echo_err "$self: invalid command \`$1\`\n"
break
fi
if [[ $run_in_docker == true ]]; then
_docker_run $@
else
$@
fi
exit
;;
esac
shift
done
# no command is run
_print_help
exit 1
}
_main $@