..
   SPDX-License-Identifier: GPL-3.0-only
   This file is part of Lazuli.

.. sectionauthor::
   Copyright (c) 2020, Remi Andruccioli <remi.andruccioli@gmail.com>

Developing your project
=======================

Your application code
---------------------

At the root of the repository is a directory named ``user``.
This is where your own source code will go.
A default file named ``main.c`` is provided.
If you need to add more source files to your project, you must declare them
in the file ``CMakeLists.txt`` at the root of the repository: you will add your
files to the list named ``LAZULI_USER_SOURCE_FILES``.

Building
---------

The next step is to build your project.

The Lazuli kernel itself is not executable.
It is developed as a static library that your own program will link against at
compile time. This is why the ``main`` function that you can see in the file
``main.c`` is the *real* main function of the final program.



The whole Lazuli project relies on CMake for configuration and compilation.
As Lazuli is designed to be cross platform and configurable, we will explain
here how to configure CMake to your specific project before building it.

Configuration
^^^^^^^^^^^^^

The first step is to make CMake generate the appropriate cross compilation
toolchain for your project. This toolchain depends on the target platform.

We will do that in an interactive fashion using the tool ``ccmake``.
It is recommended that you perform these operations in the Lazuli container.

We first create and browse the directory ``build`` which is the destination
directory of build artefacts, and we invoke ``cmake`` by pointing to the root
``CMakeFile.txt``

.. code-block:: console

    [root@6bf01305461f workspace]# mkdir build && cd build
    [root@6bf01305461f build]# cmake ..
    CMake Error at sys/cmake/machine_choice.cmake:23 (message):
    Configuration error: The target machine must be defined with cache variable
    'LZ_TARGET_MACHINE_CHOICE'.
    Call Stack (most recent call first):
    sys/CMakeLists.txt:23 (include)


    -- Configuring incomplete, errors occurred!
    [root@6bf01305461f build]#

This results in an error because the build system doesn't kow yet what is the
target platform. We will fix this using ``ccmake``, a console tool used to
configure cmake cache:

.. code-block:: console

    [root@6bf01305461f build]# ccmake .


ccmake only displays one configuration variable, LZ_TARGET_MACHINE_CHOICE,
by hitting ENTER (RETURN) will cycle through the supported platforms.

.. code-block:: console

                                                        Page 1 of 1
    LZ_TARGET_MACHINE_CHOICE

















    LZ_TARGET_MACHINE_CHOICE: Choice of the target machine.
    Keys: [enter] Edit an entry [d] Delete an entry             CMake Version 3.17.2
        [l] Show log output   [c] Configure
        [h] Help              [q] Quit without generating
        [t] Toggle advanced mode (currently off)


For now, only AVR_ATmega328p is supported.

.. code-block:: console

                                                        Page 1 of 1
    LZ_TARGET_MACHINE_CHOICE         AVR_ATmega328p

















    LZ_TARGET_MACHINE_CHOICE: Choice of the target machine.
    Keys: [enter] Edit an entry [d] Delete an entry             CMake Version 3.17.2
        [l] Show log output   [c] Configure
        [h] Help              [q] Quit without generating
        [t] Toggle advanced mode (currently off)


We can now ask CMake to configure the cross-compilation toolchain, hitting ``c``:

.. code-block:: console


    The C compiler identification is GNU 9.2.0
    The ASM compiler identification is GNU
    Found assembler: /usr/bin/avr-gcc
    Check for working C compiler: /usr/bin/avr-gcc
    Check for working C compiler: /usr/bin/avr-gcc - works
    Detecting C compiler ABI info
    Detecting C compiler ABI info - done
    Detecting C compile features
    Detecting C compile features - done
    Using module: module_version_string
    Configuring done








    Configure produced the following output
                                                                CMake Version 3.17.2
    Press [e] to exit screen



After exiting this screen by hitting ``e``, ccmake now displays all the
available configuration variables for the toolchain it created:

.. code-block:: console

                                                        Page 1 of 3
    AVR_AR                          */usr/bin/avr-ar
    AVR_CC                          */usr/bin/avr-gcc
    AVR_NM                          */usr/bin/avr-nm
    AVR_OBJCOPY                     */usr/bin/avr-objcopy
    AVR_OBJDUMP                     */usr/bin/avr-objdump
    CMAKE_BUILD_TYPE                *
    CMAKE_INSTALL_PREFIX            */usr/local
    CMAKE_TOOLCHAIN_FILE            */~/workspace/sys/cmake/avr.toolchain.cmake
    LZ_CONFIG_AVR_INSTRUMENT_PORT   *0x2B
    LZ_CONFIG_BREAK_STACK_GAP       *50
    LZ_CONFIG_CHECK_INTERRUPT_CODE  *ON
    LZ_CONFIG_CHECK_NULL_PARAMETER  *ON
    LZ_CONFIG_CHECK_NULL_PARAMETER  *ON
    LZ_CONFIG_CHECK_NULL_PARAMETER  *ON
    LZ_CONFIG_CHECK_NULL_PARAMETER  *ON
    LZ_CONFIG_CHECK_WRONG_ENUM_ENT  *ON
    LZ_CONFIG_DEFAULT_TASK_PRIORIT  *0

    AVR_AR: Path to a program.
    Keys: [enter] Edit an entry [d] Delete an entry             CMake Version 3.17.2
        [l] Show log output   [c] Configure
        [h] Help              [q] Quit without generating
        [t] Toggle advanced mode (currently off)


