誰にも見えないブログ

雑なメモ。まとまってない文章等

cmake tutorialその5:デフォルトリンク動作の制御

cmakeチュートリアルその5

昨日も今日もcmake。たぶん明日も明後日も。

共有ライブラリのリンク

  • Mixing Static and Shared (Step 9)の内容
  • 改修内容としてはMathFunctionsライブラリを必ず使うようにする
    • MathFunctionsのビルド時にユーザー定義のmysqrt.cxxを利用するかcmathのものを利用するかを選択するようにする
    • 結果的にライブラリの依存関係は↓こんなかんじ。
      • tutorial.cxx
        • MathFunctions.cxx
        • mysqrt.cxxのsqrt()(USE_MYMATHがONの場合)
        • cmathのsqrt()`(USE_MYMATHがONではない場合)
    • MathFunctionsでビルド時にユーザー定義のmysqrtかcmathのどちらのsqrtを呼ぶかを決定する
      • このビルド要件をcmakeで記述する。
  • ビルド方針
    • mysqrt.cxxをSqrtLibraryという静的ライブラリのターゲットにする
    • MathFunctionsは共有ライブラリにする
    • tutorial.cxxはそのままexecutable
source type target name
mysqrt.cxx STATIC libary SqrtLibrary
MathFunctions.cxx SHARED library MathFunctions
tutorial.cxx executable Tutorial

build

実際のビルド時に利用するcmakeの技術詳細

  • BUILD_SHARED_LIBS変数によってadd_libraryのデフォルト挙動を制御できる
    • 補足:デフォルト挙動=[STATIC | SHARED | MODULE]の指定がないコマンド実行のこと
# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
  • CMAKE_<target type>_OUTPUT_DIRECTORYでビルド結果(中間結果含む)のビルド結果を置くディレクトリを指定する。
    • *RUNTIME*の場所にはadd_executable()で指定したtargetが置かれる
    • *LIBRARY*の場所にはadd_library()MODULEオプションを指定した場合のもの(*.so)が置かれる
    • *ARCHIVE*の場所にはadd_library()STATICオプションを指定した場合のもの(*.libor *.a)が置かれる
  • 今回はArchive library runtime全てプロジェクトのバイナリディレクトリを指定しているのでそこに全部配置される
    • ビルド後のビルドディレクトリにビルド成果、中間結果が配置される
:~/Documents/study/cmake-sandbox/CMake/Help/guide/tutorial/build$ ll *.a *.so Tutorial
-rwxr-xr-x 1 yabu yabu 14880 12月  4 18:14 Tutorial*
-rwxr-xr-x 1 yabu yabu  8904 12月  4 18:14 libMathFunctions.so*
-rw-r--r-- 1 yabu yabu  3922 12月  4 18:14 libSqrtLibrary.a
  • タイポでビルド失敗(typo:MathFunctiuons)
target_link_libraries(Tutorial PUBLIC MathFunctiuons)
  • このときのビルドエラーが↓なんだけど、.hが見つかりません、じゃなくてそんなlibないよ。くらいのエラーメッセージ出してくれてもいいのに。
$ cmake --build .
-- Configuring done
-- Generating done
-- Build files have been written to: /home/yabu/Documents/study/cmake-sandbox/CMake/Help/guide/tutorial/build
[ 11%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
/home/yabu/Documents/study/cmake-sandbox/CMake/Help/guide/tutorial/devlop/tutorial.cxx:7:10: fatal error: MathFunctions.h: No such file or directory
 #include "MathFunctions.h"
          ^~~~~~~~~~~~~~~~~
compilation terminated.
CMakeFiles/Tutorial.dir/build.make:62: recipe for target 'CMakeFiles/Tutorial.dir/tutorial.cxx.o' failed
make[2]: *** [CMakeFiles/Tutorial.dir/tutorial.cxx.o] Error 1
CMakeFiles/Makefile2:370: recipe for target 'CMakeFiles/Tutorial.dir/all' failed
make[1]: *** [CMakeFiles/Tutorial.dir/all] Error 2
Makefile:162: recipe for target 'all' failed

It's intended. If the library name is not a target then it is simply forwarded to the linker (e.g. -lbaz). The target_link_libraries documentation explains all the ways various names are treated.

target_link_libraries(<target>
                      <PRIVATE|PUBLIC|INTERFACE> <item>...
                     [<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
  • 社内の詳しい人に聞いたところ、itemとmatchするtargetが見つからない場合に、library名で見に行くらしい。
    • ちょっとまだ理解しきれてないのでこのへんで説明は切り上げます。

愚痴2:勝手にソース変更ヤメテ(チュートリアル)

  • cmakeに対する文句じゃないけどチュートリアルで勝手にincludeするやつを変えてる

    • これは次のstepのサンプルコードから判明した。(上記typoの調査のため徹底的にgrepをかけて見つけた)
  • 勝手にinclude<iostrteam>include<sstream>に変えないで。

    • ビルドエラーには関係なかったけど全ファイルでdiff取ったときに出てきた。変えたならちゃんと説明して。
// A simple program that computes the square root of a number
#include <cmath>
#include <sstream>
#include <string>

まとめ

  • top-leveのCMakeLists.txtに定義したBUILD_SHARED_LIBSadd_libraryのデフォルト機能を抑制できる
  • CMAKE_<アーティファクト種類>_OUTPUT_DIRECTORYでビルド成果の格納場所を指定可能
    • 依存先の解決は各target_link_librariesにtarget名を使っているのでこの変数に設定した値は特に利用していない(というのが私の理解)

余談

  • C++と比べてJavaはファイル・クラス・名前空間が同一になるようになっている。(クラスに関してはファイルに対して一対多の関係を作れるが基本は一対一といっていいだろう)