| .. _application: |
| |
| Application Development Primer |
| ############################## |
| |
| |
| Overview |
| ******** |
| The Zephyr Kernel's build system is based on the Kbuild system used in the |
| Linux kernel. |
| |
| The build system is an application-centric system and requires an application |
| build to initiate building the kernel source tree. The application build drives |
| the configuration and build process of both the application and kernel, |
| compiling them into a single binary. |
| |
| The Zephyr Kernel's base directory hosts the kernel source code, the |
| configuration options, and the kernel build definitions. |
| |
| The files in the application directory links the kernel with the |
| application. It hosts the definitions of the application, for example, |
| application-specific configuration options and the application's source code. |
| |
| An application in the simplest form has the following structure: |
| |
| * **Application source code files**: An application typically provides one |
| or more application-specific files, written in C or assembly language. These |
| files are usually located in a sub-directory called :file:`src`. |
| |
| * **Kernel configuration files**: An application typically provides |
| a configuration file (:file:`.conf`) that specifies values for one or more |
| kernel configuration options. If omitted, the application's existing kernel |
| configuration option values are used; if no existing values are provided, |
| the kernel's default configuration values are used. |
| |
| * **Makefile**: This file tells the build system where to find the files |
| mentioned above, as well as the desired target board configuration. |
| |
| Once the application has been defined, it can be built with a single ``make`` |
| call. |
| The results of the build process are located in a sub-directory called |
| :file:`outdir/BOARD`. This directory contains the files generated by the build |
| process, the most notable of which are listed below. |
| |
| * The :file:`.config` file that contains the configuration settings |
| used to build the application. |
| |
| * The various object files (:file:`.o` files and :file:`.a` files) containing |
| custom-built kernel and application-specific code. |
| |
| * The :file:`zephyr.elf` file that contains the final combined application and |
| kernel binary. |
| |
| |
| |
| Application Structure |
| ********************* |
| |
| |
| Create one directory for your application and a sub-directory for the |
| application's source code; this makes it easier to organize directories and |
| files in the structure that the kernel expects. |
| |
| #. Create an application directory structure outside of the kernel's |
| installation directory tree. Often this is your workspace directory. |
| |
| #. In a console terminal, navigate to a location where you want your |
| application to reside. |
| |
| #. Create the application's directory, enter: |
| |
| .. code-block:: console |
| |
| $ mkdir app |
| |
| .. note:: |
| |
| This directory and the path to it, are referred to in the documentation |
| as :file:`~/app`. |
| |
| #. Create a source code directory in your :file:`~/app`, enter: |
| |
| .. code-block:: console |
| |
| $ cd app |
| $ mkdir src |
| |
| The source code directory :file:`~/app/src` is created. |
| |
| .. code-block:: console |
| |
| -- app |
| |-- src |
| |
| |
| Application Definition |
| ********************** |
| |
| An application is integrated into the build system by including the Makefile.inc |
| file provided. |
| |
| .. code-block:: make |
| |
| include $(ZEPHYR_BASE)/Makefile.inc |
| |
| The following predefined variables configure the development project: |
| |
| * :makevar:`ZEPHYR_BASE`: Sets the path to the kernel's base directory. |
| This variable is usually set by the :file:`zephyr_env.sh` script. |
| It can be used to get the kernel's base directory, as used in the |
| Makefile.inc inclusion above, or it can be overridden to select an |
| specific instance of the kernel. |
| |
| * :makevar:`PROJECT_BASE`: Provides the developer's application project |
| directory path. It is set by the :file:`Makefile.inc` file. |
| |
| * :makevar:`SOURCE_DIR`: Overrides the default value for the application's |
| source code directory. The developer source code directory is set to |
| :file:`$(PROJECT_BASE/)src/` by default. This directory name should end |
| with slash **'/'**. |
| |
| * :makevar:`BOARD`: Selects the board that the application's |
| build will use for the default configuration. |
| |
| * :makevar:`CONF_FILE`: Indicates the name of a configuration fragment file. |
| This file includes the kconfig configuration values that override the |
| default configuration values. |
| |
| * :makevar:`O`: Optional. Indicates the output directory that Kconfig uses. |
| The output directory stores all the files generated during the build |
| process. The default output directory is the :file:`$(PROJECT_BASE)/outdir` |
| directory. |
| |
| |
| Makefiles |
| ********* |
| |
| Overview |
| ======== |
| |
| The build system defines a set of conventions for the correct use of Makefiles |
| in the kernel source directories. The correct use of Makefiles is driven by the |
| concept of recursion. |
| |
| In the recursion model, each Makefile within a directory includes the source |
| code and any subdirectories to the build process. Each subdirectory follows |
| the same principle. Developers can focus exclusively in their own work. They |
| integrate their module with the build system by adding a very simple Makefile |
| following the recursive model. |
| |
| .. _makefile_conventions: |
| |
| Makefile Conventions |
| ==================== |
| |
| The following conventions restrict how to add modules and Makefiles to the |
| build system. These conventions ensure the correct implementation of the |
| recursive model. |
| |
| * Each source code directory must contain a single Makefile. Directories |
| without a Makefile are not considered source code directories. |
| |
| * The scope of every Makefile is restricted to the contents of that directory. |
| A Makefile can only make a direct reference to files and subdirectories on the |
| same level or below. |
| |
| * Makefiles list the object files that are included in the link process. The |
| build system finds the source file that generates the object file by matching |
| the object file name to the source file. |
| |
| * Parent directories add their child directories into the recursion model. |
| |
| * The root Makefile adds the directories in the kernel base directory into the |
| recursion model. |
| |
| Adding Source Files |
| =================== |
| |
| The Makefile must refer the source build indirectly, specifying the object file |
| that results from the source file using the :literal:`obj-y` variable. For |
| example, if the file that we want to add is a C file named :file:`<file>.c` the |
| following line should be added in the Makefile: |
| |
| .. code-block:: make |
| |
| obj-y += <file>.o |
| |
| .. note:: |
| |
| The same method applies for assembly files with the .S extension. |
| |
| Source files can be added conditionally using configuration options. For |
| example, if the option ``CONFIG_VAR`` is set and it implies that a source |
| file must be added in the compilation process, then the following line adds the |
| source code conditionally: |
| |
| .. code-block:: none |
| |
| obj-$(CONFIG_VAR) += <file>.o |
| |
| Adding Directories |
| ================== |
| |
| Add a subdirectory to the build system by editing the Makefile in its |
| directory. The subdirectory is added using the :literal:`obj-y` variable. The |
| correct syntax to add a subdirectory into the build queue is: |
| |
| .. code-block:: make |
| |
| obj-y += <directory_name>/ |
| |
| The backslash at the end of the directory name signals the build system that a |
| directory, and not a file, is being added to the build queue. |
| |
| The conventions require us to add only one directory per line and never to mix |
| source code with directory recursion in a single :literal:`obj-y` line. This |
| helps keep the readability of the Makefile by making it clear when an item adds |
| an additional lever of recursion. |
| |
| Directories can also be conditionally added: |
| |
| .. code-block:: none |
| |
| obj-y-$(CONFIG_VAR) += <directory_name>/ |
| |
| The subdirectory must contain its own Makefile following the rules described in |
| :ref:`makefile_conventions`. |
| |
| |
| Application Makefile |
| ******************** |
| |
| Create an application Makefile to define basic information, such as the board |
| configuration used by the application. The build system uses the Makefile to |
| build a :file:`zephyr.elf` image that contains both the application and the |
| kernel libraries. |
| |
| #. Open the :file:`Makefile` and add the following mandatory |
| entries using any standard text editor. |
| |
| .. note:: |
| |
| Ensure that there is a space before and after each ``=``. |
| |
| #. Add the name of the default board configuration for your application on a |
| new line: |
| |
| .. code-block:: make |
| |
| BOARD = board_configuration_name |
| |
| The supported boards can be found in :ref:`boards`. |
| |
| #. Add the name of the default kernel configuration file for your |
| application on a new line: |
| |
| .. code-block:: make |
| |
| CONF_FILE ?= kernel_configuration_name |
| |
| #. Include the mandatory :file:`Makefile` on a new line: |
| |
| .. code-block:: make |
| |
| include ${ZEPHYR_BASE}/Makefile.inc |
| |
| #. Save and close the :file:`Makefile`. |
| |
| |
| Below is an example Makefile: |
| |
| .. code-block:: make |
| |
| BOARD = qemu_x86 |
| CONF_FILE = prj.conf |
| |
| include ${ZEPHYR_BASE}/Makefile.inc |
| |
| Application Configuration |
| ************************* |
| |
| The application's kernel is configured using a set of configuration options |
| that can be customized for application-specific purposes. |
| The Zephyr build system takes a configuration option's value from the first |
| source in which it is specified. |
| |
| The available sources are (in order): |
| |
| #. The application's current configuration. (i.e. The :file:`.config` file.) |
| |
| #. The application's default configuration. (i.e. The :file:`.conf` file.) |
| |
| #. The board configuration used by the application. |
| (i.e. The board's :file:`.defconfig` file.) |
| |
| #. The kernel's default configuration. |
| (i.e. One of the kernel's :file:`Kconfig` files.) |
| |
| For information on available kernel configuration options, including |
| inter-dependencies between options, see the :ref:`configuration`. |
| |
| Default Board Configuration |
| =========================== |
| |
| An application's :file:`.conf` file defines its default kernel configuration. |
| The settings in this file override or augment the board configuration settings. |
| |
| The board configuration settings can be viewed |
| in :file:`\$ZEPHYR_BASE/boards/ARCHITECTURE/BOARD/BOARD_defconfig`. |
| |
| .. note:: |
| |
| When the default board configuration settings are sufficient for your |
| application, a :file:`.conf` file is not needed. Skip ahead to |
| :ref:`override_kernel_conf`. |
| |
| |
| #. Navigate to the :file:`app`, and create the :file:`prj.conf` file. Enter: |
| |
| .. code-block:: bash |
| |
| $ vim prj.conf |
| |
| The default name is :file:`prj.conf`. The filename must match the |
| ``CONF_FILE`` entry in the application :file:`Makefile`. |
| |
| #. Edit the file and add the appropriate configuration entries. |
| |
| a) Add each configuration entry on a new line. |
| |
| b) Begin each entry with ``CONFIG_``. |
| |
| c) Ensure that each entry contains no spaces |
| (including on either side of the = sign). |
| |
| d) Use a # followed by a space to comment a line. |
| |
| The example below shows a comment line and a board |
| configuration override in the :file:`prj.conf`. |
| |
| .. code-block:: c |
| |
| # Enable printk for debugging |
| CONFIG_PRINTK=y |
| |
| #. Save and close the file. |
| |
| .. _override_kernel_conf: |
| |
| Overriding Default Configuration |
| ================================ |
| |
| Override the default board and kernel configuration to temporarily alter the |
| application's configuration, perhaps to test the effect of a change. |
| |
| .. note:: |
| |
| If you want to permanently alter the configuration you |
| should revise the :file:`.conf` file. |
| |
| Configure the kernel options using a menu-driven interface. While you can add |
| entries manually, using the configuration menu is a preferred method. |
| |
| |
| #. Run the :command:`make menuconfig` rule to launch the menu-driven interface. |
| |
| a) In a terminal session, navigate to the application directory |
| (:file:`~/app`). |
| |
| b) Enter the following command: |
| |
| .. code-block:: bash |
| |
| $ make [BOARD=<type>] menuconfig |
| |
| A question-based menu opens that allows you to set individual configuration |
| options. |
| |
| .. image:: figures/app_kernel_conf_1.png |
| :width: 600px |
| :align: center |
| :alt: Main Configuration Menu |
| |
| #. Set kernel configuration values using the following |
| key commands: |
| |
| * Use the arrow keys to navigate within any menu or list. |
| |
| * Press :kbd:`Enter` to select a menu item. |
| |
| * Type an upper case :kbd:`Y` or :kbd:`N` in the |
| square brackets :guilabel:`[ ]` to |
| enable or disable a kernel configuration option. |
| |
| * Type a numerical value in the round brackets :guilabel:`( )`. |
| |
| * Press :kbd:`Tab` to navigate the command menu at the bottom of the display. |
| |
| .. note:: |
| |
| When a non-default entry is selected for options that are nonnumerical, |
| an asterisk :kbd:`*` appears between the square brackets in the display. |
| There is nothing added added the display when you select the option's |
| default. |
| |
| #. For information about any option, select the option and tab to |
| :guilabel:`<Help >` and press :kbd:`Enter`. |
| |
| Press :kbd:`Enter` to return to the menu. |
| |
| #. After configuring the kernel options for your application, tab to |
| :guilabel:`< Save >` and press :kbd:`Enter`. |
| |
| The following dialog opens with the :guilabel:`< Ok >` command selected: |
| |
| .. image:: figures/app_kernel_conf_2.png |
| :width: 400px |
| :align: center |
| :height: 100px |
| :alt: Save Configuration Dialog |
| |
| |
| #. Press :kbd:`Enter` to save the kernel configuration options to the default |
| file name; alternatively, type a file name and press :kbd:`Enter`. |
| |
| Typically, you will save to the default file name unless you are |
| experimenting with various configuration scenarios. |
| |
| An :file:`outdir` directory is created in the application directory. The |
| outdir directory contains symbolic links to files under |
| :file:`\$ZEPHYR_BASE`. |
| |
| .. note:: |
| |
| At present, only a :file:`.config` file can be built. If you have saved |
| files with different file names and want to build with one of these, |
| change the file name to :file:`.config`. To keep your original |
| :file:`.config`, rename it to something other than :file:`.config`. |
| |
| Kernel configuration files, such as the :file:`.config` file, are saved |
| as hidden files in :file:`outdir`. To list all your kernel configuration |
| files, enter :command:`ls -a` at the terminal prompt. |
| |
| The following dialog opens, displaying the file name the configuration |
| was saved to. |
| |
| .. image:: figures/app_kernel_conf_3.png |
| :width: 400px |
| :align: center |
| :height: 150px |
| :alt: Saved Configuration Name Dialog |
| |
| #. Press :kbd:`Enter` to return to the options menu. |
| |
| #. To load any saved kernel configuration file, tab to :guilabel:`< Load >` and |
| press :kbd:`Enter`. |
| |
| The following dialog opens with the :guilabel:`< Ok >` command selected: |
| |
| .. image:: figures/app_kernel_conf_4.png |
| :width: 400px |
| :align: center |
| :height: 175px |
| :alt: Configuration File Load Dialog |
| |
| #. To load the last saved kernel configuration file, press :guilabel:`< Ok >`, |
| or to load another saved configuration file, type the file name, then select |
| :guilabel:`< Ok >`. |
| |
| #. Press :kbd:`Enter` to load the file and return to the main menu. |
| |
| #. To exit the menu configuration, tab to :guilabel:`< Exit >` and press |
| :kbd:`Enter`. |
| |
| The following confirmation dialog opens with the :guilabel:`< Yes >` |
| command selected. |
| |
| .. image:: figures/app_kernel_conf_5.png |
| :width: 400px |
| :align: center |
| :height: 100px |
| :alt: Exit Dialog |
| |
| #. Press :kbd:`Enter` to retire the menu display and return to the console |
| command line. |
| |
| Application-Specific Code |
| ************************* |
| |
| Application-specific source code files are normally added to the application's |
| :file:`src` directory. If the application adds a large number of files the |
| developer can group them into sub-directories under :file:`src`, to whatever |
| depth is needed. The developer must supply a :file:`Makefile` for the |
| :file:`src` directory, as well as for each sub-directory under :file:`src`. |
| |
| .. note:: |
| |
| These Makefiles are distinct from the top-level application Makefile |
| that appears in :file:`~/app`. |
| |
| Application-specific source code should not use symbol name prefixes that have |
| been reserved by the kernel for its own use. For more information, see |
| |
| `Naming Conventions <https://wiki.zephyrproject.org/view/Coding_conventions#Naming_Conventions>`_. |
| |
| |
| The following requirements apply to all Makefiles in the :file:`src` |
| directory, including any sub-directories it may have. |
| |
| * During the build process, Kbuild identifies the source files to compile |
| into object files by matching the file names identified in |
| the application's Makefile(s). |
| |
| .. important:: |
| |
| A source file that is not referenced by any Makefile is not included |
| when the application is built. |
| |
| * A Makefile cannot directly reference source code. It can only |
| reference object files (:file:`.o` files) produced from source code files. |
| |
| * A Makefile can only reference files in its own directory or in the |
| sub-directories of that directory. |
| |
| * A Makefile may reference multiple files from a single-line entry. |
| However, a separate line must be used to reference each directory. |
| |
| |
| |
| #. Create a directory structure for your source code in :file:`src` |
| and add your source code files to it. |
| |
| #. Create a :file:`Makefile` in the :file:`src` directory. Then create |
| an additional :file:`Makefile` in each of the sub-directories under |
| the :file:`src` directory, if any. |
| |
| a) Use the following syntax to add file references: |
| |
| .. code-block:: make |
| |
| obj-y += file1.o file2.o |
| |
| b) Use the following syntax to add directory references: |
| |
| .. code-block:: make |
| |
| obj-y += directory_name/** |
| |
| |
| This example is taken from the Philosopher's Sample. To examine this file in |
| context, navigate to: :file:`\$ZEPHYR_BASE/samples/philosophers/src`. |
| |
| .. code-block:: make |
| |
| obj-y = main.o |
| |
| |
| |
| Build an Application |
| ******************** |
| |
| The Zephyr build system compiles and links all components of an application |
| into a single application image that can be run on simulated hardware or real |
| hardware. |
| |
| |
| #. Navigate to the application directory :file:`~/app`. |
| |
| #. Enter the following command to build the application's :file:`zephyr.elf` |
| image using the configuration settings for the board type specified |
| in the application's :file:`Makefile`. |
| |
| .. code-block:: console |
| |
| $ make |
| |
| If desired, you can build the application using the configuration settings |
| specified in an alternate :file:`.conf` file using the :code:`CONF_FILE` |
| parameter. These settings will override the settings in the application's |
| :file:`.config` file or its default :file:`.conf` file. For example: |
| |
| .. code-block:: console |
| |
| $ make CONF_FILE=prj.alternate.conf |
| |
| If desired, you can build the application for a different board type than the |
| one specified in the application's :file:`Makefile` using the :code:`BOARD` |
| parameter. For example: |
| |
| .. code-block:: console |
| |
| $ make BOARD=arduino_101 |
| |
| Both the :code:`CONF_FILE` and :code:`BOARD` parameters can be specified |
| when building the application. |
| |
| Rebuilding an Application |
| ************************* |
| |
| Application development is usually fastest when changes are continually tested. |
| Frequently rebuilding your application makes debugging less painful |
| as the application becomes more complex. It's usually a good idea to |
| rebuild and test after any major changes to the application's source files, |
| Makefiles, or configuration settings. |
| |
| .. important:: |
| |
| The Zephyr build system rebuilds only the parts of the application image |
| potentially affected by the changes. Consequently, rebuilding an application |
| is often significantly faster than building it the first time. |
| |
| Sometimes the build system doesn't rebuild the application correctly |
| because it fails to recompile one or more necessary files. You can force |
| the build system to rebuild the entire application from scratch with the |
| following procedure: |
| |
| |
| #. Navigate to the application directory :file:`~/app`. |
| |
| #. Enter the following command to delete the application's generated files |
| for the specified board type, except for the :file:`.config` file that |
| contains the application's current configuration information. |
| |
| .. code-block:: console |
| |
| $ make [BOARD=<type>] clean |
| |
| Alternatively, enter the following command to delete *all* generated files |
| for *all* board types, including the :file:`.config` files that contain |
| the application's current configuration information for those board types. |
| |
| .. code-block:: console |
| |
| $ make pristine |
| |
| #. Rebuild the application normally following the steps specified |
| in `Build an Application`_ above. |
| |
| |
| |
| Run an Application |
| ****************** |
| |
| An application image can be run on real or emulated hardware. The kernel has |
| built-in emulator support for QEMU. It allows you to run and test an application |
| virtually, before (or in lieu of) loading and running it on actual target |
| hardware. |
| |
| #. Open a terminal console and navigate to the application directory |
| :file:`~/app`. |
| |
| #. Enter the following command to build and run the application |
| using a QEMU-supported board configuration, such as qemu_cortex_m3 or |
| qemu_x86. |
| |
| .. code-block:: console |
| |
| $ make [BOARD=<type> ...] run |
| |
| The Zephyr build system generates a :file:`zephyr.elf` image file |
| and then begins running it in the terminal console. |
| |
| #. Press :kbd:`Ctrl A, X` to stop the application from running |
| in QEMU. |
| |
| The application stops running and the terminal console prompt |
| redisplays. |
| |
| Application Debugging |
| ********************* |
| |
| This section is a quick hands-on reference to start debugging your |
| application with QEMU. Most content in this section is already covered on |
| `QEMU`_ and `GNU_Debugger`_ reference manuals. |
| |
| .. _QEMU: http://wiki.qemu.org/Main_Page |
| |
| .. _GNU_Debugger: http://www.gnu.org/software/gdb |
| |
| In this quick reference you find shortcuts, specific environmental variables and |
| parameters that can help you to quickly set up your debugging environment. |
| |
| The simplest way to debug an application running in QEMU is using the GNU |
| Debugger and setting a local GDB server in your development system through QEMU. |
| |
| You will need an ELF binary image for debugging purposes. The build system |
| generates the image in the output directory. By default, the kernel binary name |
| is :file:`zephyr.elf`. The name can be changed using a Kconfig option. |
| |
| We will use the standard 1234 TCP port to open a :abbr:`GDB (GNU Debugger)` |
| server instance. This port number can be changed for a port that best suits the |
| development environment. |
| |
| You can run Qemu to listen for a "gdb connection" before it starts executing any |
| code to debug it. |
| |
| .. code-block:: bash |
| |
| qemu -s -S <image> |
| |
| will setup Qemu to listen on port 1234 and wait for a GDB connection to it. |
| |
| The options used above have the following meaning: |
| |
| * ``-S`` Do not start CPU at startup; rather, you must type 'c' in the |
| monitor. |
| * ``-s`` Shorthand for :literal:`-gdb tcp::1234`: open a GDB server on |
| TCP port 1234. |
| |
| To debug with QEMU and to start a GDB server and wait for a remote connect, run |
| the following inside an application: |
| |
| .. code-block:: bash |
| |
| make BOARD=qemu_x86 debugserver |
| |
| The build system will start a QEMU instance with the CPU halted at startup |
| and with a GDB server instance listening at the TCP port 1234. |
| |
| Using a local GDB configuration :file:`.gdbinit` can help initialize your GDB |
| instance on every run. |
| In this example, the initialization file points to the GDB server instance. |
| It configures a connection to a remote target at the local host on the TCP |
| port 1234. The initialization sets the kernel's root directory as a |
| reference. |
| |
| The :file:`.gdbinit` file contains the following lines: |
| |
| .. code-block:: bash |
| |
| target remote localhost:1234 |
| dir ZEPHYR_BASE |
| |
| .. note:: |
| |
| Substitute ZEPHYR_BASE for the current kernel's root directory. |
| |
| Execute the application to debug from the same directory that you chose for |
| the :file:`gdbinit` file. The command can include the ``--tui`` option |
| to enable the use of a terminal user interface. The following commands |
| connects to the GDB server using :file:`gdb`. The command loads the symbol |
| table from the elf binary file. In this example, the elf binary file name |
| corresponds to :file:`zephyr.elf` file: |
| |
| .. code-block:: bash |
| |
| $ gdb --tui zephyr.elf |
| |
| .. note:: |
| |
| The GDB version on the development system might not support the --tui |
| option. |
| |
| If you are not using a .gdbinit file, issue the following command inside GDB to |
| connect to the remove GDB server on port 1234: |
| |
| .. code-block:: bash |
| |
| (gdb) target remote localhost:1234 |
| |
| Finally, The command below connects to the GDB server using the Data |
| Displayer Debugger (:file:`ddd`). The command loads the symbol table from the |
| elf binary file, in this instance, the :file:`zephyr.elf` file. |
| |
| The :abbr:`DDD (Data Displayer Debugger)` may not be installed in your |
| development system by default. Follow your system instructions to install |
| it. |
| |
| .. code-block:: bash |
| |
| ddd --gdb --debugger "gdb zephyr.elf" |
| |
| |
| Both commands execute the :abbr:`gdb (GNU Debugger)`. The command name might |
| change depending on the toolchain you are using and your cross-development |
| tools. |