[announce] CMake Tutorial for IAR Compiler

We are pleased to announce a new CMake tutorial for IAR C/C++ Compiler users.

The tutorial is readily available at

Highlights:

  • Ready to use project examples, for all the architectures supported in CMake.
  • A generic toolchain file, suitable for all the supported architectures.
  • CTest as frontend for the IAR C-SPY Debugger.
  • Target-oriented CMakeLists.
  • And more…

We invite anyone interested to try the tutorial. Please enjoy.

2 Likes

Unfortunately that example project doesn’t work for me. Something about the way it’s trying to modify the path to add the IAR bin/ directory isn’t working on my system, so it can’t find any of the IAR tools on configure.

Using the following settings in iar-toolchain.cmake:

# Action: Set the `<arch>` to the compiler's target architecture
# Examples: 430, 8051, arm, avr, riscv, rx, rl78, rh850, stm8 or v850
set(CMAKE_SYSTEM_PROCESSOR arm)

# Action: Set the `IAR_INSTALL_DIR` to the tool installation path
set(IAR_INSTALL_DIR "C:\\Program Files\\IAR Systems\\Embedded Workbench 9.0\\arm")

And running the command `C:\Workspaces\IARExamples\cmake-tutorial\examples\using-libs\arm>cmake -G “Ninja Multi-Config” -B_builds --toolchain …/…/iar-toolchain.cmake```
I get the following output for the example program:

-- The C compiler identification is unknown
CMake Error at CMakeLists.txt:3 (project):
  The CMAKE_C_COMPILER:

    iccarm

  is not a full path and was not found in the PATH.

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


-- Configuring incomplete, errors occurred!
See also "C:/Workspaces/IARExamples/cmake-tutorial/examples/using-libs/arm/_builds/CMakeFiles/CMakeOutput.log".
See also "C:/Workspaces/IARExamples/cmake-tutorial/examples/using-libs/arm/_builds/CMakeFiles/CMakeError.log".

C:\Workspaces\IARExamples\cmake-tutorial\examples\using-libs\arm>
C:\Workspaces\IARExamples\cmake-tutorial\examples\using-libs\arm>
C:\Workspaces\IARExamples\cmake-tutorial\examples\using-libs\arm>
C:\Workspaces\IARExamples\cmake-tutorial\examples\using-libs\arm>cmake -G "Ninja Multi-Config" -B_builds --toolchain ../../iar-toolchain.cmake
-- The C compiler identification is unknown
CMake Error at CMakeLists.txt:3 (project):
  The CMAKE_C_COMPILER:

    iccarm

  is not a full path and was not found in the PATH.

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


-- Configuring incomplete, errors occurred!
See also "C:/Workspaces/IARExamples/cmake-tutorial/examples/using-libs/arm/_builds/CMakeFiles/CMakeOutput.log".
See also "C:/Workspaces/IARExamples/cmake-tutorial/examples/using-libs/arm/_builds/CMakeFiles/CMakeError.log".

I think instead of modifying the PATH like this toolchain example does, it would be better to use a find_package script to locate the IAR toolchain and use complete paths for the C compiler, etc. This is because the build environment might not be the same as the configure environment, so changes to the PATH can be lost.

Hi @pfox89 ,

Thanks for trying this tutorial. Could you please try with:

set(IAR_INSTALL_DIR "C:\\Program Files\\IAR Systems\\Embedded Workbench 9.0")

Thank you.

@felipe-iar OK, I do get a bit futher with that, but I get the following error:

-- The C compiler identification is IAR ARM 9.10.2
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - failed
-- Check for working C compiler: C:/Program Files/IAR Systems/Embedded Workbench 9.0/arm/bin/iccarm.exe
-- Check for working C compiler: C:/Program Files/IAR Systems/Embedded Workbench 9.0/arm/bin/iccarm.exe - broken
CMake Error at C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeTestCCompiler.cmake:69 (message):
  The C compiler

    "C:/Program Files/IAR Systems/Embedded Workbench 9.0/arm/bin/iccarm.exe"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: C:/Workspaces/IARExamples/cmake-tutorial/examples/using-libs/arm/_builds/CMakeFiles/CMakeTmp

    Run Build Command(s):C:/PROGRA~1/Ninja/ninja.exe cmTC_264de && [1/2] Building C object CMakeFiles\cmTC_264de.dir\Debug\testCCompiler.c.o
    [2/2] Linking C static library Debug\libcmTC_264de.a
    FAILED: Debug/libcmTC_264de.a
    cmd.exe /C "cd . && C:\Strawberry\c\bin\ar.exe Debug\libcmTC_264de.a --create  CMakeFiles\cmTC_264de.dir\Debug\testCCompiler.c.o && cd ."
    C:\Strawberry\c\bin\ar.exe: unknown option -- e
    Usage: C:\Strawberry\c\bin\ar.exe [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV] [--plugin <name>] [member-name] [count] archive-file file...
           C:\Strawberry\c\bin\ar.exe -M [<mri-script]
     commands:
      d            - delete file(s) from the archive
      m[ab]        - move file(s) in the archive
      p            - print file(s) found in the archive
      q[f]         - quick append file(s) to the archive
      r[ab][f][u]  - replace existing or insert new file(s) into the archive
      s            - act as ranlib
      t[O][v]      - display contents of the archive
      x[o]         - extract file(s) from the archive
     command specific modifiers:
      [a]          - put file(s) after [member-name]
      [b]          - put file(s) before [member-name] (same as [i])
      [D]          - use zero for timestamps and uids/gids
      [U]          - use actual timestamps and uids/gids (default)
      [N]          - use instance [count] of name
      [f]          - truncate inserted file names
      [P]          - use full path names when matching
      [o]          - preserve original dates
      [O]          - display offsets of files in the archive
      [u]          - only replace files that are newer than current archive contents
     generic modifiers:
      [c]          - do not warn if the library had to be created
      [s]          - create an archive index (cf. ranlib)
      [S]          - do not build a symbol table
      [T]          - make a thin archive
      [v]          - be verbose
      [V]          - display the version number
      @<file>      - read options from <file>
      --target=BFDNAME - specify the target object format as BFDNAME
     optional:
      --plugin <p> - load the specified plugin
     emulation options:
      No emulation specific options
    C:\Strawberry\c\bin\ar.exe: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 elf64-x86-64 elf64-l1om elf64-k1om pe-i386 pei-i386 elf32-i386 elf32-iamcu elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex
    ninja: build stopped: subcommand failed.





  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:3 (project)


-- Configuring incomplete, errors occurred!

It looks like it found the wrong binutils, not the ones associated with IAR?

Hi @pfox89,

Thank you for your detailed description of the problem.

About the suggestion of prepending the ${TOOLKIT_DIR}/bin to the PATH variable from within the iar-toolchain.cmake toolchain file, I can mention that, according to the CMake Documentation (reference), if we change the PATH environment variable, the change will only take effect while CMake is running. If echo %PATH% is executed after the CMake’s configuration step, it will be revealed that the ${TOOLKIT_DIR}/bin is not sticky when used that way. Of course, please keep in mind that this is not the only possible solution and was was chosen as “default” for the tutorial for 2 simple reasons: portability and backward compatibility. There are 10 different compiler’s target architectures on multiple operating systems supported in CMake and we tried to make sure that most of them would be covered. Also, this technique allows us to use the selected installation of the IAR tools without the need of setting the system’s global PATH outside CMake.

As per the Strawberry’s archiver interfering in the process, that’s a new one to me. It is also a bit strange, because pre-pending the ${TOOLKIT_DIR}/bin should be taking precedence, as it would be “theoretically” placed prior the C:\Strawberry folder.

As a test, you could try to slightly change the iar-toolchain.cmake using a snippet similar to this:

# Add the selected IAR toolchain to the PATH (only while CMake is running)
if(UNIX)
  set(ENV{PATH} "${TOOLKIT_DIR}/bin:$ENV{PATH}")
else()
  set(ENV{PATH} "${TOOLKIT_DIR}/bin;$ENV{PATH}")
endif()
message(STATUS "PATH is: $ENV{PATH}")

OK, you can definitely see that the IAR path comes first in this example:

