2010年11月25日

[CMake] 手動 Autotools to CMake 注意事項

前言

相較於 Makefile 的難維護, 有很多工具 "取而代之", 或者幫忙產生 Makefile.
其中 CMake 是個人認為目前較優的. 原因很多, 光 KDE 這麼龐大的計畫,
都可以透過它去完成編譯, 起碼也有相當的優勢.
OSS 的東西最怕的就是: 沒人維護, 沒人用! 沒人氣就沒人可以問, 可以協助了!
在 CMake 的 wiki 有提到幾支工具可以將現有的編譯系統轉成 CMake.
其中常用的 autotools 所列的幾支, 多半是給 KDE 用的, 其他案子不見得適用,
如果懂點 Ruby 的話, 倒是可以自己改看看.

關於 AutoTools, 可以參考 AutoBook
如果要轉成 CMake 系統, 就是要去 "翻譯" Makefile.am 和 configure.ac


Makefile.am

基本上和 Makefile 很接近, 因此很好轉譯. 例如:

SUBDIRS = . D1 D2 D3

就會變成

ADD_SUBDIRECTORY(D1)
ADD_SUBDIRECTORY(D2)
ADD_SUBDIRECTORY(D3)

File-list 及產生的 library 或 executable 手動去改成 CMake 寫法。
一些常用的 AutoMake 的 primary 例如 _DATA, _HEADERS, _LIBRARIES, _PROGRAMS, _SOURCES, etc.
就要用 ADD_LIBRARY(), ADD_EXECUTABL(), TARGET_LINK_LIBRARIES(), INSTALL() 等去描述.
像一些特別的 target 則須要手動自己加 ADD_CUSTOM_TARGET(), ADD_CUSTOM_COMMAND()

configure.ac

這部分是比較麻煩的, 尤其是一些系統偵測的動作, CMake 也許不支援或者要用其他方式

config.h.in

產生的 config.h 是最常用來判定該產生怎樣的 code.
首先,
可以將 config.h.in 改名, 例如: config.h.cmake 或要沿用這個名字也無妨.
其次,
原先在 config.h.in 裡的定義要修改, 例如:

#undef HAVE_SOMETHING

要改成

#cmakedefine HAVE_SOMETHING

例如:

/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H
/* Whether we have alarm() */
#cmakedefine HAVE_ALARM
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG (@SIZEOF_LONG@)
/* Name of package */
#cmakedefine PACKAGE

就會變成

#define HAVE_STDLIB_H
#define HAVE_ALARM
#define SIZEOF_LONG (4)
#define PACKAGE

請留意 SIZEOF_LONG 的寫法. @SIZEOF_LONG@ 會被實際的值取代, 如果有的話.
另外, 是使用 define 而非 cmakedefine
CMakeLists.txt 裡的寫法是

INCLUDE (CheckIncludeFiles)
CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H)

INCLUDE (CheckFunctionExists)
CHECK_FUNCTION_EXISTS(alarm HAVE_ALARM)

INCLUDE (CheckTypeSize)
CHECK_TYPE_SIZE(long SIZEOF_LONG)

SET(PACKAGE 1)

# Generate build-path/config.h from config.h.in at source directory.
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)

請留意 SET(PACKAGE 1) 的寫法. 因為我沒把 PACKAGE 的判讀方式轉換, 偷懶直接使用 SET()
在 config.h.in 裡, #cmakedefine PACKAGE 也可以改成 #define PACKAGE @PACKAGE@
而最後一行則是告訴 CMake 如何把 config.h.in 轉成 config.h

TODO

有些偵測系統的部分, 可能要實際編譯程式去跑. 這就有點麻煩.
可以參考 CMakePath/share/cmake-x.y/Modules 下的
FindThreads.cmake & CheckForPthreads.c
裡面 TRY_RUN() 的範例.
如果案子不大, 簡單的判斷會輕鬆多了.
像 OPTION(), CMAKE_BUILD_TYPE(), 及一些內建的 variable
判斷來決定 CMAKE_C_FLAGS.


使用 pixman 這個 library 做了一個簡略的轉換. <下載點>

沒有留言: