CMake项目中仅交叉编译指定目标的实现方法
Hey there, I totally get the frustration of having to use a global toolchain file when you only need to cross-compile specific targets—like an embedded unit test suite using Google Test—while keeping the rest of your project building with the host compiler. Let's walk through practical, low-fuss approaches to make this work, along with minimal examples.
Approach 1: Isolate Cross-Compiled Targets with ExternalProject_Add
This is the cleanest method because it creates a completely separate build context for your cross-compiled targets, using your existing toolchain file without touching the rest of your project.
Example Main CMakeLists.txt
# Build your main embedded application with the host compiler (default setup) add_executable(embedded_firmware src/main.c src/driver.c) # Set up the cross-compiled test target as an external project include(ExternalProject) ExternalProject_Add( embedded_unit_tests SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests # Pass your toolchain file to the external project's CMake invocation CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/your_toolchain.cmake BUILD_ALWAYS ON # Rebuild whenever test sources change INSTALL_COMMAND "" # Skip installation since we just need the test binary )
Example Tests/CMakeLists.txt
In this subdirectory, you can set up Google Test just like you would for a normal project—CMake will use the toolchain file you passed to handle cross-compilation:
# Make sure GTest is either cross-compiled alongside or pre-built for your target find_package(GTest REQUIRED) add_executable(unit_test_suite test_driver.cpp test_utils.cpp) target_link_libraries(unit_test_suite GTest::GTest GTest::Main)
Approach 2: Conditionally Apply Toolchain to Subdirectories
If you prefer keeping everything in a single CMake project, you can temporarily set the toolchain file before adding a subdirectory, then reset it afterward. Note: This can have side effects if you're not careful, so use it only for simple setups.
Example
# Main project: builds with host compiler add_executable(host_utils src/host_utils.c) # Switch to cross-compile toolchain for the tests subdirectory set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/your_toolchain.cmake) add_subdirectory(tests) # Reset the toolchain to avoid affecting subsequent targets unset(CMAKE_TOOLCHAIN_FILE)
Approach 3: Quick Custom Target for Simple Cases
For tiny cross-compiled targets, you can skip CMake's internal configuration and directly invoke your cross-compiler via a custom target:
# Host-side build add_executable(embedded_app src/main.c) # Define your cross-compiler path (can also pass via command line) set(CROSS_CC "C:/path/to/your/cross-gcc.exe") set(CROSS_CXX "C:/path/to/your/cross-g++.exe") # Cross-compiled test target add_custom_target( cross_compiled_test COMMAND ${CROSS_CXX} ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_main.cpp -o test_binary -lgtest -lgtest_main DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_main.cpp COMMENT "Cross-compiling unit test..." )
Your Toolchain File (Cleaned Up)
Just to keep things aligned, here's your simplified toolchain file with proper formatting:
SET(CMAKE_SYSTEM_NAME Generic) SET(CMAKE_C_COMPILER "C:/path/to/your/cross-compiler.exe") SET(CMAKE_CXX_COMPILER "C:/path/to/your/cross-cxx.exe") SET(CMAKE_FIND_ROOT_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/ghs") # Adjust find command behavior set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Pro Tips
- Reuse your toolchain file: You don't need to duplicate toolchain definitions—just pass the same file to whichever build context needs cross-compilation.
- Google Test for embedded: If GTest isn't pre-built for your target, use
ExternalProject_Addto build GTest with the same toolchain file before building your tests. - Avoid global overrides: The
ExternalProjectmethod is the most reliable because it prevents conflicts between host and target compiler settings.
内容的提问来源于stack exchange,提问作者sruli