-- PATH is: C:\Program Files\IAR Systems\Embedded Workbench 9.0/arm\bin;C:\Program Files\ImageMagick-7.1.0-Q16-HDRI;C:\Program Files\AdoptOpenJDK\jdk-8.0.292.10-hotspot\bin;C:\Python39\Scripts\;C:\Python39\;C:\Program Files\Python39\Scripts\;C:\Program Files\Python39\;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\Webex\Plugins;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files\Microsoft VS Code\bin;C:\Program Files\dotnet\;C:\Program Files\Microsoft SQL Server\130\Tools\Binn\;C:\Program Files\PuTTY\;C:\Program Files (x86)\dotnet\;C:\Program Files\Git\cmd;C:\Strawberry\c\bin;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;C:\Program Files (x86)\IVI Foundation\VISA\WinNT\Bin\;C:\Program Files\IVI Foundation\VISA\Win64\Bin\;C:\Program Files 
(x86)\IVI Foundation\VISA\WinNT\Bin;C:\Program Files\SlikSvn\bin;C:\Program Files\nodejs\;C:\ProgramData\chocolatey\bin;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files (x86)\Sennheiser\SenncomSDK\;C:\Program Files\CMake\bin;C:\Program Files\Conan\conan;C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.07\bin;C:\Users\pfox\AppData\Local\Microsoft\WindowsApps;C:\Program Files\Azure Data Studio\bin;C:\Program Files\Ninja;C:\Program Files\LLVM\bin;C:\flutter\bin;C:\Users\pfox\AppData\Roaming\Python\Python39\Scripts;C:\Users\pfox\AppData\Roaming\npm;C:\flutter\bin;C:\Users\pfox\.dotnet\tools;C:\Infineon\Toolbox Launcher;C:\Infineon\LauncherService

Maybe CMake is checking for GNU tool names (ld, ar, etc) before the IAR names and because a full path isn’t given to the compiler it checks the system path first?

When I specify the full path to the compiler like this:

# CMake requires individual variables for the C Compiler, C++ Compiler and Assembler
set(CMAKE_C_COMPILER    "${TOOLKIT_DIR}/bin/icc${CMAKE_SYSTEM_PROCESSOR}.exe")
set(CMAKE_CXX_COMPILER  "${TOOLKIT_DIR}/bin/icc${CMAKE_SYSTEM_PROCESSOR}.exe")
set(CMAKE_ASM_COMPILER "${TOOLKIT_DIR}/bin/iasm${CMAKE_SYSTEM_PROCESSOR}.exe")

It works correctly.

Nicely noticed, @pfox89. This might be, in fact, the root cause of the problem. Please give me some time to investigate this issue from my end. Thank you very much for taking time to test. I hope it helps.

Hi @pfox89,

In order to try to reproduce such issue, I installed the latest version of the StrawberryPerl on my station, so I got the ar.exe available on the PATH. The tutorial examples worked without having to specify the full path on the CMAKE_<lang>_COMPILER variable.

C:\cmake\examples\using-libs\arm>cmake -G "Ninja Multi-Config" -B_builds --toolchain ../../iar-toolchain.cmake
-- The C compiler identification is IAR ARM 9.10.2
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/IAR_Systems/EWARM/9.10.2/arm/bin/iccarm.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: C:/cmake/examples/using-libs/arm/_builds

