Using cmake, is there a way to generate n-unique object files from a single source file?
I saw one solution for autotool (of which I know how to do) but nothing for cmake ... yet.
# Make three unique object files
# from a single source file
set_source_files_properties(source.c
TARGET source_1
OBJECT_OUTPUT source_1.o
COMPILER_FLAGS -DCODE_LOGIC1
)
set_source_files_properties(source.c
TARGET source_2
OBJECT_OUTPUT source_2.o
COMPILER_FLAGS -DCODE_LOGIC2
)
set_source_files_properties(source.c
TARGET source_3
OBJECT_OUTPUT source_3.o
COMPILER_FLAGS -DCODE_LOGIC3
)
add_executable(myexec source_1 source_2 source_3)
The above doesn't work.
You are looking for add_library(<name> OBJECT <source>). With that in mind, you can do:
add_library(source_1 OBJECT source.c)
target_compile_options(source_1 PUBLIC -DLOGIC1)
add_library(source_2 OBJECT source.c)
target_compile_options(source_2 PUBLIC -DLOGIC2)
add_library(source_3 OBJECT source.c)
target_compile_options(source_3 PUBLIC -DLOGIC3)
add_executable(myexec $<TARGET_OBJECTS:source_1> $<TARGET_OBJECTS:source_2> $<TARGET_OBJECTS:source_3>)
Related
i have recently switched my stm32 project to CMake to be independent on IDE. Root repository (application) contains multiple submodules (HAL, FreeRTOS etc.) and its CMakeLists.txt includes explicitly every single used file:
set(EXECUTABLE ${PROJECT_NAME}.elf)
add_executable(${EXECUTABLE}
# Own sources
src/main.c
src/SEGGER_SYSVIEW_Config_FreeRTOS.c
src/startup_stm32h723zgtx.s
src/stm32h7xx_hal_timebase_tim.c
src/system_stm32h7xx.c
# Base CMSIS and HAL library
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c
#long list of HAL c files there...
# FreeRTOS library
lib-freertos/croutine.c
lib-freertos/event_groups.c
lib-freertos/list.c
lib-freertos/queue.c
lib-freertos/stream_buffer.c
lib-freertos/tasks.c
lib-freertos/timers.c
lib-freertos/portable/GCC/ARM_CM7/r0p1/port.c
lib-freertos/trace/Sample/FreeRTOSV10/SEGGER_SYSVIEW_FreeRTOS.c
lib-freertos/trace/SEGGER/Syscalls/SEGGER_RTT_Syscalls_GCC.c
lib-freertos/trace/SEGGER/SEGGER_RTT_ASM_ARMv7M.S
lib-freertos/trace/SEGGER/SEGGER_RTT_printf.c
lib-freertos/trace/SEGGER/SEGGER_RTT.c
lib-freertos/trace/SEGGER/SEGGER_SYSVIEW.c
)
target_include_directories(${EXECUTABLE}
PRIVATE
include
src
lib-hal/stm32h7xx/CMSIS/Include
lib-hal/stm32h7xx/CMSIS/Device/ST/STM32H7xx/Include
lib-hal/stm32h7xx/STM32H7xx_HAL_Driver/Inc
lib-freertos/include
lib-freertos/trace/Config
lib-freertos/trace/SEGGER
lib-freertos/trace/Sample/FreeRTOSV10/
lib-freertos/portable/GCC/ARM_CM7/r0p1
)
This solution works but i know it is not a sustainable approach. So i tried to create library in lib-hal and lib-freertos submodules, specifying their sources and includes
add_library(lib-hal-stm32h7xx)
target_include_directories(lib-hal-stm32h7xx
PUBLIC
CMSIS/Include
CMSIS/Device/ST/STM32H7xx/Include
STM32H7xx_HAL_Driver/Inc
PRIVATE
STM32H7xx_HAL_Driver/Src
)
target_sources(lib-hal-stm32h7xx
PRIVATE
STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim.c
STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_tim_ex.c
STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_uart.c
STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc.c
STM32H7xx_HAL_Driver/Src/stm32h7xx_hal_rcc_ex.c
#long list of HAL c files there...
)
and then using
add_subdirectory(lib-hal/stm32h7xx)
add_subdirectory(lib-freertos)
and
target_link_library(${EXECUTABLE} lib-freertos lib-hal-stm32h7xx)
to "import" submodules into application project. But when building the executable, gcc cannot access files stm32h7xx_hal_conf.h and FreeRTOSConfig.h which are located in root directory include. I do not want to put configuration headers into submodules because they are used in multiple projects with different configurations. Is it possible to somehow extend already specified directory search scope for library after adding it into parent project?
File structure of project:
-src
-include (configuration for lib-hal and lib-freertos included there)
-lib-hal
-includes...
-sources...
-lib-freertos
-includes...
-sources...
Thanks in advance for response.
As Tsyvarev mentioned in the comments, you can modify the properties of the target in your project. To keep things clean, I usually create a function for this and place it in a separate file.
Tip: you can also add source files to the target. In case of FreeRTOS, you could add architecture-specific files, in case all your projects don't run on the same MCU family.
function(configure_freertos target_name)
target_sources(${target_name}
PRIVATE
lib-freertos/portable/GCC/ARM_CM7/r0p1/port.c
)
target_include_directories(${target_name}
PUBLIC
include
lib-freertos/portable/GCC/ARM_CM7/r0p1
)
endfunction()
As the title states, is there a 'neat' way to set per configuration linker flag? It is not possible for me to use target_link_options() since I'm trying to link into a static library. Ideally, what I would want to achieve is to set Visual Studio's Librarian -> Additional Dependencies and Additional Library Directories and achieve the same result in XCode as well.
Here is what I've achieved so far:
set(LIB_LINKS_RUNTIME
${Vulkan_LIBRARIES}
${CMAKE_SOURCE_DIR}/bin/$<CONFIGURATION>/SDL2maind.lib
${CMAKE_SOURCE_DIR}/bin/$<CONFIGURATION>/SDL2d.lib
${CMAKE_SOURCE_DIR}/bin/$<CONFIGURATION>/imgui.lib
)
foreach(lib ${LIB_LINKS_RUNTIME})
set (CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} ${lib}")
endforeach()
According to https://cmake.org/cmake/help/latest/prop_tgt/STATIC_LIBRARY_OPTIONS.html STATIC_LIBRARY_OPTIONS property does the trick
set_property(TARGET Runtime PROPERTY STATIC_LIBRARY_OPTIONS ${LIB_LINKS_RUNTIME})
I'm using add_cusmtom_target to do a custom build, but what properties of this target have? Perticually how can I get the list of dependencies listed in the target:
add_custom_target(exsdk COMMAND echo DEPENDS foo.jar bar.jar)
get_target_property(D exsdk DEPENDS)
D is not found, how can I get the properties of custom target?
So, I'm making part of a project a library with some headers that are the interface to the library, and the remaining are private to the library itself. So for my library the CMAKE part looks like:
add_library(${PROJECT_NAME} ${PROJECT_SOURCES} "${PROJECT_BINARY_DIR}/libversion.h")
add_library(my::lib ALIAS ${PROJECT_NAME})
target_include_directories(${PROJECT_NAME}
PRIVATE ${Boost_INCLUDE_DIRS}
PRIVATE ${PROJECT_BINARY_DIR} #to locate libversion.h
INTERFACE ${PUBLIC_INCLUDE_HEADERS}
)
And then my test target:
add_executable(${TEST_NAME} ${TEST_SOURCES})
add_test(NAME LibTest COMMAND ${TEST_NAME})
target_link_libraries(${TEST_NAME}
PRIVATE ${Boost_LIBRARIES}
PRIVATE my::lib
)
But this only allows me to test my public interface. If I want to unit test my library, how would I go about declaring the access to the remaining headers in project lib? The way I see it would be to add an entire new target my::lib::testing which declares the interface as the current source directory (where all headers currently are located, seperating public from private headers is another issue I've yet to handle). So something like this:
add_library(${PROJECT_NAME}_TESTING ${PROJECT_SOURCES} "${PROJECT_BINARY_DIR}/libversion.h")
add_library(my::lib::testing ALIAS ${PROJECT_NAME}_TESTING)
target_include_directories(${PROJECT_NAME}_TESTING
PRIVATE ${Boost_INCLUDE_DIRS}
PRIVATE ${PROJECT_BINARY_DIR} #to locate libversion.h
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
But this requires two different targets to be build depending on the usage. One for my application linking to alias my::lib and one for unit testing, linking alias my::lib::testing.
So my question is, how do I cleanly separate headers so I can have only my INTERFACE headers shown by targets, but still access the remaining headers by my test target?
Both PRIVATE and PUBLIC items populate the INCLUDE_DIRECTORIES property of an target, so you can try to use it in target_include_directories for the test project.
add_executable(${TEST_NAME} ${TEST_SOURCES})
add_test(NAME LibTest COMMAND ${TEST_NAME})
target_link_libraries(${TEST_NAME}
PRIVATE ${Boost_LIBRARIES}
PRIVATE my::lib
)
target_include_directories( ${TEST_NAME} PRIVATE $<TARGET_PROPERTY:my::lib,INCLUDE_DIRECTORIES>)
I have a precompiled libary that also employes dynamically loaded plugins.
Library L (compoesd ba a library.lib and library.dll)
Plugin P (composed only by a plugin.dll)
I am defining the imported target of L as:
add_library(L SHARED IMPORTED)
set_target_properties(L PROPERTIES
IMPORTED_LOCATION_RELEASE library.dll
IMPLIB_LOCATION_RELEASE library.lib
)
set_target_properties(L PROPERTIES
INTERFACE_LINK_LIBRARIES P
)
How do I define the imported target for P and its properties?
If I define it as:
add_library(P MODULE IMPORTED)
set_target_properties(P PROPERTIES
IMPORTED_LOCATION_RELEASE plugin.dll
)
Then the generated projects using L will erroneously consider plugin.dll as the lib to be linked.
I would like instead to keep the dependency (so that I can transitively install plugin.dll) but avoid L to link target P
I have ended up solving this by not linking L to P using INTERFACE_LINK_LIBRARIES.
I am configuring L by adding an additional variable containing its plugins:
LIST(APPEND L_PLUGINS P)
The targets using L can get access to its plugins by simply using the variable ${L_PLUGIN} (e.g. in order to install its files)
NB: This is the same approach used by Qt plugin components