I'm new to CMake and I'm trying to convert an existing multi-target multi-arch make project to it. Basically I'm building and flashing a firmware image for AVR onto a target device, but I want to build and run unit tests on the host prior to flashing the firmware image, in particular I want building the firmware to depend on the unit tests succeeding if possible.
Note that this is different from compiling the same code in 32/64 configurations which seem to be solved by doing out of tree builds using environment variables to tell cmake which target to build from. As I need to work with both archs at the same time without twiddling with re-running cmake in between.
The principal source structure is like so:
├── CMakeLists.txt
├── src
│ └── Bar.cpp
├── lib
│ └── external/arch/foo.cpp
└── test
└── BarTest.cpp
I need all files in "src" and some files from "lib/external/avr/" to build my AVR target using avr-g++.
To build the tests that are ran on the host (x86(-64)) I need all files in "test" and some files from "src" (the code under test) and some files from "lib/external/x86/" and I need to build on the host compiler (don't care if it's gcc or clang) with slightly different flags. This is complicated in my make file above by the fact that the same file needs multiple object files built for different architectures and thus they need different output dirs.
In the end I want to be able to do make test
to run the host tests and make upload
to compile and program the target device (only if tests pass).
What I currently have in my CMakeLists.txt
:
cmake_minimum_required(VERSION 2.8)
set(AVRCPP avr-g++)
set(AVRSTRIP avr-strip)
set(OBJCOPY avr-objcopy)
set(OBJDUMP avr-objdump)
set(AVRSIZE avr-size)
set(AVRDUDE avrdude)
set(CXXSTANDARD "-std=c++14")
set(COPT "-O3")
set(CWARN "-Werror -Wall -Wextra -pedantic -Wno-attributes")
set(CTUNING "-fno-threadsafe-statics -fpack-struct -fshort-enums -fno-stack-protector")
set(BASE_AVR_CXXFLAGS "${CXXSTANDARD} ${COPT} ${CWARN} ${CTUNING}")
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_CXX_COMPILER ${AVRCPP})
#
# Probe project
#
project(probe CXX)
set(MCU "atmega328p")
set(CMCU "-mmcu=${MCU} -DF_CPU=16000000UL")
set(CDEFS "-DUART_BAUD=9600 -DUART_DATA_BITS=8 -DUART_PARITY_BITS=0 -DUART_STOP_BITS=1")
set(CMAKE_CXX_FLAGS "${BASE_AVR_CXXFLAGS} ${CMCU} ${DEFS}")
set(BASE_PATH "${${PROJECT_NAME}_SOURCE_DIR}")
set(INC_PATH "${BASE_PATH}/include")
set(SRC_PATH "${BASE_PATH}/src")
set(LIB_DIR_PATH "${BASE_PATH}/lib")
set(XTD_SRC_PATH "${BASE_PATH}/xtd_uc/src")
include_directories(${INC_PATH} "xtd_uc/include")
file(GLOB SRC_FILES "${SRC_PATH}/*.cpp")
set(XTD_SRC_FILES
${XTD_SRC_PATH}/delay.cpp
${XTD_SRC_PATH}/atmega/adc.cpp
${XTD_SRC_PATH}/atmega/bootstrap.cpp
${XTD_SRC_PATH}/atmega/chrono.cpp
${XTD_SRC_PATH}/atmega/gpio.cpp
${XTD_SRC_PATH}/atmega/sleep.cpp
${XTD_SRC_PATH}/atmega/uart.cpp
${XTD_SRC_PATH}/atmega/wdt.cpp
)
add_executable(${PROJECT_NAME} ${SRC_FILES} ${XTD_SRC_FILES})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}.elf")
# Compiling targets
add_custom_target(strip ALL ${AVRSTRIP} "${PROJECT_NAME}.elf" DEPENDS ${PROJECT_NAME})
add_custom_target(hex ALL ${OBJCOPY} -R .eeprom -O ihex "${PROJECT_NAME}.elf" "${PROJECT_NAME}.hex" DEPENDS strip)
add_custom_target(eeprom ${OBJCOPY} -j .eeprom --change-section-lma .eeprom=0 -O ihex "${PROJECT_NAME}.elf" "${PROJECT_NAME}.eeprom" DEPENDS strip)
add_custom_target(disassemble ${OBJDUMP} -S "${PROJECT_NAME}.elf" > "${PROJECT_NAME}.lst" DEPENDS strip)
# Flashing targets
set(PROG_TYPE_ARDUINO "-v -c arduino -b 115200 -P /dev/ttyUSB0")
set(PROG_TYPE_AVRISP "-v -c avrisp -b 19200 -P /dev/ttyACM0")
set(PROG_TYPE ${PROG_TYPE_ARDUINO})
add_custom_target(flash_program ${AVRDUDE} ${PROG_TYPE} -p ${MCU} -U flash:w:${PROJECT_NAME}.hex DEPENDS hex)
add_custom_target(flash_eeprom ${AVRDUDE} ${PROG_TYPE} -p ${MCU} -U eeprom:w:${PROJECT_NAME}.hex DEPENDS eeprom)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.hex;${PROJECT_NAME}.eeprom;${PROJECT_NAME}.lst")
message("* ")
message("* Project Name:\t${PROJECT_NAME}")
message("* Project Source:\t${SRC_PATH}")
message("* Project Include:\t${INC_PATH}")
message("* Library Include:\t${LIB_INC_PATH}")
message("* ")
message("* Project Source Files:\t${SRC_FILES}")
message("* XTD Source Files:\t${XTD_SRC_FILES}")
message("* ")
message("* CXX Flags:\t${CMAKE_CXX_FLAGS}")
message("* ")
And it works for building the AVR target but I'm at a loss for how to integrate the tests into this with a different compiler/target-arch.
Any help with how I would achieve the above with cmake would be greatly appreciated.