Files
esp-idf/components/freertos/CMakeLists.txt
Guillaume Souchere 9835daba70 feat(freertos/vfs): add Linux cooperative syscall dispatch with VFS FD registration
Rework the syscall interposition architecture so FreeRTOS works
standalone (without VFS) and VFS optionally overrides with strong
symbols.  All kernel FDs are registered with VFS via
esp_vfs_register_fd_with_local_fd, so the application only sees
VFS-allocated FD numbers, preventing numerical collisions between
kernel FDs and VFS-internal FD slots.

FreeRTOS side:
- Create linux_port_coop_internal.h with LINUX_COOP_IO_LOOP,
  LINUX_COOP_RESOLVE, linux_coop_yield and FD state table functions
- Export cooperative I/O primitives (freertos_linux_coop_read/write/
  open/close/fcntl/select/pread/pwrite/readv/writev/recv/send/
  recvfrom/sendto/recvmsg/sendmsg/connect/accept/pselect/poll/
  socket/socketpair/pipe/pipe2/dup/dup2/syscalls_init)
- Define weak POSIX symbols calling through to the cooperative
  primitives; keep nanosleep/sleep/usleep as strong (not FD-related)
- Refactor freertos_linux_coop_syscalls.h into a pure public API header

VFS side:
- Register the Linux host FS with esp_vfs_register_fs_with_id() as a
  proper VFS driver; register stdin/stdout/stderr at init (priority 99)
- Rewrite vfs_linux.c with strong POSIX symbols dispatching through
  esp_vfs_*
- Add strong overrides for FD-creating syscalls (open, pipe, pipe2,
  socket, socketpair, dup, dup2, accept) that register returned FDs
  with VFS
- Add strong overrides for FD-translating syscalls (readv, writev,
  recv, send, recvfrom, sendto, recvmsg, sendmsg, connect, pselect,
  poll) that translate VFS FD to kernel FD
- Delete vfs_coop_syscalls.c (absorbed into FreeRTOS weak + VFS strong)
- Update CMakeLists.txt: remove vfs_coop_syscalls.c, add linker hook
2026-06-04 11:36:34 +02:00

256 lines
9.1 KiB
CMake

