Was the ASM language simply left out of 3.13’s target_sources relative path changes?
I currently have to use CMAKE_CURRENT_SOURCE_DIR when listing assembly files under INTERFACE sources.
I have the following project tree:
freertos
├── CMakeLists.txt # final static library target is created here if requested
└── portable
├── CMakeLists.txt # includes subdirectories for specific ports based on toolchain
└── GCC # all ports for GCC toolchain variants
└── ARM_CA9
├── CMakeLists.txt # defines sources for GCC_ARM_CA9 port as an interface library
├── port.c
├── portASM.S
└── portmacro.h
When I configure this port with CMake 3.22 I end up with the following error:
My project has ASM language enabled.
If I remove portASM.S from target_sources, CMake configures just fine, but my project will not build without this assembly file.
Do you have the ASM language enabled in your project? Only C and CXX are enabled by default. If you haven’t explicitly enabled ASM, that might mean assembly source file extensions are not handled (that’s just a guess, I haven’t checked the code).
EDIT: Sorry, just saw you already mentioned that in your post.
Previously, ports were defined using generator expressions in portable’s list file. This required -DFREERTOS-PORT to be specified. For CI/CD, we want to be able to compile all targets a toolchain variant & version is able to without having to reconfigure between runs.
A project in the current branch would build with cmake -B build --toolchain freertos/toolchain/gcc-arm.cmake with a similar root-level list file:
###############################################################################
# CMakeLists.txt
###############################################################################
cmake_minimum_required(VERSION 3.16)
project(example C ASM)
add_library(freertos_config INTERFACE)
target_sources(freertos_config INTERFACE FreeRTOSConfig.h)
target_include_directories(freertos_config SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(freertos_config INTERFACE projCOVERAGE_TEST=0)
set(FREERTOS_HEAP "4" CACHE STRING "FreeRTOS heap model number. 1 .. 5. Or absolute path to custom heap source file")
set(FREERTOS_PORT "GCC_ARM_CA9" CACHE STRING "FreeRTOS Port Identifier")
# should really be using fetch content with a paritcular release tag
# but this list file was created for local testing.
add_subdirectory(freertos)
target_compile_options(freertos_kernel
PUBLIC
-mthumb
-mcpu=cortex-a9
-mfpu=auto
-mfloat-abi=hard )
###############################################################################
# FreeRTOS Kernel
# Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT
###############################################################################
###############################################################################
# FreeRTOS/CMakeLists.txt
###############################################################################
cmake_minimum_required(VERSION 3.16)
project(FreeRTOS-Kernel C ASM)
# detect toolchain being used
add_subdirectory( portable )
add_library( freertos_kernel STATIC )
# setup freertos_kernel_core and freertos_heap targets
# user supplies freertos_config target
target_link_libraries( freertos_kernel
PUBLIC
freertos_config
freertos_heap
# Aliased to the target FreeRTOS:Kernel:Port::${FREERTOS_PORT} is aliased to.
freertos_kernel_port
freertos_kernel_core )
###############################################################################
# FreeRTOS/portable/CMakeLists.txt
###############################################################################
###############################################################################
# Helper for defining a FreeRTOS port
# Useful for simple ports
###############################################################################
macro( freertos_define_port )
set(oneValueArgs
NAME ) # name to give to port library
set(multiValueArgs
ALIAS # backwards-compatible name(s)
HEADERS # header files this port uses
SOURCES ) # source files this port uses
cmake_parse_arguments(PORT
""
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN} )
add_library( ${PORT_NAME} INTERFACE )
target_sources( ${PORT_NAME} INTERFACE "${PORT_SOURCES}" )
if( ${CMAKE_VERSION} VERSION_LESS "3.23.0" )
target_sources( ${PORT_NAME} PUBLIC "${PORT_HEADERS}" )
target_include_directories( ${PORT_NAME} INTERFACE . )
else()
target_sources( ${PORT_NAME}
PUBLIC
FILE_SET HEADERS
BASE_DIRS .
FILES "${PORT_HEADERS}" )
endif()
foreach( ALIAS IN LISTS PORT_ALIAS )
add_library( FreeRTOS::Kernel::Port::${ALIAS} ALIAS ${PORT_NAME} )
endforeach()
endmacro()
# while handling specific port names for backwards compatibility:
add_subdirectory( GCC/ARM_CA9 )
get_target_property(target_name
FreeRTOS::Kernel::Port::${FREERTOS_PORT}
ALIASED_TARGET )
add_library(freertos_kernel_port ALIAS ${target_name})
There are dozens of ports we are building with CMake, this is just one of them, hence the macro in portable’s list file. Several of them have various file extensions for ASM, some use inline ASM in a C file which also works just fine.
###############################################################################
# FreeRTOS/portable/GCC/ARM_CA9/CMakeLists.txt ARM CA9 for GCC
###############################################################################
freertos_define_port(
NAME freertos_port_arm_ca9
ALIAS GCC_ARM_CA9
HEADERS
portmacro.h
SOURCES
port.c
portASM.S )
I don’t see anything specific to any particular language in the change that added that behavior. I suggest you open an issue in CMake’s issue tracker. You would be well advised to add a minimal project which demonstrates the problem, as linking to a large, complicated project like yours will make it much less likely for anyone to want to investigate it.
I found the exact problem:
quote-wrapping a dereferenced list passes it semi-colon delimited, while I believe the 3.13 change assumes that the list is merely dereferenced which passes each source space-delimited, as its own variable
That line is incorrect. The ${MY_SOURCES} should not be quoted. The target_sources() command expects each source file as a separate argument. If MY_SOURCES contained more than one file, target_sources() would end up seeing a single file with a semicolon in its file name, not two separate file names. I think what you’re actually seeing is target_sources() sees main.c;emptyasm.s, interprets it as a relative path and prepends ${CMAKE_CURRENT_SOURCE_DIR} to that whole string. From it’s perspective, there is a single file whose name is main.c;emptyasm.s. Then, later on during the generation stage, the semicolon is interpreted as a list separator, so at that point, emptyasm.s is now seen as a separate file.
TLDR: Don’t quote a whole list of files when passing it to target_sources(). Doing so makes it see that as a single file name when deciding whether to prepend a path or not.