diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..021eb86 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + push: + paths-ignore: + - 'README.md' + workflow_dispatch: + schedule: + - cron: '20 16 * * *' + +# Set a new GitHub Actions Secret named IAR_LMS_BEARER_TOKEN +# for your repository. The secret is then propagated to an +# Environment variable used for all jobs within this workflow +env: + IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} + +# Set default permissions for the workflow jobs +permissions: + contents: read + +jobs: + tutorial: + name: Build tutorial + runs-on: ubuntu-24.04 + container: ghcr.io/iarsystems/arm + steps: + - name: Checkout project + uses: actions/checkout@v4 + + - name: CMake - Configure + working-directory: tutorial + run: cmake -GNinja -Bbuild + + - name: CMake - Build + working-directory: tutorial + run: cmake --build build --verbose diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..e82a44d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,45 @@ +name: Code Analysis + +on: + push: + paths-ignore: + - 'README.md' + workflow_dispatch: + schedule: + - cron: '30 16 * * *' + +# Set a new GitHub Actions Secret named IAR_LMS_BEARER_TOKEN +# for your repository. The secret is then propagated to an +# Environment variable used for all jobs within this workflow +env: + IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }} + +# Set default permissions for the workflow jobs +permissions: + contents: read + +jobs: + tutorial: + name: Analyze tutorial + runs-on: ubuntu-24.04 + container: ghcr.io/iarsystems/arm + permissions: + security-events: write + actions: read + contents: read + packages: read + steps: + - name: Checkout project + uses: actions/checkout@v4 + + - name: IAR C-STAT Static Analysis + working-directory: tutorial + run: | + ichecks --all --output checks.manifest + icstat --checks checks.manifest --db cstat.db --sarif_dir . analyze -- iccarm tutorial.c + + - name: Upload SARIF + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: tutorial/tutorial.c.sarif + category: cstat-analysis diff --git a/LICENSE b/LICENSE index 840297e..2babc71 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2024 IAR Systems AB +Copyright (c) 2020-2025 IAR Systems AB Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 56d6d56..7c2522c 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,21 @@ # Building CMake projects with IAR +[![CI](https://github.com/iarsystems/cmake-tutorial/actions/workflows/ci.yml/badge.svg)](https://github.com/iarsystems/cmake-tutorial/actions/workflows/ci.yml) [![Code Analysis](https://github.com/iarsystems/cmake-tutorial/actions/workflows/codeql.yml/badge.svg)](https://github.com/iarsystems/cmake-tutorial/actions/workflows/codeql.yml) + CMake is an open-source, cross-platform family of tools maintained and supported by Kitware. Among its many features, it essentially provides [Makefile Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#id11) and [Ninja Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#id12) which compose scripts for cross-compiling C/C++ embedded software projects based on one or more `CMakeLists.txt` configuration files. -This tutorial offers a short introduction for those seeking information on how to start using the IAR C/C++ Compiler together with CMake from the command line. While this guide is based on the IAR Build Tools for Arm version 9.50.1 on Linux, it should work with other supported IAR products with no or minimal changes. +This tutorial offers a short introduction for those seeking information on how to start using the IAR C/C++ Compiler together with CMake from the command line. While this guide is based on the IAR Build Tools for Arm (CXARM) 9.60.4 on Linux, it should work with other supported IAR products with no or minimal changes. ## Prerequisites Before you begin, you will need to download and install the IAR product, CMake and then clone this repository. 1) Download, install and activate[^1] your IAR product -| __Product__ | __Evaluation__ | __IAR Customers (login required)__ | -| - | - | - | -| IAR Build Tools | [Contact us](https://iar.com/about/contact) | [for Arm](https://updates.iar.com/?product=BXARM) (or for others[^2]) | -| IAR Embedded Workbench | [Download](https://www.iar.com/products/free-trials/) | [for Arm](https://updates.iar.com/?product=EWARM) (or for others[^2]) | +| Product | For Evaluation | For IAR Subscribers +| - | - | - +| IAR Build Tools (CX) ☁️ | [Contact us](https://iar.com/about/contact) | [for Arm](https://updates.iar.com/?product=CXARM) +| IAR Build Tools (BX) | [Contact us](https://iar.com/about/contact) | [for Arm](https://updates.iar.com/?product=BXARM)[^2] (or for others[^3]) +| IAR Embedded Workbench | [Try now](https://www.iar.com/embedded-development-tools/free-trials) | [for Arm](https://updates.iar.com/?product=EWARM)[^2] (or for others[^3]) 2) Download and install [CMake](https://github.com/Kitware/CMake/releases/latest). @@ -50,22 +53,24 @@ target_sources(tutorial PRIVATE tutorial.c) target_compile_options(tutorial PRIVATE --cpu=cortex-m4) # linker options -target_link_options(tutorial PRIVATE --semihosting) +target_link_options(tutorial PRIVATE + --cpu=cortex-m4 + --semihosting) ``` ### Enabling the IAR Compiler CMake uses the host platform's default compiler. When cross-compiling embedded applications, the compiler must be set manually via [`CMAKE__COMPILER`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_COMPILER.html) variables for each supported language. Additionally, it is possible to specify a build tool via [`CMAKE_MAKE_PROGRAM`](): -| Variable | Description | Examples | -| - | - | - | -| `CMAKE_C_COMPILER` | Must point to the C Compiler executable | `"C:/Program Files/..../arm/bin/iccarm.exe"`
`"/opt/iarsystems/bxarm/arm/bin/iccarm"` | -| `CMAKE_CXX_COMPILER` | Must point to the C++ Compiler executable | `"C:/Program Files/..../arm/bin/iccarm.exe"`
`"/opt/iarsystems/bxarm/arm/bin/iccarm"` | -| `CMAKE_ASM_COMPILER` | Must point to the Assembler executable | `"C:/Program Files/..../arm/bin/iasmarm.exe"`
`"/opt/iarsystems/bxarm/arm/bin/iasmarm"` | -| `CMAKE_MAKE_PROGRAM` | Must point to the build tool executable | `"C:/Program Files/..../common/bin/ninja.exe"`
`"/opt/iarsystems/bxarm/common/bin/ninja"` | +| Variable | Description | Examples (for Arm) +| - | - | - +| `CMAKE_C_COMPILER` | Must point to the C Compiler executable | `"/opt/iar/cxarm/arm/bin/iccarm"`
`"/opt/iarsystems/bxarm/arm/bin/iccarm"`
`"C:/iar/..../arm/bin/iccarm.exe"` +| `CMAKE_CXX_COMPILER` | Must point to the C++ Compiler executable | `"/opt/iar/cxarm/arm/bin/iccarm"`
`"/opt/iarsystems/bxarm/arm/bin/iccarm"`
`"C:/iar/..../arm/bin/iccarm.exe"`
`"${CMAKE_C_COMPILER}"` +| `CMAKE_ASM_COMPILER` | Must point to the Assembler executable | `"/opt/iar/cxarm/arm/bin/iasmarm"`
`"/opt/iarsystems/bxarm/arm/bin/iasmarm"`
`"C:/iar/..../arm/bin/iasmarm.exe"` +| `CMAKE_MAKE_PROGRAM` | Must point to the build tool executable | `"/opt/iar/cxarm/common/bin/ninja"`
`"/opt/iarsystems/bxarm/common/bin/ninja"`
`"C:/iar/..../common/bin/ninja.exe"` During the configuration phase, CMake reads these variables from: -- a separate file called "toolchain file" that you invoke `cmake` with `--toolchain /path/to/.cmake` (see provided example files [bxarm.cmake](tutorial/bxarm.cmake) and [ewarm.cmake](tutorial/ewarm.cmake)) -or- -- the [`CMAKE_TOOLCHAIN_FILE`](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html) variable, when you invoke `cmake` with `-DCMAKE_TOOLCHAIN_FILE=/path/to/.cmake` (useful for earlier CMake versions) -or- +- a separate file called "toolchain file" that you invoke `cmake` with `--toolchain /path/to/.cmake` (see provided example files [cxarm.cmake](tutorial/cxarm.cmake), [bxarm.cmake](tutorial/bxarm.cmake) and [ewarm.cmake](tutorial/ewarm.cmake)) -or- +- the [`CMAKE_TOOLCHAIN_FILE`](https://cmake.org/cmake/help/latest/variable/CMAKE_TOOLCHAIN_FILE.html) variable, when you invoke `cmake` with `-DCMAKE_TOOLCHAIN_FILE=/path/to/.cmake` (useful for CMake < 3.21) -or- - invoking `cmake` with `-DCMAKE__COMPILER=/path/to/icc` -or- - the user/system environment variables [`CC`](https://cmake.org/cmake/help/latest/envvar/CC.html), [`CXX`](https://cmake.org/cmake/help/latest/envvar/CXX.html) and [`ASM`](https://cmake.org/cmake/help/latest/envvar/ASM.html) which can be used to override the platform's default compiler -or- - the IAR Embedded Workbench IDE 9.3 or later, shipped with IAR products starting from the IAR Embedded Workbench for Arm 9.50, where the available IAR toolchain environment is automatically set for CMake projects (See [this article](https://github.com/IARSystems/cmake-tutorial/wiki/Building-and-Debugging-from-the-Embedded-Workbench) for details). @@ -73,7 +78,7 @@ During the configuration phase, CMake reads these variables from: ### Configure and Build We are ready to build our first project! Run CMake to configure the project and then build it with your chosen build tool. -- Before starting to use CMake, make sure your compiler is working and does not run into any [license issues](#issues). Example (for Arm): +- Before starting to use CMake, make sure your compiler is working properly. Example (for Arm): ``` /path/to/iccarm --version ``` @@ -83,10 +88,10 @@ We are ready to build our first project! Run CMake to configure the project and mkdir build ``` -- Next, navigate to that build directory and run CMake to configure the project and generate a native build system using the compiler specified in the `bxarm.cmake` toolchain file (if needed, edit the supplied toolchain file to match your tool): +- Next, navigate to that build directory and run CMake to configure the project and generate a native build system using the compiler specified in the `cxarm.cmake` toolchain file (if needed, edit the supplied toolchain file to match your tool): ``` cd build -cmake .. -G Ninja --toolchain ../bxarm.cmake +cmake .. -G Ninja --toolchain ../cxarm.cmake ``` - Then call CMake for building the executable using the build system: @@ -95,22 +100,22 @@ cmake --build . ``` ## Run -Let's test the application. To run the executable you will need the non-interactive[^3] command line interface for the IAR C-SPY Debugger (`cspybat`) with the proper drivers for the desired target. Amongst the many ways of accomplishing this, let's take advantage of the `add_test()` for testing the application in a Arm Cortex-M4 simulated target. +Let's test the application. To run the executable you will need the non-interactive[^4] command line interface for the IAR C-SPY Debugger (`cspybat`) with the proper drivers for the desired target. Amongst the many ways of accomplishing this, let's take advantage of the `add_test()` for testing the application in a Arm Cortex-M4 simulated target. This section is interactive. In this example we will use Arm. So, you will need to update your Tutorial's `CMakeLists.txt`: -- Firstly add [`enable_testing()`](https://cmake.org/cmake/help/latest/command/enable_testing.html#command:enable_testing) to enable testing: +- Firstly add [`enable_testing()`](https://cmake.org/cmake/help/latest/command/enable_testing.html) to enable testing: ```cmake enable_testing() ``` -- Then use [`add_test()`](https://cmake.org/cmake/help/latest/command/add_test.html#add-test) to encapsulate the command line `cspybat` needs. In the example below, the parameters are adjusted for simulating a generic Arm Cortex-M4 target environment: +- Then use [`add_test()`](https://cmake.org/cmake/help/latest/command/add_test.html) to encapsulate the command line `cspybat` needs. In the example below, the parameters are adjusted for simulating a generic Arm Cortex-M4 target environment: ```cmake add_test(NAME tutorialTest - COMMAND /opt/iarsystems/bxarm/common/bin/CSpyBat + COMMAND /opt/iar/cxarm/common/bin/CSpyBat # C-SPY drivers for the Arm simulator via command line interface - /opt/iarsystems/bxarm/arm/bin/libarmPROC.so - /opt/iarsystems/bxarm/arm/bin/libarmSIM2.so - --plugin=/opt/iarsystems/bxarm/arm/bin/libarmLibsupportUniversal.so + /opt/iar/cxarm/arm/bin/libarmPROC.so + /opt/iar/cxarm/arm/bin/libarmSIM2.so + --plugin=/opt/iar/cxarm/arm/bin/libarmLibsupportUniversal.so # The target executable (built with debug information) --debug_file=$ # C-SPY driver options @@ -118,18 +123,20 @@ add_test(NAME tutorialTest --cpu=cortex-m4 --semihosting) ``` +>[!TIP] +>- Read this [article](https://github.com/iarsystems/cmake-tutorial/wiki/CTest-with-IAR-Embedded-Workbench-for-Arm) for the specifics when driving tests from IAR Embedded Workbench for Arm. -- Now use the [`PASS_REGULAR_EXPRESSION`](https://cmake.org/cmake/help/latest/prop_test/PASS_REGULAR_EXPRESSION.html#prop_test:PASS_REGULAR_EXPRESSION) test property to validate if the program emits the expected string to the standard output (`stdout`). In this case, verifying that `printf()` prints the expected message. +- Now use the [`PASS_REGULAR_EXPRESSION`](https://cmake.org/cmake/help/latest/prop_test/PASS_REGULAR_EXPRESSION.html) test property to validate if the program emits the expected string to the standard output (`stdout`). In this case, verifying that `printf()` prints the expected message. ```cmake set_tests_properties(tutorialTest PROPERTIES PASS_REGULAR_EXPRESSION "Hello world!") ``` -- Since `CMakeLists.txt` was modified, the build system needs to be reconfigured: +- Since `CMakeLists.txt` was modified, the build system needs to be reconfigured. Rebuilding the project will automatically force reconfiguration, creating the `CTestTestfile.cmake` file: ``` cmake --build . ``` -- And finally we call CMake's [`ctest`](https://cmake.org/cmake/help/latest/manual/ctest.1.html#manual:ctest(1)) which subsequently will execute `Tutorial.elf` using the IAR C-SPY Debugger for Arm: +- And finally we call CMake's [`ctest`](https://cmake.org/cmake/help/latest/manual/ctest.1.html) which subsequently will execute `Tutorial.elf` using the IAR C-SPY Debugger for Arm: ``` ctest ``` @@ -147,9 +154,11 @@ For technical support contact [IAR Customer Support][url-iar-customer-support]. For questions related to this tutorial: try the [wiki][url-repo-wiki] or check [earlier issues][url-repo-issue-old]. If those don't help, create a [new issue][url-repo-issue-new] with detailed information. -[^1]: For more information, see the "Installation and Licensing" guide for your product. If you do not have a license, [contact us](https://iar.com/about/contact). -[^2]: CMake has built-in IAR C/C++ Compiler support for the following non-Arm architectures: 8051, AVR, MSP430, RH850, RISC-V, RL78, RX, STM8 and V850. -[^3]: For interactively debugging of executable files (`*.elf`) using the C-SPY Debugger from the IAR Embedded Workbench IDE, read [this wiki article][url-wiki-ide-build-debug]. +[^1]: For more information, see the "Installation and Licensing" guide for your product. If you are not a subscriber yet, [contact us](https://iar.com/about/contact). +[^2]: For downloading the installers, IAR Subscribers must first perform login on [IAR MyPages](https://mypages.iar.com/s/login). +[^3]: CMake has built-in IAR C/C++ Compiler support for the following non-Arm architectures: 8051, AVR, MSP430, RH850, RISC-V, RL78, RX, STM8 and V850. +[^4]: For interactively debugging of executable files (`*.elf`) using the C-SPY Debugger from the IAR Embedded Workbench IDE, read [this wiki article][url-wiki-ide-build-debug]. + [url-iar-customer-support]: https://iar.my.site.com/mypages/s/contactsupport @@ -158,11 +167,11 @@ For questions related to this tutorial: try the [wiki][url-repo-wiki] or check [ [url-repo-issue-new]: https://github.com/IARSystems/cmake-tutorial/issues/new [url-repo-issue-old]: https://github.com/IARSystems/cmake-tutorial/issues?q=is%3Aissue+is%3Aopen%7Cclosed -[url-help-cmake_minimum_required]: https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html#command:cmake_minimum_required -[url-help-project]: https://cmake.org/cmake/help/latest/command/project.html#command:project -[url-help-add_executable]: https://cmake.org/cmake/help/latest/command/add_executable.html#command:add_executable -[url-help-target_sources]: https://cmake.org/cmake/help/latest/command/target_sources.html#target-sources -[url-help-target_compile_options]: https://cmake.org/cmake/help/latest/command/target_compile_options.html#target-compile-options -[url-help-target_link_options]: https://cmake.org/cmake/help/latest/command/target_link_options.html#target-link-options +[url-help-cmake_minimum_required]: https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html +[url-help-project]: https://cmake.org/cmake/help/latest/command/project.html +[url-help-add_executable]: https://cmake.org/cmake/help/latest/command/add_executable.html +[url-help-target_sources]: https://cmake.org/cmake/help/latest/command/target_sources.html +[url-help-target_compile_options]: https://cmake.org/cmake/help/latest/command/target_compile_options.html +[url-help-target_link_options]: https://cmake.org/cmake/help/latest/command/target_link_options.html [url-wiki-ide-build-debug]: https://github.com/IARSystems/cmake-tutorial/wiki/Building-and-Debugging-from-the-Embedded-Workbench diff --git a/examples/cstat/CMakeLists.txt b/examples/cstat/CMakeLists.txt new file mode 100644 index 0000000..f8d8661 --- /dev/null +++ b/examples/cstat/CMakeLists.txt @@ -0,0 +1,36 @@ +# Minimum CMake version is cmake-4.0.20250425-gd948dd6 +cmake_minimum_required(VERSION 4.0) + +set(This cstat_demo) + +project(${This} C) + + +# TODO 1: Enable C-STAT Static Analysis + + +# TODO 2: Select the CERT C ruleset + + +# TODO 3: Select the MISRA C:2012 ruleset + + +add_executable(${This}) + +target_sources(${This} PRIVATE + main.c + caller.c + callee.c +) + +target_compile_options(${This} PRIVATE + --no_wrap_diagnostics +) + +target_link_options(${This} PRIVATE + --vfe + --map . +) + +# TODO 4: Perform link-time analysis when using the MISRA C:2012 ruleset + diff --git a/examples/cstat/callee.c b/examples/cstat/callee.c new file mode 100644 index 0000000..3a829f8 --- /dev/null +++ b/examples/cstat/callee.c @@ -0,0 +1,8 @@ +#include "caller.h" +#include "callee.h" + +void callee(void) +{ + caller(); +} + diff --git a/examples/cstat/callee.h b/examples/cstat/callee.h new file mode 100644 index 0000000..bf0fdaa --- /dev/null +++ b/examples/cstat/callee.h @@ -0,0 +1,7 @@ +#ifndef CALLEE__H +#define CALLEE__H + +void callee(void); + +#endif + diff --git a/examples/cstat/caller.c b/examples/cstat/caller.c new file mode 100644 index 0000000..2fc0133 --- /dev/null +++ b/examples/cstat/caller.c @@ -0,0 +1,7 @@ +#include "caller.h" +#include "callee.h" + +void caller(void) +{ + callee(); +} diff --git a/examples/cstat/caller.h b/examples/cstat/caller.h new file mode 100644 index 0000000..1866b25 --- /dev/null +++ b/examples/cstat/caller.h @@ -0,0 +1,6 @@ +#ifndef CALLER__H +#define CALLER__H + +void caller(void); + +#endif diff --git a/examples/cstat/main.c b/examples/cstat/main.c new file mode 100644 index 0000000..519e70b --- /dev/null +++ b/examples/cstat/main.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include + +#include "caller.h" +#include "callee.h" + +// ARR30-C: Violation example (Using Past-the-End Index) +static int *table = NULL; +static size_t size = 0; + +int insert_in_table(size_t pos, int value) { + if (size < pos) { + int *tmp; + size = pos + 1; + tmp = (int *)realloc(table, sizeof(*table) * size); + if (tmp == NULL) { + return -1; /* Failure */ + } + table = tmp; + } + + table[pos] = value; + return 0; +} + +// ARR30-C: Violation example (Null Pointer Arithmetic) +char *init_block(size_t block_size, size_t offset, + char *data, size_t data_size) { + char *buffer = malloc(block_size); + if (data_size > block_size || block_size - data_size < offset) { + /* Data won't fit in buffer, handle error */ + } + memcpy(buffer + offset, data, data_size); + return buffer; +} + +// ARR30-C: Violation example (Pointer Past Flexible Array Member) +struct S { + size_t len; + char buf[]; /* Flexible array member */ +}; + +const char *find(const struct S *s, int c) { + const char *first = s->buf; + const char *last = s->buf + s->len; + + while (first++ != last) { /* Undefined behavior */ + if (*first == (unsigned char)c) { + return first; + } + } + return NULL; +} + +void handle_error(void) { + struct S *s = (struct S *)malloc(sizeof(struct S)); + if (s == NULL) { + /* Handle error */ + } + s->len = 0; + find(s, 'a'); +} + +// FLP30-C: Violation example +void float_loop(void) { + for (float x = 0.1f; x <= 1.0f; x += 0.1f) { + /* Loop may iterate 9 or 10 times */ + } +} + +// FLP30-C: Violation example +void flp30_2(void) { + for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) { + /* Loop may not terminate */ + } +} + +// FLP32-C: Violation example (sqrt()) +double sqroot(double x) { + double result; + result = sqrt(x); + return result; +} + +// FLP37-C: Violation example +struct S2 { + int i; + float f; +}; + +bool are_equal(const struct S2 *s1, const struct S2 *s2) { + if (!s1 && !s2) + return true; + else if (!s1 || !s2) + return false; + return 0 == memcmp(s1, s2, sizeof(struct S2)); +} + +// INT33-C: Violation example +signed long func(signed long s_a, signed long s_b) { + signed long result; + if ((s_a == LONG_MIN) && (s_b == -1)) { + /* Handle error */ + } else { + result = s_a / s_b; + } + /* ... */ + return result; +} + +// MEM34-C: Violation example +enum { BUFSIZE = 256 }; +int f1(void) { + char *text_buffer = (char *)malloc(BUFSIZE); + if (text_buffer == NULL) { + return -1; + } + return 0; +} + +enum { STR_SIZE = 32 }; +size_t str32(const char *source) { + char c_str[STR_SIZE]; + size_t ret = 0; + + if (source) { + c_str[sizeof(c_str) - 1] = '\0'; + strncpy(c_str, source, sizeof(c_str)); + ret = strlen(c_str); + } else { + /* Handle null pointer */ + } + return ret; +} + +// DCL38-C: Violation example +struct flexArrayStruct { + int num; + int data[1]; +}; + +void dcl38(size_t array_size) { + /* Space is allocated for the struct */ + struct flexArrayStruct *structP + = (struct flexArrayStruct *) + malloc(sizeof(struct flexArrayStruct) + + sizeof(int) * (array_size - 1)); + if (structP == NULL) { + /* Handle malloc failure */ + } + + structP->num = array_size; + + /* + * Access data[] as if it had been allocated + * as data[array_size]. + */ + for (size_t i = 0; i < array_size; ++i) { + structP->data[i] = 1; + } +} + +size_t count_preceding_whitespace(const char *s) { + const char *t = s; + size_t length = strlen(s) + 1; + while (isspace(*t) && (t - s < length)) { + ++t; + } + return t - s; +} + +int main() { + caller(); +} + diff --git a/examples/libs/CMakeLists.txt b/examples/libs/CMakeLists.txt index f9c1966..32c1b46 100644 --- a/examples/libs/CMakeLists.txt +++ b/examples/libs/CMakeLists.txt @@ -12,7 +12,11 @@ add_subdirectory() # TODO 5: Link the `lib` against `libs` target_link_libraries() -target_link_options(libs PRIVATE --semihosting) +target_compile_options(libs PRIVATE --cpu=cortex-m4) + +target_link_options(libs PRIVATE + --cpu=cortex-m4 + --semihosting) enable_testing() diff --git a/examples/libs/lib/CMakeLists.txt b/examples/libs/lib/CMakeLists.txt index 10ddce5..86fb120 100644 --- a/examples/libs/lib/CMakeLists.txt +++ b/examples/libs/lib/CMakeLists.txt @@ -6,3 +6,5 @@ target_sources() # TODO 3: Using the `PUBLIC` scope, expose the `lib` headers (inc) to other targets target_include_directories() + +target_compile_options(lib PRIVATE --cpu=cortex-m4) diff --git a/examples/mix/CMakeLists.txt b/examples/mix/CMakeLists.txt index 8e315af..8794b14 100644 --- a/examples/mix/CMakeLists.txt +++ b/examples/mix/CMakeLists.txt @@ -8,7 +8,11 @@ add_executable(mix) # TODO 2: Add `fun.s` source to the `mix` target target_sources(mix PRIVATE main.c) -target_link_options(mix PRIVATE --semihosting) +target_compile_options(mix PRIVATE --cpu=cortex-m4) + +target_link_options(mix PRIVATE + --cpu=cortex-m4 + --semihosting) enable_testing() diff --git a/examples/trustzone/non-secure/CMakeLists.txt b/examples/trustzone/non-secure/CMakeLists.txt index 9712b3c..2aac4de 100644 --- a/examples/trustzone/non-secure/CMakeLists.txt +++ b/examples/trustzone/non-secure/CMakeLists.txt @@ -15,6 +15,6 @@ target_link_options(non-secure PRIVATE --cpu=$ --config ${CMAKE_CURRENT_SOURCE_DIR}/v2m-mps2_ns.icf --semihosting - # TODO 5: Link agains the import library generated from the `secure` target + # TODO 5: Link against the import library generated from the `secure` target # TODO 6: Specify "no entry point" for the `non-secure` target ) diff --git a/examples/trustzone/non-secure/non-secure-hello.c b/examples/trustzone/non-secure/non-secure-hello.c index c74807c..7fc5df1 100644 --- a/examples/trustzone/non-secure/non-secure-hello.c +++ b/examples/trustzone/non-secure/non-secure-hello.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2018-2024, IAR Systems AB. + Copyright (c) 2018-2025, IAR Systems AB. `non-secure` "Hello" - A simple CMSE example This example is not production-ready within CMSE best-practices. @@ -44,7 +44,7 @@ void main_ns(void) /* Nothing more to do at this point... */ } -/* Inteface towards the secure part */ +/* Interface towards the secure part */ #pragma location=NON_SECURE_ENTRY_TABLE __root const non_secure_init_t init_table = { diff --git a/examples/trustzone/secure/secure-hello.c b/examples/trustzone/secure/secure-hello.c index 52d8a40..3cde598 100644 --- a/examples/trustzone/secure/secure-hello.c +++ b/examples/trustzone/secure/secure-hello.c @@ -1,6 +1,6 @@ /* - Copyright (c) 2018-2024, IAR Systems AB. + Copyright (c) 2018-2025, IAR Systems AB. `secure` "Hello" - A simple CMSE example This minimalistic example is not production-ready within CMSE best-practices. diff --git a/examples/trustzone/secure/secure-hello.h b/examples/trustzone/secure/secure-hello.h index dbad390..e356b2b 100644 --- a/examples/trustzone/secure/secure-hello.h +++ b/examples/trustzone/secure/secure-hello.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2018-2024, IAR Systems AB. + Copyright (c) 2018-2025, IAR Systems AB. Header file for the `trustzone` example. Contains definitions used in the following targets: diff --git a/examples/version/CMakeLists.txt b/examples/version/CMakeLists.txt index 21dc8f2..5366a60 100644 --- a/examples/version/CMakeLists.txt +++ b/examples/version/CMakeLists.txt @@ -13,7 +13,11 @@ configure_file() # TODO 3: Add the Project Binary Directory to the target's include directories target_include_directories() -target_link_options(version PRIVATE --semihosting) +target_compile_options(version PRIVATE --cpu=cortex-m4) + +target_link_options(version PRIVATE + --cpu=cortex-m4 + --semihosting) enable_testing() diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 631dac3..c5532a5 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -14,7 +14,9 @@ target_sources(tutorial PRIVATE tutorial.c) target_compile_options(tutorial PRIVATE --cpu=cortex-m4) # linker options -target_link_options(tutorial PRIVATE --semihosting) +target_link_options(tutorial PRIVATE + --cpu=cortex-m4 + --semihosting) # TODO 1: Enable testing in CMake diff --git a/tutorial/cxarm.cmake b/tutorial/cxarm.cmake new file mode 100644 index 0000000..243c0f1 --- /dev/null +++ b/tutorial/cxarm.cmake @@ -0,0 +1,26 @@ +# Toolchain File for the IAR C/C++ Compiler (CX) + +# Set CMake for cross-compiling +set(CMAKE_SYSTEM_NAME Generic) + +# Set CMake to use the IAR C/C++ Compiler from the IAR Build Tools for Arm +# Update if using a different supported target or operating system +set(CMAKE_ASM_COMPILER /opt/iar/cxarm/arm/bin/iasmarm) +set(CMAKE_C_COMPILER /opt/iar/cxarm/arm/bin/iccarm) +set(CMAKE_CXX_COMPILER /opt/iar/cxarm/arm/bin/iccarm) + +# Avoids running the linker during try_compile() +set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + +# Set the default build tool for Ninja gnerators +# Reasonably recent IAR products ships with ninja (https://ninja-build.org) +# The CMake code block below tries to find it. If not found, +# manually install the desired build system in your operating system +# Alternatively: set(CMAKE_MAKE_PROGRAM "/usr/bin/ninja") +if(CMAKE_GENERATOR MATCHES "^Ninja.*$") + find_program(CMAKE_MAKE_PROGRAM + NAMES ninja + PATHS $ENV{PATH} + /opt/iar/cxarm/common/bin + REQUIRED) +endif() diff --git a/tutorial/ewarm.cmake b/tutorial/ewarm.cmake index 2da3ef4..7c1fb0a 100644 --- a/tutorial/ewarm.cmake +++ b/tutorial/ewarm.cmake @@ -4,10 +4,10 @@ set(CMAKE_SYSTEM_NAME Generic) # Set CMake to use the IAR C/C++ Compiler from the IAR Embedded Workbench for Arm -# Update if using a different supported target or operating system -set(CMAKE_ASM_COMPILER "C:/Program Files/IAR Systems/Embedded Workbench 9.3/arm/bin/iasmarm.exe") -set(CMAKE_C_COMPILER "C:/Program Files/IAR Systems/Embedded Workbench 9.3/arm/bin/iccarm.exe") -set(CMAKE_CXX_COMPILER "C:/Program Files/IAR Systems/Embedded Workbench 9.3/arm/bin/iccarm.exe") +# Update the paths if using any different supported target/version +set(CMAKE_ASM_COMPILER "C:/iar/ewarm-9.60.4/arm/bin/iasmarm.exe") +set(CMAKE_C_COMPILER "C:/iar/ewarm-9.60.4/arm/bin/iccarm.exe") +set(CMAKE_CXX_COMPILER "C:/iar/ewarm-9.60.4/arm/bin/iccarm.exe") # Avoids running the linker during try_compile() set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) @@ -21,6 +21,6 @@ if(CMAKE_GENERATOR MATCHES "^Ninja.*$") find_program(CMAKE_MAKE_PROGRAM NAMES ninja.exe PATHS $ENV{PATH} - "C:/Program Files/IAR Systems/Embedded Workbench 9.3/common/bin" + "C:/iar/ewarm-9.60.4/common/bin" REQUIRED) endif()