【问题标题】:How to instruct CMake to use the build architecture compiler如何指示 CMake 使用构建架构编译器
【发布时间】:2016-07-10 11:43:12
【问题描述】:

使用 CMake 进行交叉编译时,通常通过 CMAKE_TOOLCHAIN_FILE 选项指定工具链文件。在GNU terminology 中,可以使用此文件指定主机架构工具集。但是,通常不能期望能够执行使用此工具链构建的任何内容。很多时候,需要为构建架构编译一些构建工具。

考虑以下设置。我有两个源文件genfoo.cbar.c。在构建期间,genfoo.c 需要编译并运行。它的输出需要写入foo.h。然后我可以编译bar.c,其中#include "foo.h"。由于 CMake 默认使用主机架构工具链,bar.c 的说明很简单。但是我如何告诉它使用构建架构工具链来编译genfoo.c?简单地说add_executable(genfoo genfoo.c) 会导致使用错误的编译器。

【问题讨论】:

  • 正如您所说,在 GNU 术语中,您将使用 configure 命令来指定主机架构。如果要为两个不同的主机环境构建,则必须运行 configure 两次。所以我看到了 CMake 的两种可能性:使用构建脚本来创建和执行所需的两个环境(参见 here)或使用 ExternalProject_Add() 并将您的 CMakeLists.txt 拆分为专用的子项目。
  • 不,使用自动工具,您只需使用 CC_FOR_BUILD。见ax_cc_for_build
  • 好吧,不知道那个。如果我理解正确,我们谈论的是CMake Cross Compiling - Using executables in the build created during the build? 中描述的用例
  • @Florian 我相信您应该使用该链接做出回答,因为它回答了我的大部分问题。我不喜欢采用的方法,但它确实解决了手头的问题。我最初没有意识到这是一种解决方案,因为它给用户带来了(构建两次)的负担。
  • 也许还可以考虑here 描述的方法,其中需要在 CMake 运行中构建可执行文件,以便它可以用于生成源代码甚至其他 CMakeLists.txt 文件。我让它在 OS X 上为 iOS 构建生成文件,所以它在实践中适用于像你这样的情况。

标签: cmake cross-compiling


【解决方案1】:

CMake 一次只能处理一个编译器。所以 - 如果你不把其他编译器设置为一种新语言 - 你最终会得到两个配置周期。

我看到了以下自动化此过程的方法:

  1. 以 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来获得想要的结果。

  2. 拆分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
    

参考文献

【讨论】:

    【解决方案2】:

    在 CMake 中完全可以做到这一点。

    诀窍是在它自己的空间内运行一个单独的 CMake 配置阶段,静默关闭每个交叉编译设置并使用主机的默认工具链,然后将生成的输出导入它的父级,交叉编译构建。

    第一部分:

    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()
    

    当它交叉编译时,它会将主机运行工具的创建放到自己的专用空间中,并将目标导入为“hostwxrc”和“hostgenerate_foo”,并依赖于生成主机工具它们自己 em> .

    当它不交叉编译时,它会按原样构建 wxrc 和 generate_foo,并将它们别名为 hostwxrc 和 hostgenerate_foo。

    之后,当你使用$&lt;TARGET_FILE:wxrc&gt;时,你指的是为target平台构建的wxrc,$&lt;TARGET_FILE:hostwxrc&gt;指的是为host构建的wxrc平台,不管它们是否相同。

    【讨论】:

    • 使用这种方法,您可能需要在使用 exec_process 调用主机 cmake 之前清除 CXX/CC 环境变量。即set(ENV{CXX} "")set(ENV{CC} "")
    猜你喜欢
    • 1970-01-01
    • 2011-07-17
    • 2013-02-26
    • 2019-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多