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

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

- Xilinx SDKでZynqプロジェクトをビルドしたことがある
- [たのしい組み込みCMake](https://qiita.com/tnishinaga/items/c01dfd5f43e446653cd1) の記事を読んでいる

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

##環境
- Windows10
- Ultra96 V2

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

### Debug実行

```terminal: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実行

```terminal: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は通常と同じようにターゲットを記載します

```cmake: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を入れておく。（これがないと相互参照してリンクエラーになる）

```cmake: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としておきます。

```cmake:ツールチェーンの設定
# ------------------
# 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` が発生します。

```terminal:
-- 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
を参考にすると、これを回避するには以下が適切のようなので加えておきます。

```cmake:armr5_toolchain.cmake
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
```

### コンパイルオプション、リンクオプションの設定
ますは先ほど確認した、SDK Makefileの設定を見ます。
Debug, Release設定で太字の違いがありますね。
####Debug
**<font color="Blue">Compile</font>**
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"
**<font color="Blue">Link</font>**
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
**<font color="Blue">Compile</font>**
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"
**<font color="Blue">Link</font>**
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

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

```cmake: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_TYPE` は `Debug` になっていますが、コンパイラ確認の後で、なぜか空にされています。

```
-----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:
```

<font color="Red">解決しなかったので、elseにDebug設定のオプション入れとくことにしました。。。</font>

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

```cmake::armr5_toolchain.cmake
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`

```terminal
> git clone --branch after_create_project_tcl_cmake git@github.com: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...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/7eb15737-d56a-d6bd-aaa2-5564e919f56d.png)
アプリケーションタブで、elfをbuildフォルダのcmakeで生成したapp_hello.elfに変更する
Apply, Debugボタンを押すとターゲットボードにダウンロードされて実行されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540259/f4ae2440-0c6d-b549-2493-5457aeb99835.png)