Windows10でCMakeを使ってXilinx Zynqアプリケーションプロジェクトをビルドする


概要

通常はXilinx SDKで自動生成する、Zynqのアプリケーションプロジェクトビルド環境をcmakeで構築します。
前提知識としては以下を想定しています。

Xilinx SDKが生成するMakefileを読み解いてCMakeファイルを作成
Windows上でCMake実行、makeして生成した.elfをターゲットボードでデバッグ実行
までを紹介します。

環境

  • Windows10
  • Ultra96 V2

Xilinx SDKの生成したMakefileを実行してみる

まずベースとなるビルド環境確認のため
Xilinx SDKで自動生成されたMakeをDebug, Releaseで実行してみます。

Debug実行

Debug
13:18:11 **** Build of configuration Debug for project app_hello ****
make all 
Building file: ../src/freertos_hello_world.c
Invoking: ARM R5 gcc compiler
armr5-none-eabi-gcc -DARMR5 -Wall -O0 -g3 -c -fmessage-length=0 -MT"src/freertos_hello_world.o" -mcpu=cortex-r5 -mfloat-abi=hard  -mfpu=vfpv3-d16 -I../../bsp/psu_cortexr5_0/include -MMD -MP -MF"src/freertos_hello_world.d" -MT"src/freertos_hello_world.o" -o "src/freertos_hello_world.o" "../src/freertos_hello_world.c"
Finished building: ../src/freertos_hello_world.c

Building target: app_hello.elf
Invoking: ARM R5 gcc linker
armr5-none-eabi-gcc -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -Wl,-T -Wl,../src/lscript.ld -L../../bsp/psu_cortexr5_0/lib -o "app_hello.elf"  ./src/freertos_hello_world.o   -Wl,--start-group,-lxil,-lfreertos,-lgcc,-lc,--end-group
Finished building target: app_hello.elf

Invoking: ARM R5 Print Size
armr5-none-eabi-size app_hello.elf  |tee "app_hello.elf.size"
   text    data     bss     dec     hex filename
  56432    4288   89120  149840   24950 app_hello.elf
Finished building: app_hello.elf.size

Release実行

Release
13:21:05 **** Build of configuration Release for project app_hello ****
make all 
Building file: ../src/freertos_hello_world.c
Invoking: ARM R5 gcc compiler
armr5-none-eabi-gcc -DARMR5 -Wall -O2 -c -fmessage-length=0 -MT"src/freertos_hello_world.o" -mcpu=cortex-r5 -mfloat-abi=hard  -mfpu=vfpv3-d16 -I../../bsp/psu_cortexr5_0/include -MMD -MP -MF"src/freertos_hello_world.d" -MT"src/freertos_hello_world.o" -o "src/freertos_hello_world.o" "../src/freertos_hello_world.c"
Finished building: ../src/freertos_hello_world.c

Building target: app_hello.elf
Invoking: ARM R5 gcc linker
armr5-none-eabi-gcc -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -Wl,-T -Wl,../src/lscript.ld -L../../bsp/psu_cortexr5_0/lib -o "app_hello.elf"  ./src/freertos_hello_world.o   -Wl,--start-group,-lxil,-lfreertos,-lgcc,-lc,--end-group
Finished building target: app_hello.elf

Invoking: ARM R5 Print Size
armr5-none-eabi-size app_hello.elf  |tee "app_hello.elf.size"
   text    data     bss     dec     hex filename
  56248    4288   89112  149648   24890 app_hello.elf
Finished building: app_hello.elf.size

リンカもGCCを使ってやっているようです。

CMakeファイルの作成

ディレクトリ構成

Zynqのプロジェクト構成は以下のようになっています。(必要な部分だけ抜粋)
freertos_hello_world.cをlibfreertos.a, libxil.aとリンクして、GCC R5のelfを作るのが目標です。
bspの方はビルド済みの前提です。

.
|-- app_hello
|   |-- CMakeLists.txt
|   |-- armr5_toolchain.cmake
|   |-- build
|   `-- src
|       |-- freertos_hello_world.c
|       `-- lscript.ld
|-- bsp
|   |-- Makefile
|   |-- psu_cortexr5_0
|   |   |-- include
|   |   |-- lib
|   |   |   |-- libfreertos.a
|   |   |   `-- libxil.a
|   |   `-- libsrc

app_hello/CMakeLists.txt がCMake用のファイルで
app_hello/arm5_toolchain.cmake がCMAKE_TOOLCHAIN_FILEで指定するクロスコンパル用のツールチェーン設定になります。