C:\cmake\examples\using-libs\arm>cmake --build _builds --config Debug --verbose
[1/6] C:\IAR_Systems\EWARM\9.10.2\arm\bin\iccarm.exe  --silent C:\cmake\examples\using-libs\arm\lib\src\add.c -DCMAKE_INTDIR=\"Debug\" -IC:\cmake\examples\using-libs\arm\lib\include -IC:\cmake\examples\using-libs\arm\lib\src -r --cpu Cortex-M4 --dlib_config normal -e --dependencies=ns lib\CMakeFiles\myMath.dir\Debug\src\add.c.o.d -o lib\CMakeFiles\myMath.dir\Debug\src\add.c.o
[2/6] C:\IAR_Systems\EWARM\9.10.2\arm\bin\iccarm.exe  --silent C:\cmake\examples\using-libs\arm\lib\src\mul.c -DCMAKE_INTDIR=\"Debug\" -IC:\cmake\examples\using-libs\arm\lib\include -IC:\cmake\examples\using-libs\arm\lib\src -r --cpu Cortex-M4 --dlib_config normal -e --dependencies=ns lib\CMakeFiles\myMath.dir\Debug\src\mul.c.o.d -o lib\CMakeFiles\myMath.dir\Debug\src\mul.c.o
[3/6] C:\IAR_Systems\EWARM\9.10.2\arm\bin\iccarm.exe  --silent C:\cmake\examples\using-libs\arm\lib\src\sub.c -DCMAKE_INTDIR=\"Debug\" -IC:\cmake\examples\using-libs\arm\lib\include -IC:\cmake\examples\using-libs\arm\lib\src -r --cpu Cortex-M4 --dlib_config normal -e --dependencies=ns lib\CMakeFiles\myMath.dir\Debug\src\sub.c.o.d -o lib\CMakeFiles\myMath.dir\Debug\src\sub.c.o
[4/6] C:\IAR_Systems\EWARM\9.10.2\arm\bin\iccarm.exe  --silent C:\cmake\examples\using-libs\arm\app\src\main.c -DCMAKE_INTDIR=\"Debug\" -IC:\cmake\examples\using-libs\arm\lib\include -r --dlib_config normal --cpu Cortex-M4 --fpu VFPv4_sp -e --dependencies=ns app\CMakeFiles\myProgram.dir\Debug\src\main.c.o.d -o app\CMakeFiles\myProgram.dir\Debug\src\main.c.o
[5/6] cmd.exe /C "cd . && C:\IAR_Systems\EWARM\9.10.2\arm\bin\iarchive.exe lib\Debug\libmyMath.a --create  lib\CMakeFiles\myMath.dir\Debug\src\add.c.o lib\CMakeFiles\myMath.dir\Debug\src\sub.c.o lib\CMakeFiles\myMath.dir\Debug\src\mul.c.o && cd ."
[6/6] cmd.exe /C "cd . && C:\IAR_Systems\EWARM\9.10.2\arm\bin\ilinkarm.exe --silent app\CMakeFiles\myProgram.dir\Debug\src\main.c.o --semihosting --redirect ___write=___write_buffered --map C:/cmake/examples/using-libs/arm/_builds/app/Debug/myProgram.elf.map --config C:/IAR_Systems/EWarm/9.10.2/arm/config/linker/ST/stm32f407xG.icf  lib\Debug\libmyMath.a -o app\Debug\myProgram.elf && cd ."

C:\cmake\examples\using-libs\arm>ar
Usage: ar [emulation options] [-]{dmpqrstx}[abcDfilMNoOPsSTuvV] [--plugin <name>] [member-name] [count] archive-file file...
       ar -M [<mri-script]
<...>
 emulation options:
  No emulation specific options
ar: supported targets: pe-x86-64 pei-x86-64 pe-bigobj-x86-64 elf64-x86-64 elf64-l1om elf64-k1om pe-i386 pei-i386 elf32-i386 elf32-iamcu elf64-little elf64-big elf32-little elf32-big plugin srec symbolsrec verilog tekhex binary ihex

C:\cmake\examples\using-libs\arm>echo %PATH%
C:\cmake\cmake-3.22.0-rc1-windows-x86_64\bin;C:\Windows;C:\WINDOWS\system32;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\Sequencer\;C:\Strawberry\c\bin;C:\Strawberry\perl\site\bin;C:\Strawberry\perl\bin;

C:\cmake\examples\using-libs\arm>

Ah, it looks like this was partially my mistake. After correcting the path, I didn’t delete the build directory before re-configuring. Because the path was wrong on my first attempt, it had cached binutils paths that it had found in the system PATH, which happened to be the ones from Strawberry Perl on my system.

It works if I start with a clean build directory. It might be worth at least noting this pitfall in the documentation.

In the long run, it might be better if CMake failed quickly if it can’t find the specified compiler, rather than continuing to search and potentially putting wrong values in the cache.

Thanks for the feedback. Perhaps it is a good idea to provide an explicit distinction between IAR_INSTALL_DIR and TOOLKIT_DIR/bin in the tutorial’s “Configuring the toolchain file” section.