# FreeRTOS Component Architecture
#
# The FreeRTOS component mainly contains
# - Different FreeRTOS kernel implementations (namely IDF FreeRTOS and Amazon SMP FreeRTOS).
# - Different ports of each architecture for each kernel implementation.
# - IDF additions to FreeRTOS (e.g., features and API) to augment FreeRTOS
#
# The FreeRTOS component organizes its files as follows
#
# - `./config`
# - Contains all "FreeRTOSConfig.h" files required by FreeRTOS
# - `./esp_additions`
# - Additional features added by ESP-IDF to augment FreeRTOS, and not part of the original kernel
# - `./FreeRTOS-Kernel-...`
# - Different FreeRTOS kernel implementations. Each implementation is kept in its own directory.
# - Ports for the implementation are kept in `FreeRTOS-Kernel-.../portable/xxx/`\
# - `./test_apps`
# - Contains all unit tests/test apps for the FreeRTOS component.
# - `./`
# - Files common across all kernel implementations and all ports
# Bootloader builds only needs FreeRTOS for config, not for anything else
idf_build_get_property(non_os_build NON_OS_BUILD)
if(non_os_build)
idf_component_register()
return()
endif()
# Set some convenience variables
idf_build_get_property(target IDF_TARGET)
if(CONFIG_FREERTOS_SMP)
set(kernel_impl "FreeRTOS-Kernel-SMP")
else()
set(kernel_impl "FreeRTOS-Kernel")
endif()
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
set(arch "xtensa")
elseif(CONFIG_IDF_TARGET_ARCH_RISCV)
set(arch "riscv")
elseif(${target} STREQUAL "linux")
set(arch "linux")
endif()
set(srcs "")
set(include_dirs "")
set(private_include_dirs "")
set(private_requirements "")
set(ldfragments "")
# ---------------------------------------------------- Set Private Requirements ----------------------------------------
list(APPEND private_requirements esp_hal_systimer)
# ---------------------------------------------------- Set Sources -----------------------------------------------------
# Add common source files
list(APPEND srcs
"heap_idf.c")
if((arch STREQUAL "xtensa") OR (arch STREQUAL "riscv"))
list(APPEND srcs
"app_startup.c"
"port_common.c"
"port_systick.c")
endif()
# Add FreeRTOS Kernel source files
list(APPEND srcs
"${kernel_impl}/list.c"
"${kernel_impl}/queue.c"
"${kernel_impl}/tasks.c"
"${kernel_impl}/timers.c"
"${kernel_impl}/event_groups.c"
"${kernel_impl}/stream_buffer.c")
# Add port source files
list(APPEND srcs
"${kernel_impl}/portable/${arch}/port.c")
if(arch STREQUAL "linux")
list(APPEND srcs
"${kernel_impl}/portable/${arch}/utils/wait_for_event.c"
"${kernel_impl}/portable/${arch}/utils/linux_port_coop_syscalls.c")
if(kernel_impl STREQUAL "FreeRTOS-Kernel")
list(APPEND srcs
"${kernel_impl}/portable/${arch}/port_idf.c")
endif()
else()
list(APPEND srcs
"${kernel_impl}/portable/${arch}/portasm.S")
endif()
if(arch STREQUAL "xtensa")
list(APPEND srcs
"${kernel_impl}/portable/${arch}/xtensa_init.c"
"${kernel_impl}/portable/${arch}/xtensa_overlay_os_hook.c")
endif()
# Add ESP-additions source files
list(APPEND srcs
"esp_additions/idf_additions_event_groups.c"
"esp_additions/idf_additions.c")
# ------------------------------------------------ Set Public Includes -------------------------------------------------
# Add common public include directories
list(APPEND include_dirs
"config/include" # For `#include "freertos/FreeRTOSConfig.h"`
"config/include/freertos" # For `#include "FreeRTOSConfig.h"`
"config/${arch}/include") # For `#include "freertos/FreeRTOSConfig_arch.h"`
# Add FreeRTOS Kernel public include directories
list(APPEND include_dirs
"${kernel_impl}/include") # FreeRTOS headers via `#include "freertos/xxx.h"`
# Add port public include directories
list(APPEND include_dirs
"${kernel_impl}/portable/${arch}/include" # For port headers via `#include "freertos/...h"`
"${kernel_impl}/portable/${arch}/include/freertos") # For port headers via `#include "...h"`
# Add ESP-additions public include directories
list(APPEND include_dirs
"esp_additions/include") # For ESP-addition headers via
# - `#include "freertos/...h"`
# - `#include "esp_private/...h"`
# ----------------------------------------------- Set Private Includes -------------------------------------------------
# Add common private include directories
if((arch STREQUAL "xtensa") OR (arch STREQUAL "riscv"))
list(APPEND private_include_dirs
".") # For `#include "port_systick.h"
endif()
# Add FreeRTOS Kernel private include directories
list(APPEND private_include_dirs
"${kernel_impl}/include/freertos") # FreeRTOS headers via `#include "xxx.h"`
# Add port private include directories
if(arch STREQUAL "linux")
list(APPEND private_include_dirs
"${kernel_impl}/portable/${arch}/") # Linux port `#include "utils/wait_for_event.h"`
endif()
# Add ESP-additions private include directories
list(APPEND private_include_dirs
"esp_additions") # For `include "freertos_tasks_c_additions.h"`
# ------------------------------------------------------- Misc ---------------------------------------------------------
# Add linker fragments
list(APPEND ldfragments
"linker_common.lf")
if((arch STREQUAL "xtensa") OR (arch STREQUAL "riscv"))
if(kernel_impl STREQUAL "FreeRTOS-Kernel-SMP")
list(APPEND ldfragments
"linker_smp.lf")
else()
list(APPEND ldfragments
"linker.lf")
endif()
endif()
# ------------------------------------------------ Register Component --------------------------------------------------
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include_dirs}
PRIV_INCLUDE_DIRS ${private_include_dirs}
LDFRAGMENTS ${ldfragments}
PRIV_REQUIRES ${private_requirements})
if(arch STREQUAL "linux")
target_compile_definitions(${COMPONENT_LIB} PUBLIC "projCOVERAGE_TEST=0")
target_link_libraries(${COMPONENT_LIB} PUBLIC pthread)
# dl is needed for dlsym(RTLD_NEXT, ...) used by the cooperative syscall
# interposition layer (linux_port_coop_syscalls.c)
target_link_libraries(${COMPONENT_LIB} PRIVATE dl)
# Disable strict prototype warnings in upstream code
# (struct event * event_create() is missing 'void')
set_source_files_properties(
"${kernel_impl}/portable/${arch}/utils/wait_for_event.c"
PROPERTIES COMPILE_OPTIONS
"-Wno-strict-prototypes"
)
if(APPLE)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _app_main")
else()
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main")
endif()
else()
idf_component_get_property(COMPONENT_DIR freertos COMPONENT_DIR)
idf_component_set_property(freertos ORIG_INCLUDE_PATH "${COMPONENT_DIR}/${kernel_impl}/include/freertos/")
if(CONFIG_FREERTOS_DEBUG_OCDAWARE)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=FreeRTOS_openocd_params")
endif()
set_source_files_properties(
tasks.c
event_groups.c
timers.c
queue.c
stream_buffer.c
PROPERTIES COMPILE_DEFINITIONS
_ESP_FREERTOS_INTERNAL
)
# The freertos component provides the `start_app` and `start_app_other_cores`
# if it is included in the build. It then calls `app_main`
# from the main task created, which must be provided by the user.
# Like for `start_app` and `start_app_other_cores`,
# we can't establish dependency on what we don't yet know, so we force the
# linker to not drop this symbol.
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main")
if(CONFIG_ESP_TRACE_ENABLE)
idf_component_optional_requires(PUBLIC esp_trace)
endif()
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
# [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() calls esp_gdbstub_init() (called on CPU0).
# This should be resolved when link-time registration of startup functions is added.
idf_component_optional_requires(PRIVATE esp_gdbstub)
endif()
if(CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER)
# [refactor-todo]: esp_timer is required by FreeRTOS when we use esp_timer_get_time() to do profiling
# Introduce a port wrapper function to avoid including esp_timer.h into the public header
idf_component_optional_requires(PUBLIC esp_timer)
endif()
if(CONFIG_SPIRAM)
idf_component_optional_requires(PRIVATE esp_psram)
endif()
if(CONFIG_PM_TRACE)
# esp_pm is required by port_systick.c for tracing
idf_component_optional_requires(PRIVATE esp_pm)
endif()
if(NOT CONFIG_FREERTOS_SMP AND
CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # suppress false-positive warning
set_source_files_properties(
"${kernel_impl}/queue.c"
PROPERTIES COMPILE_OPTIONS
"-Wno-analyzer-null-argument"
)
endif()
endif()