CMakeのTipsというかメモ

いまさらながらCMakeを使ってみたのですが、なかなか良いですね。
ただ、ネット上には日本語の情報がちょっと少ないので(英語の情報は結構あるけど)いくつかメモしときます。

ちなみに、最初はまず
http://www.cmake.org/Wiki/CMake_FAQ
のFAQに一通り目を通すことをお勧めします。
また、使用したCMakeはversion 2.8.10.1です(Ubuntu 13.04 64bit)。

Makefileでいう += ってどう記述するの


例えばMakefileで
SRCS += hoge.c
というのは、
set (SRCS ${SRCS} hoge.c)
というように、変数の後に追加したい値を書けばよい。


コンパイルフラグにセミコロン(';')が入ってビルドが止まるんだけど


FAQの
http://www.cmake.org/Wiki/CMake_FAQ#Why_do_I_have_unwanted_semicolons_.3B_in_my_compiler_flags.3F
がそのまんま。CMakeは、内部ではリストをセミコロン区切りの文字列として管理しているので、それをコンパイラに渡すとセミコロンが残ってしまうらしい。
そういう場合は、" " で囲うことでセミコロン区切りをスペース区切りに変換してくれる。

特に、先ほどの例のように
CFLAGS += -g
とMakefileで書いていたのを
# NG
set (CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-g")
とうっかり書くと、セミコロンが入ってしまい死ぬ。
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
とすればOK。


ターゲット名をlibhogeにしてライブラリをビルドすると、liblibhoge.soができる


まあ、ターゲット名をlibhogeでなくhogeにしろ、ということなんでしょうけど…。
FAQの
http://www.cmake.org/Wiki/CMake_FAQ#How_do_I_rename_a_library_after_it_has_already_been_built.3F
にヒントがある。ビルド後にファイルのコピーをするのではなく、set_target_property() を使ってOUTPUT_NAMEプロパティを変更する方が良いそうだ。

ただ、先頭の "lib" だけを削除するのはもっと簡単で、PREFIXプロパティをいじって消せばOK。
set (TARGET_NAME libhoge)
add_library (${TARGET_NAME} SHARED hoge.c hoge2.c)
set_target_properties (${TARGET_NAME}
                       PROPERTIES PREFIX
                       "")


ビルド時に、公開ヘッダファイルを一箇所にコピーしたい


例えばこのような感じの(ほげほげした)プロジェクトがあって、
.
├── lib
│     ├── libhoge
│     │     ├── include
│     │     │     ├── hoge.h
│     │     │     └── hoge_common.h
│     │     ├── src
│     │     │     ├── src1.c
│     │     │     ├── src2.c
│     │     │     └── internal.h
│     │     └── CMakeLists.txt
│     └── libfuga
│            ├── fuga.c
│            ├── fuga.h
│            └── CMakeLists.txt
├── src
│     └── main.c
└── CMakeLists.txt

ビルドを実行する前に、export_headers というディレクトリを作って
- libhoge/hoge.h
- libhoge/hoge_common.h
- libfuga/fuga.h
をコピーして格納したい、というようなケース。

http://stackoverflow.com/questions/15972898/cmake-how-to-run-a-add-custom-command-before-everything-else
を読むと、add_custom_target() を使ってコマンドを定義し、さらに add_dependencies() で依存関係を作っておけば、
ビルド前に何かを実行させることができる、ということらしい。

つまり、例えばlib/libhoge/CMakeLists.txtの中に
add_library (libhoge SHARED src/src1.c src/src2.c)
add_custom_target (copy_header_hoge_h
                   COMMAND
                   ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/include/hoge.h
                                            ${CMAKE_BINARY_DIR}/export_headers/libhoge/hoge.h)
add_dependencies(libhoge copy_header_hoge_h)
と書いておけば、libhogeをビルドする前にinclude/hoge.hをコピーできる。


……まあ、ヘッダファイルそれぞれに対してこれらをいちいち書くのは非常に面倒なので、
マクロにしてしまいましょう。

set (TARGET_NAME libhoge)
set (SRCS
    src/src1.c
    src/src2.c
)
set (C_INCLUDES
    include
    src
)

# コピーするヘッダファイルの一覧
set (EXPORT_HEADER_FILES
    include/hoge.h
    include/hoge_common.h
)
# export_headers内のサブディレクトリ名
set (EXPORT_HEADER_DIR libhoge)

include_directories (${C_INCLUDES})
add_library (${TARGET_NAME} SHARED ${SRCS})
set_target_properties (${TARGET_NAME}
                       PROPERTIES PREFIX
                       "")
# マクロなので、引数にリストを渡す時は " " で囲うことに注意
copy_headers (${TARGET_NAME} ${EXPORT_HEADER_DIR} "${EXPORT_HEADER_FILES}")
set (TARGET_NAME libfuga)
set (SRCS
    fuga.c
)

# コピーするヘッダファイルの一覧
set (EXPORT_HEADER_FILES
    fuga.h
)
# export_headers内のサブディレクトリ名
set (EXPORT_HEADER_DIR libfuga)

add_library (${TARGET_NAME} SHARED ${SRCS})
set_target_properties (${TARGET_NAME}
                       PROPERTIES PREFIX
                       "")
copy_headers (${TARGET_NAME} ${EXPORT_HEADER_DIR} "${EXPORT_HEADER_FILES}")
# ---------- 共通の設定

# バージョンはてきとう
cmake_minimum_required (VERSION 2.6.0)

project (piyo-project)

set (CMAKE_BUILD_TYPE Debug)
set (CMAKE_C_FLAGS "-Wall -Werror")

set (GLOBAL_HEADER_DIR ${CMAKE_BINARY_DIR}/export_headers)


# ---------- マクロ定義

# ヘッダをコピーするマクロ
macro (copy_headers MODULE_NAME OUT_DIR_PREFIX FILE_LIST)

    foreach (HEADER_FILE ${FILE_LIST})
        # ファイル名を取得
        get_filename_component (FNAME ${HEADER_FILE} NAME)
        # ファイル名の一部を使って、ターゲット名を生成
        get_filename_component (TEMP_TARGET ${HEADER_FILE} NAME_WE)
        set (TEMP_TARGET copy_header_${OUT_DIR_PREFIX}_${TEMP_TARGET})
        # コピーするコマンド
        add_custom_target (
            ${TEMP_TARGET}
            COMMAND
            ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FILE}
                                     ${GLOBAL_HEADER_DIR}/${OUT_DIR_PREFIX}/${FNAME}
        )
        # 依存関係を指定(ライブラリのビルドの前にコピーが実行されるようになる)
        add_dependencies (${MODULE_NAME} ${TEMP_TARGET})
    endforeach (HEADER_FILE ${FILE_LIST})