You can configure these variables according to your needs and hit ``c`` again:

.. code-block:: console

    Using module: module_version_string
    Configuring done

















    Configure produced the following output
                                                                CMake Version 3.17.2
    Press [e] to exit screen

After hitting ``e``, you can now generate the full configured toolchain and exit
by hitting ``g``. You can then return to the workspace:

.. code-block:: console

    [root@6bf01305461f build]# cd ..
    [root@6bf01305461f workspace]#


Note that if you already know your target platform,
the cross compilation toolchain can be generated by doing only:

.. code-block:: console

    [root@6bf01305461f workspace]# cmake -S . -B ./build -DLZ_TARGET_MACHINE_CHOICE=AVR_ATmega328p
    -- The C compiler identification is GNU 9.2.0
    -- The ASM compiler identification is GNU
    -- Found assembler: /usr/bin/avr-gcc
    -- Check for working C compiler: /usr/bin/avr-gcc
    -- Check for working C compiler: /usr/bin/avr-gcc - works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    Using module: module_version_string
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /~/workspace/build
    [root@6bf01305461f workspace]#


At any moment you can set configuration variables by invoking ccmake pointing
to the ``build`` directory:

.. code-block:: console

    [root@6bf01305461f workspace]# ccmake build/

Modules

Compilation
^^^^^^^^^^^

Compilation is quite straightforward. Simply invoke ``cmake`` with
``build`` option pointing to the ``build`` directory:

.. code-block:: console

    [root@6bf01305461f workspace]# cmake --build ./build
    Scanning dependencies of target module_version_string
    [  4%] Building C object sys/kern/modules/version_string/CMakeFiles/module_version_string.dir/version_string.c.obj
    [  4%] Built target module_version_string
    Scanning dependencies of target LazuliKernel_AVR_ATmega328p_0.1.0
    [  9%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/arch/AVR/arch.c.obj
    [ 13%] Building ASM object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/arch/AVR/interrupt_vectors_table.S.obj
    [ 18%] Building ASM object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/arch/AVR/startup.S.obj
    [ 22%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/arch/AVR/timer_counter_1.c.obj
    [ 27%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/kernel.c.obj
    [ 31%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/memory.c.obj
    [ 36%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/scheduler.c.obj
    [ 40%] Building C object sys/CMakeFiles/LazuliKernel_AVR_ATmega328p_0.1.0.dir/kern/list.c.obj
    [ 45%] Linking C static library libLazuliKernel_AVR_ATmega328p_0.1.0.a
    [ 45%] Built target LazuliKernel_AVR_ATmega328p_0.1.0
    Scanning dependencies of target LazuliUserProject_AVR_ATmega328p_1.0.0
    [ 50%] Building C object CMakeFiles/LazuliUserProject_AVR_ATmega328p_1.0.0.dir/user/main.c.obj
    [ 54%] Linking C executable LazuliUserProject_AVR_ATmega328p_1.0.0
    [ 54%] Built target LazuliUserProject_AVR_ATmega328p_1.0.0
    Scanning dependencies of target hex_output
    [ 59%] Generating user HEX file: LazuliUserProject_AVR_ATmega328p_1.0.0.hex
    [ 59%] Built target hex_output
    Scanning dependencies of target lst_ouput
    [ 63%] Generating user LST file: LazuliUserProject_AVR_ATmega328p_1.0.0.lst
    [ 63%] Built target lst_ouput
    Scanning dependencies of target kernel_lst_ouput
    [ 68%] Generating kernel LST file: LazuliKernel_AVR_ATmega328p_0.1.0.lst
    [ 68%] Built target kernel_lst_ouput
    Scanning dependencies of target module_clock_24
    [ 72%] Building C object sys/kern/modules/clock_24/CMakeFiles/module_clock_24.dir/clock_24.c.obj
    [ 72%] Built target module_clock_24
    Scanning dependencies of target module_mutex
    [ 77%] Building C object sys/kern/modules/mutex/CMakeFiles/module_mutex.dir/mutex.c.obj
    [ 81%] Building ASM object sys/kern/modules/mutex/CMakeFiles/module_mutex.dir/arch/AVR/mutex.S.obj
    [ 81%] Built target module_mutex
    Scanning dependencies of target module_serial
    [ 86%] Building C object sys/kern/modules/serial/CMakeFiles/module_serial.dir/serial.c.obj
    [ 90%] Building C object sys/kern/modules/serial/CMakeFiles/module_serial.dir/arch/AVR/usart.c.obj
    [ 90%] Built target module_serial
    Scanning dependencies of target module_spinlock
    [ 95%] Building C object sys/kern/modules/spinlock/CMakeFiles/module_spinlock.dir/spinlock.c.obj
    [100%] Building ASM object sys/kern/modules/spinlock/CMakeFiles/module_spinlock.dir/arch/AVR/spinlock.S.obj
    [100%] Built target module_spinlock
    [root@6bf01305461f workspace]#

You can notice that the build system builds all modules,
even those that are not used by your project.
However they are built *but not linked to your project*.
This is to ensure that code modifications made to the kernel doesn't break
integrity of the *whole kernel*, including modules.
