如何在Windows上使用cmake + arm-none-eabi进行交叉编译?

10

我希望能够在Windows构建服务器上自动化几个项目的交叉编译工作。但是我在使用arm交叉编译器方面遇到了一些问题。安装似乎有点困难。cmake编译器检查失败,出现链接错误(见下文)。

我的实验项目如下:

main.cpp - a test programm
CMakeLists.txt - the cmake build script
cmake/STM32F2xx.cmake - the special settings for the ARM STM32F2xx-series

我正在使用三个包:

cmake-3.8.0-win64-x64.msi -cmake for windows
mingw-w64-install.exe - mingw 64 for windows
gcc-arm-none-eabi-6-2017-q1-update-win32.exe - arm x compiler

主要的.cpp文件包含以下内容:
int main(void) {
    return 0;
}

CMakeLists.txt 包含以下内容:
cmake_minimum_required (VERSION 3.0)
# module name
set(PrjName testPrj) 

project (${PrjName})
# module version
set(PCK_MAJOR 1)
set(PCK_MINOR 0)
set(PCK_REVISION 0)

#####################
# Features switches
#####################

#####################
# architecture
#####################
# possible values:
#   NATIVE
#   STM32F2xx

SET(Arch NATIVE CACHE STRING "Architecture")

#############################
# software stack search path
############################
SET(SWstackPath NONE CACHE STRING "software stack search path")

#############################
# software stack handling
############################
if (${SWstackPath} STREQUAL NONE)
else ()
    include_directories(${SWstackPath})
endif()

#############################
# package creation
#############################
SET(PackageFormat "DEFAULT" CACHE STRING "the format of the installation package")


########################
# define module content
########################

# MetaData header
set(testApp "testApp")

set(${testApp}_VERSION_MAJOR 1)
set(${testApp}_VERSION_MINOR 2)
set(${testApp}_VERSION_REVISION 3)
set(${testApp}_SOVERSION 4)

########################
# architecture handling
########################
if(${Arch} STREQUAL NATIVE)
    MESSAGE("Architecture is set to NATIVE")
else()
    include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/${Arch}.cmake)
endif()

if (${PackageFormat} STREQUAL "DEFAULT")
    if (UNIX)
        include(GNUInstallDirs)
        set(CPACK_GENERATOR "DEB")
    else ()
        set(CPACK_GENERATOR "ZIP")
        set(CMAKE_INSTALL_FULL_BINDIR "bin")
        set(CMAKE_INSTALL_FULL_LIBDIR "lib")
        set(CMAKE_INSTALL_FULL_LIBDIRSTATIC "lib")
        set(CMAKE_INSTALL_FULL_INCLUDEDIR "include")
        set(CMAKE_INSTALL_FULL_MANDIR "doc")
    endif()
elseif(${PackageFormat} STREQUAL "ZIP")
    set(CPACK_GENERATOR "ZIP")
    set(CMAKE_INSTALL_FULL_BINDIR "bin")
    set(CMAKE_INSTALL_FULL_LIBDIR "lib")
    set(CMAKE_INSTALL_FULL_LIBDIRSTATIC "lib")
    set(CMAKE_INSTALL_FULL_INCLUDEDIR "include")
    set(CMAKE_INSTALL_FULL_MANDIR "doc")
else()
    message( FATAL_ERROR "The PackageFormat is unknown")
endif()

################################
# compile of the module content
################################

list(APPEND testApp_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
)

add_executable(${testApp}
    ${testApp_sources}
)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set_target_properties(${testApp} PROPERTIES
    LINKER_LANGUAGE CXX
)

################################
# installation
################################
if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")

    # install app
    install(
        TARGETS ${testApp}
        RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_BINDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/static
    )

    set(CPACK_PACKAGE_DESCRIPTION "test")
    set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "test")
    set(CPACK_PACKAGE_VENDOR "xxx")
    set(CPACK_PACKAGE_CONTACT "xxx")
    set(CPACK_PACKAGE_VERSION_MAJOR "${PCK_MAJOR}")
    set(CPACK_PACKAGE_VERSION_MINOR "${PCK_MINOR}")
    set(CPACK_PACKAGE_VERSION_PATCH "${PCK_REVISION}")
    set(CPACK_PACKAGE_FILE_NAME "${PrjName}_${PCK_MAJOR}.${PCK_MINOR}.${PCK_REVISION}")
    set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PrjName}_${PCK_MAJOR}.${PCK_MINOR}.${PCK_REVISION}")

    include(CPack)
