FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

CMakeで管理された外部のライブラリをリンクする方法

ところで、CMakeで管理された別のライブラリを、自動的にコンパイルして、リンクまでするためにはどうすればいいんだろう。 今のISSでそれを実現するために、とりあえず簡単なモデルを作って勉強してみることにした。

github.com

プロジェクトの構成

$ tree .
.
├── CMakeLists.txt
├── main.c
└── vendor
    ├── CMakeLists.txt
    ├── library.c
    └── library.h

メインのプログラムがmain.cだ。

  • main.c
#include <stdio.h>
#include "./vendor/library.h"

int main ()
{
    volatile int a = 100, b = 200;
    printf ("call_add(%d, %d) = %d\n", a, b, call_add (a, b));

    return 0;
}
  • vendor/library.c
int call_add (int a, int b)
{
    return a + b;
}

main()の中で、vendor/library.c で定義されているcall_add()を読んでいる。このlibraryは、別のCMakeLists.txt (あるいは別のリポジトリ)で管理されていて、mainをビルドするときに、一緒にlibraryもビルドされるようにしたい。

CMakeLists.txtの構成

CMakeLists.txtは、以下のようにしてみた。

  • ./CMakeLists.txt
add_executable (main
                main.c)

add_subdirectory (./vendor/)
target_link_libraries (main library)
link_directories (./vendor/)
  • ./vendor/CMakeLists.txt
add_library (library STATIC library.c)

とりあえずは、library側は通常通りライブラリをビルドするためのCMakeLists.txtを記述する。肝となるのは、main側のCMakeLists.txtだ。

  1. subdirectoryにより、別の場所にライブラリが存在することを示す。
  2. target_link_libraries により、main がlibraryを使用することを示す。
  3. link_directory により、リンク時にvendorディレクトリを参照するように指定する。

おそらく肝になっているのはsubdirectoryなのかな? subdirectory中に入っているlibraryを使うためには、vendor側のCMakeLists.txtも実行しないといけない、というカラクリになっているのか。

$ cmake .
-- The C compiler identification is GNU 4.9.2
-- The CXX compiler identification is GNU 4.9.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
CMake Warning (dev) at CMakeLists.txt:6 (link_directories):
  This command specifies the relative path

    ./vendor

  as a link directory.

  Policy CMP0015 is not set: link_directories() treats paths relative to the
  source dir.  Run "cmake --help-policy CMP0015" for policy details.  Use the
  cmake_policy command to set the policy and suppress this warning.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) in CMakeLists.txt:
  No cmake_minimum_required command is present.  A line of code such as

    cmake_minimum_required(VERSION 3.0)

  should be added at the top of the file.  The version specified may be lower
  if you wish to support older CMake versions for this project.  For more
  information run "cmake --help-policy CMP0000".
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done
-- Generating done
-- Build files have been written to: /home/vagrant/swimmer_riscv/cmake_tests

$ make
Scanning dependencies of target library
[ 50%] Building C object vendor/CMakeFiles/library.dir/library.o
Linking C static library liblibrary.a
[ 50%] Built target library
Scanning dependencies of target main
[100%] Building C object CMakeFiles/main.dir/main.o
Linking C executable main
[100%] Built target main

$ ./main
call_add(100, 200) = 300

これで、自動的にvendorディレクトリもビルドしてくれるMakefileが生成された。これを使って、どうにかしてISSのプロジェクトも、全て一発でビルドが完成するように改良してみよう。