From 324d5e427c66f39848047cdededb583f667f0be2 Mon Sep 17 00:00:00 2001 From: Eric-Paul Ickhorn Date: Fri, 9 Feb 2024 16:12:06 +0100 Subject: [PATCH] Added build system --- .gitignore | 12 ++ action.bash | 236 ++++++++++++++++++++++++++++ build-config/modules.txt | 1 + core/build-config/include_paths.txt | 2 + core/build-config/tests.txt | 0 5 files changed, 251 insertions(+) create mode 100644 .gitignore create mode 100755 action.bash create mode 100644 build-config/modules.txt create mode 100644 core/build-config/include_paths.txt create mode 100644 core/build-config/tests.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d3c00bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ + +# Complete folders that are unwanted in commits +*.build/ +*.local/ +*.vscode/ + +# Machine Code +*.a +*.dll +*.elf +*.exe +*.so diff --git a/action.bash b/action.bash new file mode 100755 index 0000000..7b890f2 --- /dev/null +++ b/action.bash @@ -0,0 +1,236 @@ +#!/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 diff --git a/build-config/modules.txt b/build-config/modules.txt new file mode 100644 index 0000000..0f31176 --- /dev/null +++ b/build-config/modules.txt @@ -0,0 +1 @@ +core \ No newline at end of file diff --git a/core/build-config/include_paths.txt b/core/build-config/include_paths.txt new file mode 100644 index 0000000..c527a74 --- /dev/null +++ b/core/build-config/include_paths.txt @@ -0,0 +1,2 @@ +.build/depends/libRR/Core/core/exports +.build/depends/libRR/Core/platform/exports \ No newline at end of file diff --git a/core/build-config/tests.txt b/core/build-config/tests.txt new file mode 100644 index 0000000..e69de29