# ############################################################################## # cmake/nuttx_add_application.cmake # # SPDX-License-Identifier: Apache-2.0 # # Licensed to the Apache Software Foundation (ASF) under one or more contributor # license agreements. See the NOTICE file distributed with this work for # additional information regarding copyright ownership. The ASF licenses this # file to you under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. # # ############################################################################## include(nuttx_parse_function_args) define_property( GLOBAL PROPERTY NUTTX_APPS_LIBRARIES BRIEF_DOCS "NuttX application libs" FULL_DOCS "List of all NuttX application libraries") # Create a directories for the application binaries `bin` for stripped binaries # `bin_debug` for debug binaries if(NOT EXISTS ${NUTTX_BINARY_DIR}/bin) file(MAKE_DIRECTORY ${NUTTX_BINARY_DIR}/bin) endif() if(NOT EXISTS ${NUTTX_BINARY_DIR}/bin_debug) file(MAKE_DIRECTORY ${NUTTX_BINARY_DIR}/bin_debug) endif() # ~~~ # nuttx_add_application # # Description: # Declares a NuttX application as a static library. The corresponding target # will be named apps_. The first entry into the source list is assumed # to be the one containing main() and will thus receive a -Dmain=app_main # definition during build. # # Usage: # nuttx_add_application( NAME [ PRIORITY ] # [ STACKSIZE ] [ COMPILE_FLAGS ] # [ INCLUDE_DIRECTORIES ] [ DEPENDS ] # [ DEFINITIONS ] [ MODULE ] [ SRCS ] ) # # Parameters: # NAME : unique name of application # PRIORITY : priority # STACKSIZE : stack size # COMPILE_FLAGS : compile flags # INCLUDE_DIRECTORIES : include directories # DEPENDS : targets which this module depends on # DEFINITIONS : optional compile definitions # MODULE : if "m", build module (designed to received # CONFIG_ value) # SRCS : source files # NO_MAIN_ALIAS : do not add a main=_main alias(*) # DYNLIB : if "y", build as dynamic loadable library # LINK_FLAGS : link flags only for elf or loadable link # # (*) This is only really needed in convoluted cases where a single .c file # contains differently named _main() entries for different . This # situation should really be changed into a separate main file per actual app # using a shared user library. # # Example: # nuttx_add_application( # NAME test # SRCS file.cpp # STACKSIZE 1024 # DEPENDS nshlib # MODULE ${CONFIG_EXAMPLES_TEST}) # ~~~ function(nuttx_add_application) # parse arguments into variables nuttx_parse_function_args( FUNC nuttx_add_application ONE_VALUE NAME PRIORITY STACKSIZE MODULE DYNLIB UID GID MODE MULTI_VALUE COMPILE_FLAGS LINK_FLAGS INCLUDE_DIRECTORIES SRCS DEPENDS DEFINITIONS OPTIONS NO_MAIN_ALIAS ARGN ${ARGN}) if(NOT NAME) return() endif() string(REPLACE "-" "_" NAME_SYM "${NAME}") # check if SRCS exist if(SRCS) file(GLOB SRCS_EXIST ${SRCS}) endif() # create target if(SRCS_EXIST) if(MODULE AND ("${MODULE}" STREQUAL "m") OR CONFIG_BUILD_KERNEL OR "${DYNLIB}" STREQUAL "y") # create as standalone executable (loadable application or "module") set(TARGET "${NAME}") # determine the compiled elf mode if(CONFIG_BUILD_KERNEL) set(KERNEL_ELF_MODE True) # kernel elf will link all user libs elseif("${MODULE}" STREQUAL "m") set(LOADABLE_ELF_MODE True) # loadable elf only link extra libs elseif("${DYNLIB}" STREQUAL "y") set(DYNLIB_ELF_MODE True) # dynlib elf dont need start obj and other lib endif() # Use ELF capable toolchain, by building manually and overwriting the # non-elf output if(NOT CMAKE_C_ELF_COMPILER) set(ELF_NAME "${NAME}") set(TARGET "ELF_${TARGET}") add_library(${TARGET} ${SRCS}) add_dependencies(${TARGET} apps_post) if(TARGET STARTUP_OBJS) add_dependencies(${TARGET} STARTUP_OBJS) endif() if(NOT "${CMAKE_LD}" MATCHES "gcc$") set(USE_LINKER True) endif() if(STACKSIZE) set(SYMBOL_STACKSIZE $<$>:-Wl,>--defsym nx_stacksize=${STACKSIZE}) endif() if(PRIORITY AND NOT PRIORITY STREQUAL "SCHED_PRIORITY_DEFAULT") set(SYMBOL_PRIORITY $<$>:-Wl,>--defsym nx_priority=${PRIORITY}) endif() if(CONFIG_SCHED_USER_IDENTITY) if(UID) set(SYMBOL_UID $<$>:-Wl,>--defsym nx_uid=${UID}) endif() if(GID) set(SYMBOL_GID $<$>:-Wl,>--defsym nx_gid=${GID}) endif() if(MODE) set(SYMBOL_MODE $<$>:-Wl,>--defsym nx_mode=${MODE}) endif() endif() add_custom_command( TARGET ${TARGET} POST_BUILD COMMAND # add default link option ${CMAKE_LD} -T ${NUTTX_BINARY_DIR}/gnu-elf.ld # add global MOD link option if dynlib link $<$:$> # add global ELF link option if m&kernel link $<$,$>:$> # add local link option last ${LINK_FLAGS} ${SYMBOL_STACKSIZE} ${SYMBOL_PRIORITY} ${SYMBOL_UID} ${SYMBOL_GID} ${SYMBOL_MODE} # link startup obj if m&kernel link $<$,$>>:$> $<$>:-Wl,>--start-group # link user lib if kernel link $<$:$>> # always link extra libs $> $<$>:-Wl,>--whole-archive $ $<$>:-Wl,>--no-whole-archive $<$>:-Wl,>--end-group -o ${NUTTX_BINARY_DIR}/bin_debug/${ELF_NAME} COMMAND ${CMAKE_COMMAND} -E copy ${NUTTX_BINARY_DIR}/bin_debug/${ELF_NAME} ${NUTTX_BINARY_DIR}/bin/${ELF_NAME} # keep the application attribute symbols through strip so the binary # loader can still read them, see NX_KEEP in Application.mk COMMAND ${CMAKE_STRIP} -K nx_stacksize -K nx_priority -K nx_uid -K nx_gid -K nx_mode ${NUTTX_BINARY_DIR}/bin/${ELF_NAME} # match the Application.mk install rule: ld -r output is not marked # executable, but filesystem images built from bin/ must carry the # execute permission COMMAND chmod +x ${NUTTX_BINARY_DIR}/bin/${ELF_NAME} COMMENT "Building ELF:${ELF_NAME}" COMMAND_EXPAND_LISTS) else() add_executable(${TARGET} ${SRCS}) target_link_options( ${TARGET} PRIVATE $> ) endif() # easy access to final ELF, regardless of how it was created set_property(TARGET ${TARGET} PROPERTY ELF_BINARY ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}) nuttx_add_library_internal(${TARGET}) # loadable build requires applying ELF flags to all applications if(CONFIG_MODULES) target_compile_options( ${TARGET} PRIVATE $> ) endif() if(DYNLIB_ELF_MODE) target_compile_options( ${TARGET} PRIVATE $> ) endif() install(TARGETS ${TARGET}) set_property( TARGET nuttx APPEND PROPERTY NUTTX_LOADABLE_APPS ${TARGET}) else() # create as library to be archived into libapps.a set(TARGET "apps_${NAME}") add_library(${TARGET} ${SRCS}) nuttx_add_library_internal(${TARGET}) # add to list of application libraries set_property(GLOBAL APPEND PROPERTY NUTTX_APPS_LIBRARIES ${TARGET}) if(NOT NO_MAIN_ALIAS) # provide main() alias list(GET SRCS 0 MAIN_SRC) set_property( SOURCE ${MAIN_SRC} APPEND PROPERTY COMPILE_DEFINITIONS main=${NAME_SYM}_main) endif() endif() else() set(TARGET "apps_${NAME}") add_custom_target(${TARGET}) set_property(GLOBAL APPEND PROPERTY NUTTX_APPS_ONLY_REGISTER ${TARGET}) set_target_properties(${TARGET} PROPERTIES NO_COMPILABLE_TARGET True) set(NO_COMPILABLE_TARGET True) endif() # apps applications need to depends on apps_context by default add_dependencies(${TARGET} apps_context) # store parameters into properties (used during builtin list generation) set_target_properties(${TARGET} PROPERTIES APP_MAIN ${NAME_SYM}_main) set_target_properties(${TARGET} PROPERTIES APP_NAME ${NAME}) if(PRIORITY) set_target_properties(${TARGET} PROPERTIES APP_PRIORITY ${PRIORITY}) else() set_target_properties(${TARGET} PROPERTIES APP_PRIORITY SCHED_PRIORITY_DEFAULT) endif() if(STACKSIZE) set_target_properties(${TARGET} PROPERTIES APP_STACK ${STACKSIZE}) else() set_target_properties(${TARGET} PROPERTIES APP_STACK ${CONFIG_DEFAULT_TASK_STACKSIZE}) endif() # call target_ options only target is compilable if(NOT NO_COMPILABLE_TARGET) # compile options if(COMPILE_FLAGS) target_compile_options(${TARGET} PRIVATE ${COMPILE_FLAGS}) endif() # compile definitions if(DEFINITIONS) target_compile_definitions(${TARGET} PRIVATE ${DEFINITIONS}) endif() if(INCLUDE_DIRECTORIES) target_include_directories(${TARGET} BEFORE PRIVATE ${INCLUDE_DIRECTORIES}) endif() # Set apps global compile options & definitions hold by nuttx_apps_interface target_compile_options( ${TARGET} PRIVATE $> ) target_compile_definitions( ${TARGET} PRIVATE $> ) target_include_directories( ${TARGET} PRIVATE $> ) endif() # add supplied dependencies if(DEPENDS) # using target_link_libraries for dependencies provides linking as well as # interface include and libraries foreach(dep ${DEPENDS}) nuttx_add_dependencies(TARGET ${TARGET} DEPENDS ${dep}) endforeach() endif() endfunction()