CMakeLists.txt

ターゲットの設定

CMakeLists.txtは通常と同じようにターゲットを記載します

CMakeLists.txt
set(TARGET_NAME hello)
add_executable(${TARGET_NAME}
 ./src/freertos_hello_world.c)
include_directories(../bsp/psu_cortexr5_0/include/)

ライブラリのリンク

bsp/psu_cortexr5_0/lib以下の libxil.a, libfreertos.a をリンクする。
SDK生成のMakefileと同じように、--start-group, --end-groupを入れておく。(これがないと相互参照してリンクエラーになる)

CMakeLists.txt
find_library(LIBRARY_XIL
 NAMES xil
 HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../bsp/psu_cortexr5_0/lib/
)
find_library(LIBRARY_FREERTOS
 NAMES freertos
 HINTS ${CMAKE_CURRENT_SOURCE_DIR}/../bsp/psu_cortexr5_0/lib/
)
message("LIBRARY_XIL : " ${LIBRARY_XIL})
message("LIBRARY_FREERTOS : " ${LIBRARY_FREERTOS})
link_directories(${TARGET_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../bsp/psu_cortexr5_0/lib/)

target_link_libraries(${TARGET_NAME}
 -Wl,--start-group
 ${LIBRARY_XIL}
 ${LIBRARY_FREERTOS}
 gcc
 c
 -Wl,--end-group
)

arm5_toolchain.cmake

ツールチェーンの設定

ARM5用のツールチェーン設定を行います。
※Xilinxのツールチェーンディレクトリ↓にパスが通っている前提とします。
インストールフォルダ/Xilinx/SDK/2019.1/gnu/armr5/nt/gcc-arm-none-eabi/bin/
SDKが生成したMakefileはリンカにldではなくgccを使っていたのでgccとしておきます。

ツールチェーンの設定
# ------------------
# target
# ------------------
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CROSS_PREFIX "armr5-none-eabi-")
# ------------------
# toolchain
# ------------------
set(CMAKE_C_COMPILER   ${CROSS_PREFIX}gcc)
set(CMAKE_CXX_COMPILER ${CROSS_PREFIX}g++)
#set(CMAKE_LINKER       ${CROSS_PREFIX}ld)
set(CMAKE_LINKER       ${CROSS_PREFIX}gcc) # SDKではgccになってる.
set(CMAKE_AR           ${CROSS_PREFIX}ar)
set(CMAKE_RANLIB       ${CROSS_PREFIX}ranlib)
set(CMAKE_AS           ${CROSS_PREFIX}as)
set(CMAKE_NM           ${CROSS_PREFIX}nm)
set(CMAKE_OBJDUMP      ${CROSS_PREFIX}objdump)

コンパイラチェックエラーの回避

cmakeでは単純なプログラムを使って、設定されたコンパイラが正常に動作しているのか確認しているようです。
ARM R5 gccはWindows上では当然動作しないので、ツールチェーンを変更してcmakeを実行すると以下のエラー armr5-none-eabi-gcc.exe" is not able to compile a simple test program が発生します。

-- Check for working C compiler: F:/Xilinx/SDK/2019.1/gnu/armr5/nt/gcc-arm-none-eabi/bin/armr5-none-eabi-gcc.exe - broken
CMake Error at C:/Program Files/CMake/share/cmake-3.18/Modules/CMakeTestCCompiler.cmake:66 (message):
  The C compiler

    "F:/Xilinx/SDK/2019.1/gnu/armr5/nt/gcc-arm-none-eabi/bin/armr5-none-eabi-gcc.exe"

  is not able to compile a simple test program.

  It fails with the following output:

    Change Dir: F:/git-work/ultra96v2_helloworld_cmake/app_hello/build/CMakeFiles/CMakeTmp

https://cmake.org/cmake/help/v3.6/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.html
https://stackoverflow.com/questions/53633705/cmake-the-c-compiler-is-not-able-to-compile-a-simple-test-program/53635241
を参考にすると、これを回避するには以下が適切のようなので加えておきます。

armr5_toolchain.cmake
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")

コンパイルオプション、リンクオプションの設定

ますは先ほど確認した、SDK Makefileの設定を見ます。
Debug, Release設定で太字の違いがありますね。

Debug

