Makefile 和 CMake 之間的轉換和實作
http://mqjing.blogspot.tw/2009/09/cmake-how-to-use-cmake.html
CMake 常用變數
簡介
CMake用來產生跨平台的專案建置文件,在windows下它會生成visual studio的專案檔(.sln) codeblock eclipse,在linux下它會生成Makefile。類似工具有autotools和qmake,不過autotools太複雜,qmake只限於qt使用。
CMake用更抽象的語法來組織項目。例如用math表示數學庫,而不需要再具體指定到底是math.dll還是libmath.so。
類似功能的工具
-
SCons
- by python
-
Apache ant
- by java
-
優點
- stable
- fast
- 支援Code::Blocks, Xcode等
-
缺點
- 需學習語法
專案建置工具比較
使用
GUI
- command line:
cmake
- curse-based TUI:
ccmake
- QT-based GUI:
cmake-gui
Out-Of-Source Build
將build資料和原始碼分離
1 | 修改 CMakeLists.txt |
- 執行結束後,build資料夾會出現各項中間檔、makefile 以及執行檔
優點
- 可保持working directory的乾淨
- 只要用新的資料夾,就可以產生多個不同的build,也可以隨時刪除
語法
- 設定變數
set(var hello)
- 印出訊息
message(${var})
1 | cmake_minimum_required (VERSION 2.6) # minimum executable version of cmake |
在不同的資料夾下建立執行檔
1 | relative destination |
CMake語法
general purpose constructs: set
, unset
, if
, elseif
, else
, endif
, foreach
, while
, break
CMake 變數
變數不分大小寫,但我習慣性用大寫
-
變數指定
- CMake 有許多預設變數,以改變基本的運作,用
cmake --help-variables-list
可以瀏覽 - 在檔案內指定
set(CMAKE_INSTALL_PREFIX /home/eric/testinstall)
- CMake 有許多預設變數,以改變基本的運作,用
-
平台相關變數
- 作業系統
WIN32
True on windows systems, including win64.UNIX
True for UNIX and UNIX like operating systems.APPLE
True if running on Mac OSX.CYGWIN
True for cygwin.
- 編譯器
MSVC
True when using Microsoft Visual CGNU<LANG>
True if the compiler of this language is GNUMINGW
True if the compiler is MinGW
- example
1
2
3if (NOT WIN32)
option (WITH GUESS NAME "Guess acronym name" ON)
endif (NOT WIN32)- 找需要的package
1
2
3
4find package ( LibXml2 )
if (LIBXML2 FOUND)
add definitions (−DHAVE XML ${LIBXML2 DEFINITIONS })
includedirectories( ${LIBXML2 INCLUDE DIR })XXXFOUND
- Set to false, or undefined, if we haven’t found, or don’t want to use XXXXXX_INCLUDE_DIRS
- The final set of include directories listed in one variable for use by client code
XXX_LIBRARIES
- The libraries to link against to use XXX. These should include full paths
XXX_DEFINITIONS
- Definitions to use when compiling code that uses XXX
XXX_EXECUTABLE
- Where to find the XXX tool
XXX_LIBRARY_DIRS
- Optionally, the final set of library directories listed in one variable for use by client code
- to find an executable program
find_program
- to find a library
find_library
- to find any kind of file
find_file
- to find a path where a file reside
find_path
- 作業系統
-
file manipulation with file
READ
,WRITE
,APPEND
,RENAME
,REMOVE
,MAKE DIRECTORY
-
advanced files operations
GLOB
,GLOB RECURSE [file name in a path]
,DOWNLOAD
,UPLOAD
-
working with path
file (TO CMAKE PATH /TO NATIVE PATH ...)
, get filename component
-
execute an external process (with stdout, stderr and return code retrieval): execute process
-
builtin list manipulation command
LENGTH
,GET
,APPEND
,FIND
,APPEND
,INSERT
,REMOVE ITEM
,REMOVE AT
,REMOVE DUPLICATES REVERSE
,SORT
-
string manipulation
- upper/lower case conversion, length, comparison, substring, regular expression match
CMake Application
-
CPack
- CMake friend application
- used to easily package your software
- Package the resulting binaries with CPack
-
CTest
- make test
- runs systematic test with CTest and publish them with CDash
-
Wizard mode
- cmake -i, interactive equivalent of the Normal mode
-
Command mode
- cmake -E
, command line mode which offers basic command in a portable way
- cmake -E
專案說明
一個簡單的圍棋程式
file tree
1 | ├── CMakeLists.txt |
1 | P?=binary |
CMakeLists.txt in root directory
1 | cmake_minimum_required(VERSION 2.6) |
Makefile 和 CMake 的語法比較
makefile | cmake |
---|---|
COMPILE_FLAGS = -c -m32 -O3 -fPIC -w -DSOMETHING -Wall -I src/sdk/core |
SET( COMPILE_FLAGS "-c -m32 -O3 -fPIC -w DSOMETHING -Wall" ) INCLUDE_DIRECTORIES( src/sdk/core ) |
1 | #Makefile |
1 | # CMake |
using libraries
call find_package with the name of your library, which will invoke a library search script from your cmake module path. This script (which is also written in CMake) will attempt to detect the location of the library's header and lib files and store them in a couple of CMake variables that can then be passed to the according CMake commands like include_directories and target_link_libraries.
There are two problems with this approach: First, you need a search script. Fortunately, CMake ships with search scripts for Pthreads, Boost and a couple of others, but if you are using a more exotic library, you might have to write the search script yourself, which is kind of an arcane experience at first...
並不會刪除自身產出的快取和中間檔
The following Makefile builds an executable named prog from the sources prog1.c, prog2.c, prog3.c and main.c. prog is linked against libmystatlib.a and libmydynlib.so which are both also built from source. Additionally, prog uses the library libstuff.a in stuff/lib and its header in stuff/include. The Makefile by default builds a release target, but offers also a debug target:
1 | #Makefile |
1 | #CMakeLists.txt |
In this simple example, the most important differences are:
CMake recognizes which compilers to use for which kind of source. Also, it invokes the right sequence of commands for each type of target. Therefore, there is no explicit specification of commands like $(CC)..., $(RANLIB)... and so on.
All usual compiler/linker flags dealing with inclusion of header files, libraries, etc. are replaced by platform independent / build system independent commands.
Debugging flags are included by either setting the variable CMAKE_BUILD_TYPE to "Debug", or by passing it to CMake when invoking the program: cmake -DCMAKE_BUILD_TYPE:STRING=Debug.
CMake offers also the platform independent inclusion of the '-fPIC' flag (via the POSITION_INDEPENDENT_CODE property) and many others. Still, more obscure settings can be implemented by hand in CMake just as well as in a Makefile (by using COMPILE_FLAGS and similar properties). Of course CMake really starts to shine when third party libraries (like OpenGL) are included in a portable manner.
The build process has one step if you use a Makefile, namely typing
make at the command line. For CMake, there are two steps: First, you need to setup your build environment (either by typing cmake <source_dir> in your build directory or by running some GUI client). This creates a Makefile or something equivalent, depending on the build system of your choice (e.g. make on Unixes or VC++ or MinGW + Msys on Windows). The build system can be passed to CMake as a parameter; however, CMake makes reasonable default choices depending on your system configuration. Second, you perform the actual build in the selected build system.
Sources and build instructions are available at https://github.com/rhoelzel/make_cmake.
設定變數範例
set(MYLIBPATH "C:\\Documents and
Settings\\Jing\\Desktop\\opencv_bin\\lib\\release\\")
使用變數範例
target_link_libraries(${name} ${MYLIBPATH}cv200.lib)
建立 macro 範例
MACRO(MY_DEFINE_EXAMPLE name srcs)
add_executable(${name} ${srcs})
ENDMACRO(MY_DEFINE_EXAMPLE)
使用 macro 範例
MY_DEFINE_EXAMPLE(demo demo.cpp)
存取環境變數的範例
MESSAGE("$ENV{PATH}")
加入 Post Build 的範例
add_custom_command(
TARGET ${MyPluginTarget}
POST_BUILD
COMMAND copy
${CMAKE_CFG_INTDIR}\\${MyPluginTarget}.dll
"C:\\Program Files\\Mozilla Firefox\\
plugins\\${MyPluginTarget}.dll"
)
若你的執行檔是 Windows 程式, 請加入 Win32
add_executable(demo WIN32 ${SOURCE})
MFC 設定
1 | set(CMAKE_MFC_FLAG 2) |
add_executable(demo WIN32 ${SOURCE})
設定 source code 群組範例
1 | # ex1: |
建立 dll 範例
1 | add_library( target SHARED a.c b.c); |
#console 與 windows (/SUBSYSTEM:CONSOLE or /SUBSYSTEM:WINDOWS)
a. 如果你的程式是 Windows.
=> 則 add_executable(demo WIN32 ${SOURCE})
b. 如果是 console, 則
=> 則 add_executable(demo ${SOURCE})
好用的變數 (more)
PROJECT_SOURCE_DIR
: 包含 project 命令的 CMakeFile.txt 完整路徑. (ex: c:\abc)
1 | set(PROJECT_HOME ${PROJECT_SOURCE_DIR}\\..\\) |
Reference
- make makefile cmake qmake都是什麼,有什麼區別?-玟清的回答-知乎
- CMake筆記
- Eric Noulard - CMake tutorial
- CMake 入門 - 維基教科書,自由的教學讀本
- stackoverflow - Cmake vs make sample codes?
- stackoverflow - cmake CFLAGS CXXFLAGS modification
- stackoverflow - Converting old makefile to CMake
- stackoverflow - Creating CMakeLists file from existing Makefile