endif()

cmake/STM32F2xx.cmake包含以下内容:

set(CMAKE_C_FLAGS_INIT "--cpu Cortex-M3")
set(CMAKE_CXX_FLAGS_INIT "--cpu Cortex-M3")
set(CMAKE_C_LINK_FLAGS_INIT "--zt")

我创建了一个适用于 ARM 编译器的工具链文件:

# generated cmake toolchain file for
include (CMakeForceCompiler)

# We are cross compiling so we don't want compiler tests to run, as they will fail
set(CMAKE_SYSTEM_NAME Generic)
# Set processor type
set(CMAKE_SYSTEM_PROCESSOR arm)

SET(CMAKE_CROSSCOMPILING 1)

set(CMAKE_ASM_COMPILER "arm-none-eabi-as.exe")
set(CMAKE_C_COMPILER "arm-none-eabi-gcc.exe")
set(CMAKE_CXX_COMPILER "arm-none-eabi-g++.exe")
set(CMAKE_LINKER "arm-none-eabi-gcc.exe")
set(CMAKE_MAKE_PROGRAM "mingw32-make.exe")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --specs=nosys.specs")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --specs=nosys.specs")

使用命令行编译时:

cd D:\git\myTestBuild\build
PATH=C:\Program Files\CMake\bin;C:\Program Files (x86)\GNU Tools ARM Embedded\6 2017-q1-update\bin;C:\Program Files\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev2\mingw64\bin;%PATH%
"C:\Program Files\CMake\bin\cmake.exe" -DArch="STM32F2xx"  -G"MinGW Makefiles" -DPackageFormat=ZIP -DSWstackPath="D:\git\myTestBuild\SWstack" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="D:\git\myTestBuild\dump\toolchain.cmake"  ..

CMake Error at C:/Program Files/CMake/share/cmake-3.8/Modules/CMakeTestCCompiler.cmake:51 (message):
  The C compiler "C:/Program Files (x86)/GNU Tools ARM Embedded/6
  2017-q1-update/bin/arm-none-eabi-gcc.exe" is not able to compile a simple
  test program.

  It fails with the following output:

   Change Dir: D:/git/myTestBuild/build/CMakeFiles/CMakeTmp



  Run Build Command:"C:/Program
  Files/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev2/mingw64/bin/mingw32-make.exe"
  "cmTC_8c052/fast"

  C:/Program
  Files/mingw-w64/x86_64-6.3.0-posix-seh-rt_v5-rev2/mingw64/bin/mingw32-make.exe
  -f CMakeFiles\cmTC_8c052.dir\build.make CMakeFiles/cmTC_8c052.dir/build

  mingw32-make.exe[1]: Entering directory
  'D:/git/myTestBuild/build/CMakeFiles/CMakeTmp'

  Building C object CMakeFiles/cmTC_8c052.dir/testCCompiler.c.obj

  "C:\Program Files (x86)\GNU Tools ARM Embedded\6
  2017-q1-update\bin\arm-none-eabi-gcc.exe" -o
  CMakeFiles\cmTC_8c052.dir\testCCompiler.c.obj -c
  D:\git\myTestBuild\build\CMakeFiles\CMakeTmp\testCCompiler.c

  Linking C executable cmTC_8c052

  "C:\Program Files\CMake\bin\cmake.exe" -E cmake_link_script
  CMakeFiles\cmTC_8c052.dir\link.txt --verbose=1

  "C:\Program Files (x86)\GNU Tools ARM Embedded\6
  2017-q1-update\bin\arm-none-eabi-gcc.exe"
  CMakeFiles/cmTC_8c052.dir/testCCompiler.c.obj -o cmTC_8c052

  c:/program files (x86)/gnu tools arm embedded/6
  2017-q1-update/bin/../lib/gcc/arm-none-eabi/6.3.1/../../../../arm-none-eabi/lib\libc.a(lib_a-exit.o):
  In function `exit':

  exit.c:(.text.exit+0x2c): undefined reference to `_exit'

  collect2.exe: error: ld returned 1 exit status

  CMakeFiles\cmTC_8c052.dir\build.make:96: recipe for target 'cmTC_8c052'
  failed

  mingw32-make.exe[1]: *** [cmTC_8c052] Error 1

  mingw32-make.exe[1]: Leaving directory
  'D:/git/myTestBuild/build/CMakeFiles/CMakeTmp'

  Makefile:125: recipe for target 'cmTC_8c052/fast' failed

  mingw32-make.exe: *** [cmTC_8c052/fast] Error 2





  CMake will not be able to correctly generate this project.
