#!/usr/bin/env bash cd $(dirname "$(pwd)/$0") REPOSITORY_FOLDER=$(pwd) PROJECT_NAME="maintree" DEBUG_CC_OPTIONS="-g3 -Wall -Wextra -Wpedantic" RELEASE_CC_OPTIONS="-O3 -Wall" MAIN_OBJECTS_FOLDER="$REPOSITORY_FOLDER/.build/objects" CONFIG_FILE_INCLUDE_PATHS="build-config/include_paths.txt" function clone_dependencies { echo "================ Cloning Dependencies! ================" mkdir -p .build/depends/libRR cd .build/depends/libRR/ if [[ -d "Core" ]] then rm -rf Core fi git clone --depth=1 https://git.nerdcult.net/libRR/Core/ cd "$REPOSITORY_FOLDER" } function build_dependencies { echo "================ Building Dependencies! ================" mkdir -p "$REPOSITORY_FOLDER/.build/output" cd .build/depends/libRR/Core/ bash build.bash release cp .build/librr-core.a "$REPOSITORY_FOLDER/.build" cp .build/librr-platform.a "$REPOSITORY_FOLDER/.build" cd "$REPOSITORY_FOLDER" } function get_include_path_configuration { MODULE_NAME=$1 INCLUDE_CONFIG_PATH="$REPOSITORY_FOLDER/$MODULE_NAME/$CONFIG_FILE_INCLUDE_PATHS" INCLUDE_STATEMENTS="-I $REPOSITORY_FOLDER/$MODULE_NAME/inc-c/" if [[ ! -f $INCLUDE_CONFIG_PATH ]] then return fi for LINE in $(cat $INCLUDE_CONFIG_PATH) do INCLUDE_STATEMENTS="$INCLUDE_STATEMENTS -I $REPOSITORY_FOLDER/$LINE" done } function generate_object_name { INPUT_NAME=$1 NUM_SUBPATHS=$(echo $INPUT_NAME | tr -cd "/" | wc -c) SANITIZED_INPUT_NAME=$(echo $INPUT_NAME | tr "/" "_") OBJECT_NAME="$NUM_SUBPATHS-$SANITIZED_INPUT_NAME.o" } function compile_module_c_sources { MODULE_NAME=$1 get_include_path_configuration $MODULE_NAME MODULE_SOURCE_PATH="$REPOSITORY_FOLDER/$MODULE_NAME/src-c" MODULE_OBJECTS_FOLDER="$MAIN_OBJECTS_FOLDER/$MODULE_NAME" rm -r $MODULE_OBJECTS_FOLDER mkdir -p $MODULE_OBJECTS_FOLDER # Loop through all files in the 'src-c'-folder and hand them over to GCC cd $MODULE_SOURCE_PATH MODULE_SOURCES=$(find . -mindepth 1) for SOURCE_FOLDER_ITEM in $MODULE_SOURCES do # Cut away the dot-slash given by 'find' as abbrevation for the working directory RELATIVE_SOURCE_PATH=$(echo $SOURCE_FOLDER_ITEM | cut -c "3-") # If this folder item is a folder, it must be created as an # output-folder for the object files to be placed in if [[ -d $RELATIVE_SOURCE_PATH ]] then mkdir -p "$MODULE_OBJECTS_FOLDER/$RELATIVE_SOURCE_PATH" continue fi # Check if this is a C source file by checking the last 2 characters (the ending), # and if it isn't, continue with the next file. LEN_SOURCE_FILE_NAME=${#RELATIVE_SOURCE_PATH} let PENULTIMATE_OFFSET=$LEN_SOURCE_FILE_NAME-1 LAST_2_CHARACTERS=$(echo $RELATIVE_SOURCE_PATH | cut -c "$PENULTIMATE_OFFSET-") if [[ $LAST_2_CHARACTERS != ".c" ]]; then continue; fi # Status Message echo "==> File: $RELATIVE_SOURCE_PATH" # Finally, call GCC to compile the C-file and let it place the file in the # objects folder or one of the possible subfolders which now could exist. generate_object_name $RELATIVE_SOURCE_PATH gcc -c $CC_OPTIONS -o \ "$MODULE_OBJECTS_FOLDER/$OBJECT_NAME" \ "$MODULE_SOURCE_PATH/$RELATIVE_SOURCE_PATH" \ $INCLUDE_STATEMENTS done ar -rvs $REPOSITORY_FOLDER/.build/$PROJECT_NAME-$MODULE_NAME.a $MODULE_OBJECTS_FOLDER/* cd $REPOSITORY_FOLDER } function get_linkage_path_configuration() { TEST_PATH=$1 LINKAGE_PATHS=$DEFAULT_LINKAGE_PATHS if [[ -f "$TEST_PATH/linkage_paths.txt" ]] then for LINKAGE_ITEM in $(cat "$TEST_PATH/linkage_paths.txt") do LINKAGE_PATHS="$LINKAGE_PATHS $REPOSITORY_FOLDER/$LINKAGE_ITEM" done fi } function compile_single_test() { TEST_PATH=$1 TEST_NAME=$(basename $TEST_PATH) echo "Compiling Test: $TEST_NAME" # TODO: As a small improvement, the tests could be able to have multiple sub-folders for sources. get_include_path_configuration $TEST_PATH get_linkage_path_configuration $TEST_PATH gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_STATEMENTS } function compile_all_tests_of_module() { MODULE_NAME=$1 echo "================================================================" echo "COMPILING ALL TESTS OF MODULE: '$MODULE_NAME'." echo " " TEST_PATH_LIST_PATH="$REPOSITORY_FOLDER/$MODULE_NAME/build-config/tests.txt" if [[ ! -f $TEST_PATH_LIST_PATH ]] then echo "Couldn't find list of tests for module '$MODULE_NAME'. Skipping." return fi for RELATIVE_TEST_PATH in $(cat $TEST_PATH_LIST_PATH) do TEST_PATH=$REPOSITORY_FOLDER/$MODULE_NAME/$RELATIVE_TEST_PATH compile_single_test $TEST_PATH done } function compile_all_tests_of_all_modules() { if [[ ! -f "build-config/modules.txt" ]] then echo "Failed compiling tests: Couldn't find 'build-config/modules.txt" return fi for MODULE in $(cat "build-config/modules.txt") do compile_all_tests_of_module $MODULE done } function compile_all_sources_of_all_modules() { if [[ ! -f "build-config/modules.txt" ]] then echo "Failed compiling sources: Couldn't find 'build-config/modules.txt" return fi for MODULE in $(cat "build-config/modules.txt") do compile_module_c_sources $MODULE done } function build_in_debug_profile { echo "================ Building in Debug Profile! ================" CC_OPTIONS=$DEBUG_CC_OPTIONS compile_all_sources_of_all_modules } function build_in_release_profile { echo "================ Building in Release Profile! ================" CC_OPTIONS=$RELEASE_CC_OPTIONS compile_all_sources_of_all_modules } case $1 in "d" | "dbg" | "debug") build_in_debug_profile ;; "r" | "release") build_in_release_profile ;; "c" | "clone-dependencies") clone_dependencies ;; "b" | "build-dependencies") build_dependencies ;; "t" | "build-tests") compile_all_tests_of_all_modules ;; "h" | "help") echo "Known Actions:" echo "[ d | dbg | debug ]: Build in the debug profile; build with debug symbols." echo "[ r | release ]: Build for a release, with speed optimizations." echo "[ c | clone-dependencies]: Clone the dependencies using Git (network required)." echo "[ b | build-dependencies]: Build the dependencies (which must have been cloned first!)." echo "[ h | help ]: Display this message." echo "" echo "Note: Before being able to build (debug-profile / release-profile), cloning and building the dependencies is required!" ;; *) echo "Unknown action, try '$0 help' or '$0 h'." ;; esac