本文是CMake Tutorial的心得, CMake是一個用於build, test與package的cross-platform tool, 基本上是透過撰寫CMakeLists來描述如何build, test與package專案,接著會產生makefile, 再透過makefile產生最終的target(executable, library, or both)
讓我們從最簡單的CMakeLists.txt開始,基本上CMakeLists.txt的指令是不分大小寫的
# Require a minimum version of cmake. # cmake_minimum_required(VERSION <min>>[...<policy_max>] [FATAL_ERROR]) cmake_minimum_required(VERSION 3.10) # Set the name of the project. # project(<PROJECT-NAME< [<anguage-name>...]) # project(<PROJECT-NAME> # [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] # [DESCRIPTION <project-description-string>] # [HOMEPAGE_URL <url-string>] # [LANGUAGES <language-name>...]) project(Tutorial VERSION 0.1.2 DESCRIPTION "This is Brook 1st CMake") # Add an executable to the project using the specified source files. # add_executable(<name> [WIN32] [MACOSX_BUNDLE] # [EXCLUDE_FROM_ALL] # [source1] [source2 ...]) add_executable(Tutorial hello.c)
hello.c
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { printf("hello world\n"); return 0; }
有了CMakeLists.txt與source code, 就可以使用cmake [options] <path-to-source>建立Makefile, 並使用cmake --build <dir>去build targe
[brook@:~/Projects/cmake]$ tree . `-- src |-- CMakeLists.txt `-- hello.c 1 directory, 2 files [brook@:~/Projects/cmake]$ mkdir build && cd build [brook@:~/Projects/cmake/build]$ cmake ../src/ -- The C compiler identification is GNU 7.5.0 -- The CXX compiler identification is GNU 7.5.0 -- 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 -- Detecting C compile features -- Detecting C compile features - 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 -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /build/brook/Projects/cmake/build [brook@:~/Projects/cmake/build]$ ls CMakeCache.txt CMakeFiles Makefile cmake_install.cmake [brook@:~/Projects/cmake/build]$ cmake --build . Scanning dependencies of target Tutorial [ 50%] Building C object CMakeFiles/Tutorial.dir/hello.c.o [100%] Linking C executable Tutorial [100%] Built target Tutorial [brook@:~/Projects/cmake/build]$ ls CMakeCache.txt CMakeFiles Makefile Tutorial cmake_install.cmake [brook@:~/Projects/cmake/build]$ ./Tutorial hello world
Adding a Version Number and Configured Header File
前面的CMakeLists.txt中描述了project(Tutorial VERSION 0.1.2 DESCRIPTION "This is Brook 1st CMake"), 但是沒在C code中被用到, 所以, 我們將這些變數加入configure a header file 並傳遞給source code# Require a minimum version of cmake. # cmake_minimum_required(VERSION <min>>[...<policy_max>] [FATAL_ERROR]) cmake_minimum_required(VERSION 3.10) # Set the name of the project. # project(<PROJECT-NAME< [<anguage-name>...]) # project(<PROJECT-NAME> # [VERSION <major>[.<minor>[.<patch>[.<tweak>]]]] # [DESCRIPTION <project-description-string>] # [LANGUAGES <language-name>...]) project(Tutorial VERSION 0.1.2 DESCRIPTION "This is Brook 1st CMake") # Add an executable to the project using the specified source files. # add_executable(<name> [WIN32] [MACOSX_BUNDLE] # [EXCLUDE_FROM_ALL] # [source1] [source2 ...]) add_executable(Tutorial hello.c) # Copy a file to another location and modify its contents. # configure_file(<input> <output> # [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS | # FILE_PERMISSIONS <permissions>...] # [COPYONLY] [ESCAPE_QUOTES] [@ONLY] # [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) configure_file(Config.h.in Config.h) # Add include directories to a target. # target_include_directories(&;lt;target> [SYSTEM] [AFTER|BEFORE] # &;lt;INTERFACE|PUBLIC|PRIVATE> [items1...] # [&;lt;INTERFACE|PUBLIC|PRIVATE> [items2...] ...]) target_include_directories(Tutorial PUBLIC "${PROJECT_BINARY_DIR}")
首先先透過configure_file()設定configure file的input與output, 在CMake建立Makefile過程中, 就會將configure的input變數取代後, 產生configure的output檔. 由於configure header file要被source code給include進來, 所以還得透過target_include_directories()設定對應的include path. 相關執行步驟如下:
[brook@:~/Projects/cmake]$ tree . `-- src |-- CMakeLists.txt |-- Config.h.in `-- hello.c 1 directory, 3 files [brook@:~/Projects/cmake]$ cat src/Config.h.in // the configured options and settings for Tutorial #define VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define VERSION_MINOR @Tutorial_VERSION_MINOR@ [brook@:~/Projects/cmake]$ cat src/hello.c #include <stdio.h> #include <stdlib.h> #include "Config.h" int main(int argc, char *argv[]) { printf("hello world(version: %d.%d)\n", VERSION_MAJOR, VERSION_MINOR); return 0; } [brook@:~/Projects/cmake]$ mkdir build && cd build [brook@:~/Projects/cmake/build]$ cmake ../src/ -- The C compiler identification is GNU 7.5.0 -- The CXX compiler identification is GNU 7.5.0 -- 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 -- Detecting C compile features -- Detecting C compile features - 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 -- Detecting CXX compile features -- Detecting CXX compile features - done -- Configuring done -- Generating done -- Build files have been written to: /build/brook/Projects/cmake/build [brook@:~/Projects/cmake/build]$ ls CMakeCache.txt CMakeFiles Config.h Makefile cmake_install.cmake [brook@:~/Projects/cmake/build]$ cmake --build . Scanning dependencies of target Tutorial [ 50%] Building C object CMakeFiles/Tutorial.dir/hello.c.o [100%] Linking C executable Tutorial [100%] Built target Tutorial [brook@:~/Projects/cmake/build]$ ./Tutorial hello world(version: 0.1) [brook@:~/Projects/cmake/build]$ cat Config.h // the configured options and settings for Tutorial #define VERSION_MAJOR 0 #define VERSION_MINOR 1
在這裡我們有用到幾個CMake的變數, 包含PROJECT_BINARY_DIR, <PROJECT-NAME>_VERSION_MAJOR, PROJECT_BINARY_DIR等等, 這些都可以參考cmake-variables(7)取得更多的變數與相關細節, 我這裡就簡單介紹幾個基本的, 並透過Configure header file讓大家稍微理解一下對應的值
[brook@:~/Projects/cmake/build]$ cat ../src/Config.h.in // the configured options and settings for Tutorial #define VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define VERSION_MINOR @Tutorial_VERSION_MINOR@ // <PROJECT-NAME>_BINARY_DIR // A variable is created with the name used in the project() command, // and is the binary directory for the project. #define Tutorial_BINARY_DIR @Tutorial_BINARY_DIR@ // <PROJECT-NAME>_SOURCE_DIR // Top level source directory for the named project. // A variable is created with the name used in the project() command, // and is the source directory for the project. #define Tutorial_SOURCE_DIR @Tutorial_SOURCE_DIR@ // <PROJECT-NAME>_VERSION // Value given to the VERSION option of the most recent call // to the project() command with project name <PROJECT-NAME> #define Tutorial_VERSION "@Tutorial_VERSION@" #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ #define Tutorial_VERSION_PATCH @Tutorial_VERSION_PATCH@ #define Tutorial_VERSION_TWEAK @Tutorial_VERSION_TWEAK@ // Full path to build directory for project. // This is the binary directory of the most recent project() command. #define PROJECT_BINARY_DIR @PROJECT_BINARY_DIR@ // Short project description given to the project command. // This is the description given to the most recent project() command. #define PROJECT_DESCRIPTION "@PROJECT_DESCRIPTION@" // Name of the project given to the project command. // This is the name given to the most recent project() command. #define PROJECT_NAME @PROJECT_NAME@ // Top level source directory for the current project. // This is the source directory of the most recent project() command. #define PROJECT_SOURCE_DIR @PROJECT_SOURCE_DIR@ // Value given to the VERSION option of the most recent call to the project() command #define PROJECT_VERSION "@PROJECT_VERSION@" #define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define PROJECT_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define PROJECT_VERSION_PATCH @PROJECT_VERSION_PATCH@ #define PROJECT_VERSION_TWEAK @PROJECT_VERSION_TWEAK@ [brook@:~/Projects/cmake/build]$ cmake ../src/ -- Configuring done -- Generating done -- Build files have been written to: /build/brook/Projects/cmake/build [brook@:~/Projects/cmake/build]$ cat Config.h // the configured options and settings for Tutorial #define VERSION_MAJOR 0 #define VERSION_MINOR 1 // <PROJECT-NAME>_BINARY_DIR // A variable is created with the name used in the project() command, // and is the binary directory for the project. #define Tutorial_BINARY_DIR /build/brook/Projects/cmake/build // <PROJECT-NAME>_SOURCE_DIR // Top level source directory for the named project. // A variable is created with the name used in the project() command, // and is the source directory for the project. #define Tutorial_SOURCE_DIR /build/brook/Projects/cmake/src // <PROJECT-NAME>_VERSION // Value given to the VERSION option of the most recent call // to the project() command with project name <PROJECT-NAME> #define Tutorial_VERSION "0.1.2" #define Tutorial_VERSION_MAJOR 0 #define Tutorial_VERSION_MINOR 1 #define Tutorial_VERSION_PATCH 2 #define Tutorial_VERSION_TWEAK // Full path to build directory for project. // This is the binary directory of the most recent project() command. #define PROJECT_BINARY_DIR /build/brook/Projects/cmake/build // Short project description given to the project command. // This is the description given to the most recent project() command. #define PROJECT_DESCRIPTION "This is Brook 1st CMake" // Name of the project given to the project command. // This is the name given to the most recent project() command. #define PROJECT_NAME Tutorial // Top level source directory for the current project. // This is the source directory of the most recent project() command. #define PROJECT_SOURCE_DIR /build/brook/Projects/cmake/src // Value given to the VERSION option of the most recent call to the project() command #define PROJECT_VERSION "0.1.2" #define PROJECT_VERSION_MAJOR 0 #define PROJECT_VERSION_MINOR 1 #define PROJECT_VERSION_PATCH 2 #define PROJECT_VERSION_TWEAK