endmacro (copy_headers MODULE_NAME OUT_DIR_PREFIX FILE_LIST)


# ---------- サブディレクトリを登録

set (SUB_DIRS
    lib/libhoge
    lib/libfuga
)
foreach (DIR ${SUB_DIRS})
    add_subdirectory (${DIR})
endforeach (DIR ${SUB_DIRS})


# ---------- メインの実行ファイル

set (TARGET_EXE_NAME piyoproj)
set (SRCS
    src/main.c
)
set (SHARED_LIBS
    libhoge
    libfuga
)

include_directories (${GLOBAL_HEADER_DIR})
add_executable (${TARGET_EXE_NAME} ${SRCS})
target_link_libraries (${TARGET_EXE_NAME} ${SHARED_LIBS})

実行結果。
$ mkdir build
$ cd build
$ cmake ..
-- The C compiler identification is GNU 4.7.3
-- The CXX compiler identification is GNU 4.7.3
-- 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
-- Configuring done
-- Generating done
-- Build files have been written to: /home/amano/cmake_sample/build
$ make
Scanning dependencies of target copy_header_libfuga_fuga
[  0%] Built target copy_header_libfuga_fuga
Scanning dependencies of target libfuga
[ 25%] Building C object lib/libfuga/CMakeFiles/libfuga.dir/fuga.c.o
Linking C shared library libfuga.so
[ 25%] Built target libfuga
Scanning dependencies of target copy_header_libhoge_hoge_common
[ 25%] Built target copy_header_libhoge_hoge_common
Scanning dependencies of target copy_header_libhoge_hoge
[ 25%] Built target copy_header_libhoge_hoge
Scanning dependencies of target libhoge
[ 50%] Building C object lib/libhoge/CMakeFiles/libhoge.dir/src/src1.c.o
[ 75%] Building C object lib/libhoge/CMakeFiles/libhoge.dir/src/src2.c.o
Linking C shared library libhoge.so
[ 75%] Built target libhoge
Scanning dependencies of target piyoproj
[100%] Building C object CMakeFiles/piyoproj.dir/src/main.c.o
Linking C executable piyoproj
[100%] Built target piyoproj
$ ls -R export_headers/
export_headers/:
libfuga  libhoge

export_headers/libfuga:
fuga.h

export_headers/libhoge:
hoge.h  hoge_common.h

# いつの間にか年が明けてブログ開設から1年が過ぎていることについてはスルー。

コメントを投稿

0 コメント