如何指示 CMake 使用构建架构编译器
How to instruct CMake to use the build architecture compiler
使用CMake进行交叉编译时,一般通过CMAKE_TOOLCHAIN_FILE
选项指定工具链文件。在 GNU terminology 中,可以使用此文件指定主机架构工具集。但是,通常不能期望能够执行使用此工具链构建的任何内容。很多时候,需要为构建架构编译一些构建工具。
考虑以下设置。我有两个源文件 genfoo.c
和 bar.c
。在构建期间,需要编译 genfoo.c
和 运行。它的输出需要写入foo.h
。然后我可以编译bar.c
,其中#include "foo.h"
。由于 CMake 默认使用主机架构工具链,因此 bar.c
的说明很简单。但是我如何告诉它使用构建架构工具链来编译 genfoo.c
?简单地说 add_executable(genfoo genfoo.c)
将导致使用错误的编译器。
CMake 一次只能处理一个编译器。所以 - 如果你不走很远的路将其他编译器设置为一种新语言 - 你最终将有两个配置周期。
我看到以下方法可以自动执行此过程:
以 CMake 页面中的示例 "CMake Cross Compiling - Using executables in the build created during the build?" 作为起点,我将得到:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()
然后使用如下脚本:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuild
我将通过调用 ./build.sh
.
获得想要的结果
拆分 CMakeLists.txt
,甚至可能用我知道构建工具输出路径的东西替换 export()
/include()
,例如使用 CMAKE_RUNTIME_OUTPUT_DIRECTORY
会简化事情:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
参考资料
- How do I make CMake output into a 'bin' dir?
完全可以在 CMake 中完成。
诀窍是 运行 一个单独的 CMake 配置阶段 在它自己的 space 中,默默地关闭每个交叉编译设置并使用主机的默认工具链,然后将生成的输出导入它的父级,交叉编译构建。
第一部分:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... 然后你添加通常的 add_executable 和任何...
最后:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
当它交叉编译时,它会将主机运行工具的创建典当成它自己专用的space,并将目标导入为"hostwxrc"和"hostgenerate_foo" , 依赖于生成 host_tools 自身 .
当它不交叉编译时,它会按原样构建 wxrc 和 generate_foo,并将它们分别命名为 hostwxrc 和 hostgenerate_foo.
在此之后,当你使用$<TARGET_FILE:wxrc>
时,你指的是为target平台构建的wxrc,$<TARGET_FILE:hostwxrc>
指的是为target平台构建的wxrc 主机平台,不管它们是否相同。
使用CMake进行交叉编译时,一般通过CMAKE_TOOLCHAIN_FILE
选项指定工具链文件。在 GNU terminology 中,可以使用此文件指定主机架构工具集。但是,通常不能期望能够执行使用此工具链构建的任何内容。很多时候,需要为构建架构编译一些构建工具。
考虑以下设置。我有两个源文件 genfoo.c
和 bar.c
。在构建期间,需要编译 genfoo.c
和 运行。它的输出需要写入foo.h
。然后我可以编译bar.c
,其中#include "foo.h"
。由于 CMake 默认使用主机架构工具链,因此 bar.c
的说明很简单。但是我如何告诉它使用构建架构工具链来编译 genfoo.c
?简单地说 add_executable(genfoo genfoo.c)
将导致使用错误的编译器。
CMake 一次只能处理一个编译器。所以 - 如果你不走很远的路将其他编译器设置为一种新语言 - 你最终将有两个配置周期。
我看到以下方法可以自动执行此过程:
以 CMake 页面中的示例 "CMake Cross Compiling - Using executables in the build created during the build?" 作为起点,我将得到:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0) project(FooBarTest) # When crosscompiling import the executable targets if (CMAKE_CROSSCOMPILING) set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build") file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE) include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake) # Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h COMMAND genfoo ) add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h) target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) endif() # Only build the generator if not crosscompiling if (NOT CMAKE_CROSSCOMPILING) add_executable(genfoo genfoo.cpp) export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake") endif()
然后使用如下脚本:
build.sh
#!/bin/bash if [ ! -d hostBuild ]; then cmake -E make_directory hostBuild cmake -E chdir hostBuild cmake .. fi cmake --build hostBuild if [ ! -d crossBuild ]; then cmake -E make_directory crossBuild cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake fi cmake --build crossBuild
我将通过调用
./build.sh
. 获得想要的结果
拆分
CMakeLists.txt
,甚至可能用我知道构建工具输出路径的东西替换export()
/include()
,例如使用CMAKE_RUNTIME_OUTPUT_DIRECTORY
会简化事情:CMakeLists.txt
cmake_minimum_required(VERSION 3.0) project(FooBarTest) # Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h COMMAND genfoo ) add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h) target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0) project(BuildTools) add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash if [ ! -d crossBuild ]; then cmake -E make_directory crossBuild cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake fi if [ ! -d hostBuild ]; then cmake -E make_directory hostBuild cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild fi cmake --build hostBuild cmake --build crossBuild
参考资料
- How do I make CMake output into a 'bin' dir?
完全可以在 CMake 中完成。
诀窍是 运行 一个单独的 CMake 配置阶段 在它自己的 space 中,默默地关闭每个交叉编译设置并使用主机的默认工具链,然后将生成的输出导入它的父级,交叉编译构建。
第一部分:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... 然后你添加通常的 add_executable 和任何...
最后:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
当它交叉编译时,它会将主机运行工具的创建典当成它自己专用的space,并将目标导入为"hostwxrc"和"hostgenerate_foo" , 依赖于生成 host_tools 自身 .
当它不交叉编译时,它会按原样构建 wxrc 和 generate_foo,并将它们分别命名为 hostwxrc 和 hostgenerate_foo.
在此之后,当你使用$<TARGET_FILE:wxrc>
时,你指的是为target平台构建的wxrc,$<TARGET_FILE:hostwxrc>
指的是为target平台构建的wxrc 主机平台,不管它们是否相同。