如何让WSL环境下CMake构建的文件同步回Windows主机?
问题
接手一个基于STM32 MCU的固件项目,该项目已通过Docker定义构建流程,可生成.bin和.elf二进制文件。目前正在搭建Visual Studio 2022 + CMake的开发环境,目标是在WSL发行版中触发构建,并将生成的.elf和.bin文件同步回Windows主机,用于gdb server调试。
已编写简化版CMakeLists.txt(如下),能成功运行现有Docker镜像完成项目构建:
# CMakeList.txt : Top-level CMake project file, do global configuration # and include sub-projects here. # cmake_minimum_required (VERSION 3.8) # Enable Hot Reload for MSVC compilers if supported. if (POLICY CMP0141) cmake_policy(SET CMP0141 NEW) set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>") endif() project ("firmware_cmake") include(ExternalProject) set(DOCKERFILE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) ExternalProject_Add( build_image PREFIX build_image SOURCE_DIR ${DOCKERFILE_DIR} CONFIGURE_COMMAND rm -rf ${CMAKE_SOURCE_DIR}/build/ ${CMAKE_SOURCE_DIR}/Firmware/autogen ${CMAKE_SOURCE_DIR}/Firmware/build ${CMAKE_SOURCE_DIR}/Firmware/.tup BUILD_COMMAND docker build -t build-img . BUILD_IN_SOURCE 1 INSTALL_COMMAND "" ALWAYS TRUE ) ExternalProject_Add( build_cont DEPENDS build_image PREFIX build_cont SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CONFIGURE_COMMAND docker rm build-cont BUILD_COMMAND docker run -i -v ${CMAKE_CURRENT_SOURCE_DIR}:/FW --name build-cont build-img BUILD_IN_SOURCE 1 INSTALL_COMMAND "" ALWAYS TRUE ) add_custom_target(copy-runtime-files ALL COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/build/Firmware.bin ${CMAKE_BINARY_DIR}/Firmware.bin DEPENDS build_cont)
遇到的问题:生成的固件文件构建后未同步回Windows主机——WSL中可看到文件存在于~/.vs/firmware_cmake/out/build/linux-debug/,但Windows端的%path-to-my-project%\out\Ubuntu\build\linux-debug目录下无同步文件。
测试验证:创建cmake-test测试项目(仅含hello-world.cpp),add_executable生成的cmake-test-execute可正常同步,但自定义命令生成的test.txt无法同步。已在CMakePresets.json中配置copyBuildOutput为true。
需求:在不更改现有固件构建方式的前提下,让CMake将.bin/.elf文件标记为输出工件,实现和add_executable生成文件一致的Windows同步效果。
解决方案
方法1:用add_custom_command定义输出文件(推荐)
VS的WSL同步机制仅识别CMake标记为目标输出的文件,add_custom_target本身不关联输出,因此需要先通过add_custom_command明确定义生成的.bin/.elf为输出文件,再让自定义目标依赖这些输出:
# 定义要同步的输出文件路径 set(FIRMWARE_BIN ${CMAKE_BINARY_DIR}/Firmware.bin) set(FIRMWARE_ELF ${CMAKE_BINARY_DIR}/Firmware.elf) # 定义生成输出文件的命令 add_custom_command( OUTPUT ${FIRMWARE_BIN} ${FIRMWARE_ELF} COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/build/Firmware.bin ${FIRMWARE_BIN} COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/build/Firmware.elf ${FIRMWARE_ELF} DEPENDS build_cont # 依赖Docker构建完成 COMMENT "Copying firmware files to build directory" ) # 创建自定义目标,关联上述输出文件 add_custom_target(copy-runtime-files ALL DEPENDS ${FIRMWARE_BIN} ${FIRMWARE_ELF}) # 标记为VS构建输出,确保同步机制识别 set_property(TARGET copy-runtime-files PROPERTY VS_GLOBAL_BuildOutput "${FIRMWARE_BIN};${FIRMWARE_ELF}")
这种方式让CMake明确识别这些文件为构建产物,VS的copyBuildOutput会自动同步它们到Windows主机。
方法2:直接标记目标的输出属性
如果不想修改现有add_custom_target结构,可在目标定义后添加属性,强制标记文件为输出:
add_custom_target(copy-runtime-files ALL COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/build/Firmware.bin ${CMAKE_BINARY_DIR}/Firmware.bin COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/Firmware/build/Firmware.elf ${CMAKE_BINARY_DIR}/Firmware.elf DEPENDS build_cont) # 标记文件为目标的输出 set_property(TARGET copy-runtime-files APPEND PROPERTY OUTPUT "${CMAKE_BINARY_DIR}/Firmware.bin" OUTPUT "${CMAKE_BINARY_DIR}/Firmware.elf") # 告诉VS这些是构建输出 set_property(TARGET copy-runtime-files PROPERTY VS_GLOBAL_BuildOutput "${CMAKE_BINARY_DIR}/Firmware.bin;${CMAKE_BINARY_DIR}/Firmware.elf")
方法3:构建后手动同步(备选)
若上述CMake配置仍不生效,可在CMakePresets.json的构建预设中添加postBuildCommand,直接执行WSL到Windows的复制:
{ "version": 3, "buildPresets": [ { "name": "linux-debug", "configurePreset": "linux-debug", "targets": ["all"], "postBuildCommand": "cp ${sourceDir}/Firmware/build/Firmware* ${sourceDir}/out/Ubuntu/build/linux-debug/" } ] }
注意命令路径为WSL内路径,因构建命令在WSL环境执行,${sourceDir}会自动映射到WSL对应的项目目录。
内容的提问来源于stack exchange,提问作者BDeC

