-->

CMake - compile natively and crosscompile the same

2019-05-10 15:55发布

问题:

We're writing an application for an embedded ARM/Linux device. Development is performed on a Windows PC, using a crosscompiler, Eclipse and Ninja. CMake currently can create the build scripts that work well for the intended purpose.

We have unit tests that run on the embedded device attached to the net, once the project is pushed (over Git) to the server.

We're trying to implement unit tests, that would run on the PC, before we try them on the device. That means building natively, using MinGW GCC - of course we can't launch the ARM Linux executables on the PC.

Even if we switch the toolchain, launching CMake to rebuild the ruleset for Ninja, or create two build directories, one for PC, one for ARM, the problem remains that CMake will try to run a test executable, and later during build, unit tests will be attempted on the ARM build.

How can we configure the builds (through CMake) to create both - and not attempt to run the crosscompiled ones on the PC?

回答1:

I have a similar setup in my projects (building from the same sources a simulator, unit tests, and the target binary), and you can check for CMAKE_CROSSCOMPILING to differentiate your two use cases. Just putting

if (NOT CMAKE_CROSSCOMPILING)
    ....
endif()

around the particular commands should do the trick.

And you need to have two binary output directories. CMake does not allow to mix toolchains in one directory.

But you don't need to have two IDE projects. In my projects:

  • I've added all sources - incl. the "cross-compile only" files - into the library/executable targets
    • I'm marking them as "excluded from build" for the PC only variants
    • So all sources will show-up in one IDE project (e.g. for searching through the code)
  • I've added the cross-compiling call as a custom target
    • I've removed it from the default build, but you can explicitly start it from your IDE
    • In my case it's an external script, but you can also pass the necessary calls directly in COMMAND parameters
    • You could even use another ExternalProject_Add() to include your own project for cross-compiling

Here are some code snippets for this kind of approach:

if (NOT CMAKE_CROSSCOMPILING)
    set(PC "ON" CACHE INTERNAL "hw-platform PC")
    unset(MCU CACHE)
else()
    set(MCU "ON" CACHE INTERNAL "hw-platform MCU")
    unset(PC CACHE)
endif()

...

if (PC)
    # Exclude files that only compile/work on MCU
    set_source_files_properties(... PROPERTIES HEADER_FILE_ONLY 1)
endif()

...

if (PC)
    add_test(...)
endif()

...

if (PC AND EXISTS "${CMAKE_SOURCE_DIR}/buildMcu.cmd")
    add_custom_target(
        BUILD_MCU
        COMMAND buildMcu.cmd
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    )
    set_target_properties(BUILD_MCU PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD 1)
endif()

References

  • How to instruct CMake to use the build architecture compiler