Call Stack (most recent call first):
  CMakeLists.txt:5 (project)

它失败了。编译器无法链接简单演示程序,因为它找不到“_exit”符号。这个问题应该通过添加“--specs=nosys.specs”来解决。看起来它并不起作用。

有什么想法吗?


1
你无法在工具链文件中添加CMAKE_CXX_FLAGS(因为它们尚未定义)。你可以尝试使用add_compile_options()。否则,请将 CMAKE_TRY_COMPILE_TARGET_TYPE设置为 STATIC_LIBRARY - Florian
由于CMAKE_CXX_FLAGS不能用于设置“--specs”参数,我需要另一种解决方案来在工具链/平台文件中设置此参数以进行编译/链接。 - Stefan Jaritz
1个回答

17

将我的评论转化为答案

我尝试了你的示例的简化版本。我能够重现你最初的错误,并通过设置 CMAKE_TRY_COMPILE_TARGET_TYPESTATIC_LIBRARY 来修复编译器检测。但是,构建一个“可执行文件”仍然会失败。

所以,你可以将 CMAKE_EXE_LINKER_FLAGS_INIT 设置为 --specs=nosys.specs(因为这些是链接器标志)。请确保如果使用了 ..._INIT 标志,则从空二进制输出目录开始,因为生成的 CMAKE_EXE_LINKER_FLAGS 将被缓存。

我更喜欢强制使用结果的 CMAKE_EXE_LINKER_FLAGS 变量(INTERNAL 确定了 FORCE)。

CMakeLists.txt

cmake_minimum_required(VERSION 3.6)

project(testApp)

file(WRITE main.cpp "int main(void) { return 0; }")

set(testApp "testApp")

list(
    APPEND testApp_sources
        main.cpp
)

add_executable(
    ${testApp}
    ${testApp_sources}
)

toolchain.cmake

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_C_COMPILER "arm-none-eabi-gcc.exe")
set(CMAKE_CXX_COMPILER "arm-none-eabi-g++.exe")

set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs" CACHE INTERNAL "")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

是否:

build> cmake -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE:PATH="..\toolchain.cmake"  ..
-- The C compiler identification is GNU 6.3.1
-- The CXX compiler identification is GNU 6.3.1
-- Check for working C compiler: C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/bin/arm-none-eabi-gcc.exe
-- Check for working C compiler: C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/bin/arm-none-eabi-gcc.exe -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/bin/arm-none-eabi-g++.exe
-- Check for working CXX compiler: C:/Program Files (x86)/GNU Tools ARM Embedded/6 2017-q1-update/bin/arm-none-eabi-g++.exe -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: build

build> cmake --build .
Scanning dependencies of target testApp
[ 50%] Building CXX object CMakeFiles/testApp.dir/main.obj
[100%] Linking CXX executable testApp
[100%] Built target testApp

参考资料


CACHE INTERNAL "" 是什么意思?为什么需要这个? - m4l490n
1
CACHE 表示将值缓存到 CmakeCache.txt 中,以便在后续运行 CMake 时即使未重新定义也能保留。INTERNAL 表示将其隐藏在像 cmake-gui 这样的工具中,不对用户可见。 - HunterZ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接