|
|
|
|
cmake_minimum_required(VERSION 3.10)
|
|
|
|
|
|
|
|
|
|
get_filename_component(TARGET_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
|
|
|
|
string(TOUPPER ${TARGET_NAME} TARGET_NAME_UPPER)
|
|
|
|
|
|
|
|
|
|
if(DEFINED BUILD_${TARGET_NAME_UPPER}_HAS_TEST)
|
|
|
|
|
set(MY_HAS_TEST ${BUILD_${TARGET_NAME_UPPER}_HAS_TEST})
|
|
|
|
|
else()
|
|
|
|
|
set(MY_HAS_TEST OFF)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(MY_HAS_TEST)
|
|
|
|
|
option(BUILD_${TARGET_NAME_UPPER}_STANDALONE "Build ${TARGET_NAME_UPPER} as a standalone executable" OFF)
|
|
|
|
|
# mark_as_advanced(BUILD_${TARGET_NAME_UPPER}_STANDALONE)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(FINAL_MODULE_SRCS "")
|
|
|
|
|
set(FLAT_SRC_DIR "${CMAKE_BINARY_DIR}/flat_sources/${TARGET_NAME}")
|
|
|
|
|
set(NEED_FLATTEN FALSE)
|
|
|
|
|
|
|
|
|
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
|
|
|
|
set(IS_TOP_LEVEL TRUE)
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Detected Top-Level Project. Enabling recursive flatten build.")
|
|
|
|
|
set(NEED_FLATTEN TRUE)
|
|
|
|
|
else()
|
|
|
|
|
set(IS_TOP_LEVEL FALSE)
|
|
|
|
|
file(GLOB ALL_C_FILES "*.c")
|
|
|
|
|
set(MODULE_SRCS "")
|
|
|
|
|
foreach(SRC_FILE ${ALL_C_FILES})
|
|
|
|
|
get_filename_component(FILE_NAME ${SRC_FILE} NAME)
|
|
|
|
|
if(FILE_NAME MATCHES ".*~$" OR FILE_NAME MATCHES "\\.bak$" OR FILE_NAME MATCHES "\\.swp$")
|
|
|
|
|
continue()
|
|
|
|
|
else()
|
|
|
|
|
list(APPEND MODULE_SRCS ${SRC_FILE})
|
|
|
|
|
endif()
|
|
|
|
|
endforeach()
|
|
|
|
|
set(FINAL_MODULE_SRCS ${MODULE_SRCS})
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(NEED_FLATTEN)
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Searching for files in: ${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
|
|
|
|
|
|
file(GLOB_RECURSE ALL_SOURCE_FILES
|
|
|
|
|
CONFIGURE_DEPENDS
|
|
|
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.c"
|
|
|
|
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
set(FILTERED_SOURCE_FILES "")
|
|
|
|
|
foreach(SRC_FILE ${ALL_SOURCE_FILES})
|
|
|
|
|
get_filename_component(ABS_FILE ${SRC_FILE} ABSOLUTE)
|
|
|
|
|
|
|
|
|
|
if(ABS_FILE MATCHES "^${CMAKE_BINARY_DIR}")
|
|
|
|
|
continue()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
get_filename_component(FILE_NAME ${SRC_FILE} NAME)
|
|
|
|
|
if(FILE_NAME MATCHES "CMakeCCompilerId\\.c$" OR FILE_NAME MATCHES "CMakeTmp")
|
|
|
|
|
continue()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(FILE_NAME MATCHES ".*~$" OR FILE_NAME MATCHES "\\.bak$" OR FILE_NAME MATCHES "\\.swp$")
|
|
|
|
|
continue()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
list(APPEND FILTERED_SOURCE_FILES ${SRC_FILE})
|
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
|
|
set(ALL_SOURCE_FILES ${FILTERED_SOURCE_FILES})
|
|
|
|
|
|
|
|
|
|
list(LENGTH ALL_SOURCE_FILES FILE_COUNT)
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Found ${FILE_COUNT} valid files after filtering.")
|
|
|
|
|
|
|
|
|
|
if(NOT ALL_SOURCE_FILES)
|
|
|
|
|
message(FATAL_ERROR "[${TARGET_NAME}] No valid source files found after filtering.")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(FLAT_SRCS_LIST "")
|
|
|
|
|
set(COPY_COMMANDS "")
|
|
|
|
|
|
|
|
|
|
foreach(SRC_FILE ${ALL_SOURCE_FILES})
|
|
|
|
|
get_filename_component(FILE_NAME ${SRC_FILE} NAME)
|
|
|
|
|
get_filename_component(FILE_EXT ${SRC_FILE} EXT)
|
|
|
|
|
|
|
|
|
|
set(DEST_FILE "${FLAT_SRC_DIR}/${FILE_NAME}")
|
|
|
|
|
|
|
|
|
|
if(EXISTS "${DEST_FILE}")
|
|
|
|
|
message(WARNING "[${TARGET_NAME}] Filename conflict: '${FILE_NAME}'. Skipping ${SRC_FILE}.")
|
|
|
|
|
continue()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
list(APPEND COPY_COMMANDS
|
|
|
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SRC_FILE} ${DEST_FILE}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if(FILE_EXT STREQUAL ".c")
|
|
|
|
|
list(APPEND FLAT_SRCS_LIST ${DEST_FILE})
|
|
|
|
|
endif()
|
|
|
|
|
endforeach()
|
|
|
|
|
|
|
|
|
|
set(FINAL_MODULE_SRCS ${FLAT_SRCS_LIST})
|
|
|
|
|
|
|
|
|
|
if(NOT FINAL_MODULE_SRCS)
|
|
|
|
|
message(FATAL_ERROR "[${TARGET_NAME}] No .c files found to compile!")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
add_custom_target(${TARGET_NAME}_flatten_sources
|
|
|
|
|
${COPY_COMMANDS}
|
|
|
|
|
COMMENT "[${TARGET_NAME}] Flattening sources..."
|
|
|
|
|
BYPRODUCTS ${FLAT_SRC_DIR}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${FLAT_SRC_DIR}")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(MODULE_SRCS ${FINAL_MODULE_SRCS})
|
|
|
|
|
|
|
|
|
|
if(NOT MODULE_SRCS AND NOT NEED_FLATTEN)
|
|
|
|
|
if(NOT IS_TOP_LEVEL)
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] No source files found. Creating INTERFACE (header-only) library.")
|
|
|
|
|
add_library(${TARGET_NAME} INTERFACE)
|
|
|
|
|
set(INTERFACE_INCLUDES "")
|
|
|
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
|
|
|
list(APPEND INTERFACE_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
|
|
|
endif()
|
|
|
|
|
if(EXISTS "${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}")
|
|
|
|
|
list(APPEND INTERFACE_INCLUDES "${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}")
|
|
|
|
|
endif()
|
|
|
|
|
if(EXISTS "${PROJECT_SOURCE_DIR}/include")
|
|
|
|
|
list(APPEND INTERFACE_INCLUDES "${PROJECT_SOURCE_DIR}/include")
|
|
|
|
|
endif()
|
|
|
|
|
target_include_directories(${TARGET_NAME} INTERFACE ${INTERFACE_INCLUDES})
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] INTERFACE includes: ${INTERFACE_INCLUDES}")
|
|
|
|
|
return()
|
|
|
|
|
endif()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(EXPLICIT_STANDALONE OFF)
|
|
|
|
|
if(DEFINED BUILD_${TARGET_NAME_UPPER}_STANDALONE AND BUILD_${TARGET_NAME_UPPER}_STANDALONE)
|
|
|
|
|
set(EXPLICIT_STANDALONE ON)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(IMPLICIT_STANDALONE OFF)
|
|
|
|
|
if(IS_TOP_LEVEL AND DEFINED MAIN AND MAIN)
|
|
|
|
|
set(IMPLICIT_STANDALONE ON)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(EXPLICIT_STANDALONE OR IMPLICIT_STANDALONE)
|
|
|
|
|
set(SHOULD_BUILD_EXECUTABLE TRUE)
|
|
|
|
|
else()
|
|
|
|
|
set(SHOULD_BUILD_EXECUTABLE FALSE)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(NEED_FLATTEN AND FINAL_MODULE_SRCS)
|
|
|
|
|
set_source_files_properties(${FINAL_MODULE_SRCS} PROPERTIES GENERATED TRUE)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(SHOULD_BUILD_EXECUTABLE)
|
|
|
|
|
set(CURRENT_TARGET_NAME ${TARGET_NAME})
|
|
|
|
|
add_executable(${CURRENT_TARGET_NAME} ${MODULE_SRCS})
|
|
|
|
|
|
|
|
|
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
|
|
|
target_compile_definitions(${CURRENT_TARGET_NAME} PUBLIC DEBUG)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
target_compile_definitions(${TARGET_NAME} PRIVATE ${GLOBAL_ENABLED_MACROS})
|
|
|
|
|
|
|
|
|
|
if(NEED_FLATTEN)
|
|
|
|
|
add_dependencies(${CURRENT_TARGET_NAME} ${TARGET_NAME}_flatten_sources)
|
|
|
|
|
target_include_directories(${CURRENT_TARGET_NAME} PRIVATE ${FLAT_SRC_DIR})
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
target_compile_definitions(${CURRENT_TARGET_NAME} PRIVATE MAIN STANDALONE_BUILD)
|
|
|
|
|
set_target_properties(${CURRENT_TARGET_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/output)
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Building Standalone: ${CURRENT_TARGET_NAME} (Sources count: ${MODULE_SRCS})")
|
|
|
|
|
else()
|
|
|
|
|
set(CURRENT_TARGET_NAME ${TARGET_NAME})
|
|
|
|
|
if(MY_BUILD_STATIC)
|
|
|
|
|
add_library(${TARGET_NAME} STATIC ${MODULE_SRCS})
|
|
|
|
|
else()
|
|
|
|
|
add_library(${TARGET_NAME} SHARED ${MODULE_SRCS})
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
|
|
|
|
target_compile_definitions(${TARGET_NAME} PUBLIC DEBUG)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
target_compile_definitions(${TARGET_NAME} PRIVATE ${GLOBAL_ENABLED_MACROS})
|
|
|
|
|
|
|
|
|
|
if(NEED_FLATTEN)
|
|
|
|
|
add_dependencies(${CURRENT_TARGET_NAME} ${TARGET_NAME}_flatten_sources)
|
|
|
|
|
target_include_directories(${CURRENT_TARGET_NAME} PRIVATE ${FLAT_SRC_DIR})
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set_target_properties(${TARGET_NAME} PROPERTIES
|
|
|
|
|
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/output
|
|
|
|
|
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/output
|
|
|
|
|
)
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
set(MY_PUBLIC_INCLUDES "")
|
|
|
|
|
|
|
|
|
|
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
|
|
|
list(APPEND MY_PUBLIC_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Found local include: ${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(EXISTS "${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}")
|
|
|
|
|
list(APPEND MY_PUBLIC_INCLUDES "${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}")
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Found global sub-include: ${PROJECT_SOURCE_DIR}/include/${TARGET_NAME}")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(EXISTS "${PROJECT_SOURCE_DIR}/include")
|
|
|
|
|
list(APPEND MY_PUBLIC_INCLUDES "${PROJECT_SOURCE_DIR}/include")
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Found global root include: ${PROJECT_SOURCE_DIR}/include")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
if(NOT MY_PUBLIC_INCLUDES)
|
|
|
|
|
if(NEED_FLATTEN)
|
|
|
|
|
list(APPEND MY_PUBLIC_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
|
else()
|
|
|
|
|
list(APPEND MY_PUBLIC_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
|
endif()
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Fallback to source dir: ${CMAKE_CURRENT_SOURCE_DIR}")
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
target_include_directories(${CURRENT_TARGET_NAME}
|
|
|
|
|
PUBLIC ${MY_PUBLIC_INCLUDES}
|
|
|
|
|
${PROJECT_SOURCE_DIR}/../Core/Inc
|
|
|
|
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
target_link_libraries(${CURRENT_TARGET_NAME}
|
|
|
|
|
PRIVATE m
|
|
|
|
|
stm32cubemx
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
string(TOLOWER "${CMAKE_SYSTEM_NAME}" SYSTEM_NAME_LOWER)
|
|
|
|
|
if(CMAKE_CROSSCOMPILING AND NOT SYSTEM_NAME_LOWER MATCHES "linux|windows|darwin|android")
|
|
|
|
|
message(STATUS ">>> 检测到裸机/RTOS 环境 (${CMAKE_SYSTEM_NAME}),屏蔽 pthread。")
|
|
|
|
|
else()
|
|
|
|
|
find_package(Threads REQUIRED)
|
|
|
|
|
target_link_libraries(${CURRENT_TARGET_NAME}
|
|
|
|
|
PUBLIC Threads::Threads
|
|
|
|
|
PRIVATE ${CMAKE_DL_LIBS}
|
|
|
|
|
)
|
|
|
|
|
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
|
|
|
|
target_link_libraries(${CURRENT_TARGET_NAME} PRIVATE rt)
|
|
|
|
|
endif()
|
|
|
|
|
endif()
|
|
|
|
|
|
|
|
|
|
target_compile_options(${CURRENT_TARGET_NAME}
|
|
|
|
|
PRIVATE
|
|
|
|
|
-Wall
|
|
|
|
|
$<$<CONFIG:Debug>:-g -O0>
|
|
|
|
|
$<$<CONFIG:Release>:-O2>
|
|
|
|
|
-ffunction-sections -fdata-sections
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
target_link_options(${CURRENT_TARGET_NAME}
|
|
|
|
|
PRIVATE
|
|
|
|
|
-Wl,--gc-sections
|
|
|
|
|
$<$<CONFIG:Release>:-s>
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
message(STATUS "[${TARGET_NAME}] Configured target: ${CURRENT_TARGET_NAME}")
|