Cmake: Specify a separate build toolchain for testing?

Viewed 365

I am using CMake to build a project for an embedded system, but my unit testing is done on an x86 host. Therefore, I need to use a completely different compiler to build the tests from the one used for the cross-compiled binary.

I have a main CMakeLists.txt file at the top level of my project, and then another one in my testing folder which gets added with add_subdirectory at the top level. Should I just keep them completely separate or is there a better way to accomplish this?

Running my main build without the cross compiler will cause it to fail, so it really needs to be a separate process for the tests.

1 Answers

Should I just keep them completely separate

There's no need to. Keep proper minimum dependencies between targets, add EXCLUDE_FROM_ALL to tests targets and manage targets with good grouping. Or explicitly compile only targets that you want to compile.

or is there a better way to accomplish this?

The known limitation:

  • You may have one compiler per one cmake configuration.
  • You can't (easily ;) "switch" between compilers and use different compiler for different target.
  • To use a different compiler, you have to reconfigure cmake.

Solution:

  • Configure cmake differently for unit testing and for normal compilation.
  • Typically use an external tool/script/whatever to manage cmake configuration and execute actions you want.
  • By properly labeling unit tests and using EXCLUDE_FROM_ALL on unused target, compile only what you want.

I typically use a Makefile, only because shell does autodetection of autocompletion for me:

all: normal_build
normal_build:
     cmake -S . -B _build/$@ \
            -DCMAKE_TOOLCHAIN_FILE=the_target_toolchain_file.camle
     cmake --build _build/$@ --target the_firmware

unit_tests_on_pc:
     camke -S . -B _build/$@ \
            -DCMAKE_C_FLAGS="-fsanitize -Wall -Wextra -pedantic etc...."
     cmake --build _build/$@ --target unit_tests # note - compile only unit tests
     cd _build/$@ && ctest -LE "on_target"

# tests with set CMAKE_CROSSCOMPILING_EMULATOR in toolchain file
unit_tests_on_simulator:
     cmake -S . -B _build/$@ \
           -DCMAKE_TOOLCHAIN_FILE=the_toolchain_file_for_simulator.camke
     cmake --build _build/$@ --target unit_tests
     cd _build/$@ && ctest -E "on_target"

# tests with set CMAKE_CROSSCOMPILING_EMULATOR to a script
# that flashes some connected target with the firmware and get's output from it
unit_tests_on_target:
     cmake -S . -B _build/$@ \
           -DCMAKE_TOOLCHAIN_FILE=the_toolchain_file_for_unit_tests.camke
     # special targets compiled here - only integration tests for real hardware!
     cmake --build _build/$@ --target integration_tests
     cd _build/$@ && ctest -E "on_target"

# etc..
Related