关于在CMake工具链中获取无后缀<TARGET>以解决自定义C编译器多输出文件问题的问询
This is a common pain point when working with embedded or custom compilers in CMake, so let's break down a clean toolchain-level fix that avoids both redundant linking and unwanted file suffixes.
Core Approach
The key is to leverage CMake's generator expressions to get the suffix-free target name directly in your toolchain configuration, while still letting CMake properly track the main ELF output to prevent redundant builds.
Step 1: Set the ELF Suffix for C Executables
First, tell CMake that your C executables use the .elf suffix. This fixes the redundant linking issue because CMake will now recognize the .elf file as the official target output and track its dependencies correctly:
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
Step 2: Configure Link Command with Generator Expressions
In your CMAKE_C_LINK_EXECUTABLE setting, use the $<TARGET_NAME> generator expression to reference the suffix-free target name for your HEX and MAP outputs. This ensures those files don't inherit the .elf suffix:
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> --elf-output <TARGET> --hex-output $<TARGET_FILE_DIR:<TARGET>>/$<TARGET_NAME>.hex --map-output $<TARGET_FILE_DIR:<TARGET>>/$<TARGET_NAME>.map" )
$<TARGET_NAME>resolves to the exact name you passed toadd_executable(e.g.,fooforadd_executable(foo src/main.c)), so your outputs becomefoo.elf,foo.hex, andfoo.map.$<TARGET_FILE_DIR:<TARGET>>ensures the HEX/MAP files are placed in the same directory as the ELF file, which is useful if you're using subdirectories or out-of-source builds.
Step 3: Add Clean Rules for Extra Outputs (Optional)
To make sure make clean removes the HEX and MAP files too, add a function in your toolchain to automatically set the ADDITIONAL_MAKE_CLEAN_FILES property for all C executable targets:
# Auto-add clean rules for HEX/MAP files function(add_additional_clean_files target) get_target_property(target_type ${target} TYPE) if(target_type STREQUAL "EXECUTABLE") set_target_properties(${target} PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${target}.hex;${CMAKE_CURRENT_BINARY_DIR}/${target}.map" ) endif() endfunction() # Apply the function to all targets (CMake 3.20+) cmake_language(DEFER DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} CALL add_additional_clean_files ${CMAKE_CURRENT_TARGET})
For older CMake versions (pre-3.20), you can use a project include file to iterate over all targets after they're created:
# In your toolchain file set(CMAKE_PROJECT_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/clean_extra_outputs.cmake) # clean_extra_outputs.cmake foreach(target ${CMAKE_PROJECT_TARGETS}) get_target_property(target_type ${target} TYPE) if(target_type STREQUAL "EXECUTABLE") set_target_properties(${target} PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${target}.hex;${CMAKE_CURRENT_BINARY_DIR}/${target}.map" ) endif() endforeach()
Why This Works
- No Redundant Linking: By setting
CMAKE_EXECUTABLE_SUFFIX_C, CMake correctly identifies the.elffile as the primary target output. It will only re-run the linker if dependencies (object files, flags, etc.) change. - Clean File Names:
$<TARGET_NAME>gives you the raw target name without any suffixes, so your HEX/MAP files don't end up with.elf.hexor.elf.map. - Toolchain-Level Logic: All configuration stays in your toolchain file, so project-level CMake code doesn't need extra boilerplate.
内容的提问来源于stack exchange,提问作者PasterOfMuppets