Compile
armr5-none-eabi-gcc -DARMR5 -Wall -O0 -g3 -c -fmessage-length=0 -MT"src/freertos_hello_world.o" -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -I../../bsp/psu_cortexr5_0/include -MMD -MP -MF"src/freertos_hello_world.d" -MT"src/freertos_hello_world.o" -o "src/freertos_hello_world.o" "../src/freertos_hello_world.c"
Link
armr5-none-eabi-gcc -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -Wl,-T -Wl,../src/lscript.ld -L../../bsp/psu_cortexr5_0/lib -o "app_hello.elf" ./src/freertos_hello_world.o -Wl,--start-group,-lxil,-lfreertos,-lgcc,-lc,--end-group

Release

Compile
armr5-none-eabi-gcc -DARMR5 -Wall -O2 -c -fmessage-length=0 -MT"src/freertos_hello_world.o" -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -I../../bsp/psu_cortexr5_0/include -MMD -MP -MF"src/freertos_hello_world.d" -MT"src/freertos_hello_world.o" -o "src/freertos_hello_world.o" "../src/freertos_hello_world.c"
Link
armr5-none-eabi-gcc -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -Wl,-T -Wl,../src/lscript.ld -L../../bsp/psu_cortexr5_0/lib -o "app_hello.elf" ./src/freertos_hello_world.o -Wl,--start-group,-lxil,-lfreertos,-lgcc,-lc,--end-group

コンパイルオプションは以下のように記載します。

armr5_toolchain.cmake
message("CMAKE_BUILD_TYPE            : " ${CMAKE_BUILD_TYPE})
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
    add_definitions(-DARMR5 -DMY_DEBUG_INFO)
    set(GCC_COVERAGE_COMPILE_FLAGS "-Wall -O0 -g3 -fmessage-length=0 -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16")
elseif("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
    set(GCC_COVERAGE_COMPILE_FLAGS "-Wall -O2 -fmessage-length=0 -mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16")
else()
    message(FATAL_ERROR "FATAL_ERROR! you must add -DCMAKE_BUILD_TYPE=Debug or -DCMAKE_BUILD_TYPE=Release")
endif()
set(CMAKE_C_FLAGS  "${GCC_COVERAGE_COMPILE_FLAGS}")

これで cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=./armr5_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug .. を実行すると、なぜかelseのFATAL_ERRORのメッセージに入ってしまいます。
armr5_toolchain.cmakeの最初と最後にログを入れてい見ると、何度かarmr5_toolchain.cmakeが呼ばれているように見えます。
最初の2回は CMAKE_BUILD_TYPEDebug になっていますが、コンパイラ確認の後で、なぜか空にされています。

-----begin armr5_toolchain.cmake-----
CMAKE_BUILD_TYPE            : Debug
Generated with config types:
-----end armr5_toolchain.cmake-----
-----begin armr5_toolchain.cmake-----
CMAKE_BUILD_TYPE            : Debug
Generated with config types:
-----end armr5_toolchain.cmake-----
-- The C compiler identification is GNU 8.2.0
-- The CXX compiler identification is GNU 8.2.0
-- Detecting C compiler ABI info
-----begin armr5_toolchain.cmake-----
CMAKE_BUILD_TYPE            :
Generated with config types:

解決しなかったので、elseにDebug設定のオプション入れとくことにしました。。。

リンクオプションはDebug, Releaseで違いがないので

set(GCC_COVERAGE_LINK_FLAGS "-mcpu=cortex-r5 -mfloat-abi=hard -mfpu=vfpv3-d16 -T ../src/lscript.ld")
set(CMAKE_EXE_LINKER_FLAGS  "${GCC_COVERAGE_LINK_FLAGS}")

とします。
あとは実行してみます。

この記事の成果物実行方法

Githubからclone

※ この時のtagは 7af008695eb88d458a47b6571ba607b38e562f92

> git clone --branch after_create_project_tcl_cmake [email protected]:azukibar0713/ultra96v2_xsct_tcl.git ultra96v2_hello_world_cmake_0
> cd ultra96v2_hello_world_cmake_0/bsp
> make
> cd ../app_hello/build/
> cmake -G "Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=./armr5_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug ..
> make

cmakeコマンドは、-GのGenerator設定(Windows環境なのでデフォルトはVisualstudioとなってしまう)をします。

Xilinx SDK Eclipse上で実行

cloneしたフォルダをworkspace指定で開きます。
アプリケーションプロジェクトを右クリック->Debug As->Debug Configurations...

アプリケーションタブで、elfをbuildフォルダのcmakeで生成したapp_hello.elfに変更する
Apply, Debugボタンを押すとターゲットボードにダウンロードされて実行されます。