本文不介紹cmake命令使用方法,也不講CMakeLists.txt的語法,有需要的讀者可以看我另外相關的文章即可(此為實戰篇)。
本文核心講解添加版本支持、添加編譯庫支持、添加編譯選項支持、添加庫版本信息、添加多文件支持、添加安裝路勁支持、添加測試驗證支持、添加依賴函數與頭文件與庫文件支持、添加三方庫依賴搜索支持、添加生成中間文件支持、添加生成發行版本安裝包支持等功能。
本文共分14章,為了便于學習,內容組織如下:
前面1~7章為基本常用方法,可滿足大部分項目需求;
接下來三(8~10)章節非常簡單,用于支持依賴的檢測,便于學習人員歇口氣;
后面的11~14章為高級功能,可以查詢未知依賴、生成中間依賴文件,還可以制作標準的安裝包。
廢話少說,直接上主菜(復雜的解釋也略過了)。有需要的,可以聯系我獲取每章節的實例。
一、基本工程
最簡單的工程是編譯一個源文件,并生成一個可執行文件。CMakeLists.txt僅僅只需要3行:
cmake_minimum_required(VERSION 2.8)
project(Tutorial)
add_executable(Tutorial tutorial.cxx)
對應的tutorial.cxx源碼用于計算輸入數據的平方根:
// A simple program that computes the suqare root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout, "Usage: %s number\n", argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);
return 0;
}
將tutorial.cxx與CMakeLists.txt放在同一目錄,創建build目錄,并編譯、運行,結果如下:
$ mkdir build
$ ls
build CMakeLists.txt tutorial.cxx
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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: /work/study/Studied_Module/Module/cmake/basic_point/build
$ make
Scanning dependencies of target Tutorial
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
$ ./Tutorial
Usage: ./Tutorial number
$ ./Tutorial 9
The square root of 9 is 3
二、添加配置頭文件
有時候我們需要為我們的代碼添加版本信息,或者其他相關的配置信息。我們當然可以通過直接添加配置的頭文件來實現,不過通過CMakeLists.txt來實現會更加的靈活。下面是基于前面例子實現添加版本信息的CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(Tutorial)
# The version number
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
# configure a header file to pass some of the CMake settings
# to the source code
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
# add the executable
add_executable(Tutorial tutorial.cxx)
上面指定TutorialConfig.h由TutorialConfig.h.in文件生成。TutorialConfig.h.in的內容如下:
// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
當CMake配置這個頭文件時,@Tutorial_VERSION_MAJOR@和@Tutorial_VERSION_MINOR@的值將被CMakeLists.txt文件中的值替換(注意兩邊的名字要一致)。
接下來我們修改tutorial.cxx源碼,看是如何使用CMakeLists.txt定義的版本的:
// A simple program that computes the suqare root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout, "%s Version %d.%d\n", argv[0],
Tutorial_VERSION_MAJOR, Tutorial_VERSION_MINOR);
fprintf(stdout, "Usage: %s number\n", argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);
return 0;
}
建立build目錄,再次編譯結果如下:
$ mkdir build
$ ls
build CMakeLists.txt TutorialConfig.h.in tutorial.cxx
$ cd build/
$ cmake ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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: /work/study/Studied_Module/Module/cmake/basic_version/build
$ make
Scanning dependencies of target Tutorial
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number
$ ./Tutorial 16
The square root of 16 is 4
總結:添加配置頭文件的流程如下:
在CMakeLists.txt中通過set命令設置自己命名的變量;
添加配置文件說明:
configure_file (
"${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
"${PROJECT_BINARY_DIR}/TutorialConfig.h"
)
創建配置文件*.h.in,并使用@variable@來訪問第一步在CMakeLists.txt通過set定義的變量,使用C/C++的標準#define來定義;
在C/C++源碼中通過include包含編譯生成的配置頭文件;
在C/C++源碼中直接使用#define宏定義的名稱。
三、添加一個庫
繼續基于前面的實例,我們將計算平方根的方法提取出來,做成一個mysqrt.cxx源文件庫放在MathFunctions目錄,我們提供的算法名稱為mysqrt()。源碼如下:
$ cd MathFunctions/
$ cat mysqrt.h
#ifndef MYSQRT_H__
#define MYSQRT_H__
double mysqrt(double x);
#endif
$ cat mysqrt.cxx
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double mysqrt(double x)
{
double g = x;
while(fabs(g*g - x) > 0.000001)
{
g = (g+x/g)/2;
}
return g;
}
在MathFunctions目錄中添加子CMakeLists.txt,編譯生成庫文件:
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(MathFunctions)
add_library(MathFunctions SHARED mysqrt.cxx)
接下來修改頂層CMakeLists.txt,添加子目錄MathFunctions的編譯支持,添加頭文件依賴路徑,并添加依賴的庫說明:
include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")
add_library(MathFuncions)
# add the executable
add_executable(Tutorial tutorial.cxx)
add_link_libraries(Tutorial MathFunctions)
最后,修改tutorial.cxx源碼,添加代碼調用我們自己的mysqrt()函數(這里同時調用,還可以驗證我們的算法是否正確):
double inputValue = atof(argv[1]);
double outputValue = sqrt(inputValue);
fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);
outputValue = mysqrt(inputValue);
fprintf(stdout, "The square root of %g is %g\n", inputValue, outputValue);
四、添加編譯選項
繼續接著前面的實例,我們添加了自己的mysqrt()函數,但是我們并不一定都是使用自己的mysqrt()函數,當系統提供了sqrt()時,我們肯定希望調用系統標準的函數。也就是說,我們需要根據系統情況,動態選擇調用方法。
我們當然可以通過在頭文件中添加編譯選項來實現,不過通過CMakeLists.txt來實現將更加靈活有趣。
首先,我們定義一個編譯宏USE_MYMATH(在頂層CMakeLists.txt):
# should we use our own math functions ?
option(USE_MYMATH
"Use tutorial provided math implementation" ON)
這將告訴CMake默認打開USE_MYMATH,當然也可以通過ccmake或者編譯選項來重新配置。接下來我們在頂層CMakeLists.txt同時添加依賴庫的說明:
# add the MathFunctions library ?
#
if (USE_MYMATH)
include_directories("${PROJECT_SOURCE_DIR}/MathFunctions")
add_subdirectory(MathFunctions)
set(EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
#endif(USE_MYMATH)
# add the executable
add_executable(Tutorial tutorial.cxx)
target_link_libraries(Tutorial ${EXTRA_LIBS})
注意:上面添加的USE_MYMATH選項的option命令,必須在configure_file命令之前,否則其默認ON的配置將會無效。
接下來,修改tutorial.cxx源代碼,添加條件編譯代碼:
// A simple program that computes the suqare root of a number
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
#ifdef USE_MYMATH
#include "mysqrt.h"
#endif
int main(int argc, char *argv[])
{
if (argc < 2)
{
fprintf(stdout, "%s Version %d.%d\n", argv[0],
Tutorial_VERSION_MAJOR, Tutorial_VERSION_MINOR);
fprintf(stdout, "Usage: %s number\n", argv[0]);
return 1;
}
double inputValue = atof(argv[1]);
#ifdef USE_MYMATH
double outputValue = mysqrt(inputValue);
fprintf(stdout, "The square root of %g is %g(use tutorial mysqrt())\n", inputValue, outputValue);
#else
double outputValue = sqrt(inputValue);
fprintf(stdout, "The square root of %g is %g(use system sqrt())\n", inputValue, outputValue);
#endif
return 0;
}
最后,在TutorialConfig.h.in中添加支持,以便在CMake命令行傳入不同的編譯選項時生成不同的TutorialConfig.h文件:
#cmakedefine USE_MYMATH
創建build目錄,并編譯驗證結果如下:
使用mysqrt():
$ mkdir build
$ ls
build CMakeLists.txt MathFunctions TutorialConfig.h.in tutorial.cxx
$ cd build/
[study@konishi build]$ cmake -DUSE_MYMATH=True ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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: /work/study/Studied_Module/Module/cmake/04_basic_options/build
$ make
Scanning dependencies of target MathFunctions
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX shared library libMathFunctions.so
[ 50%] Built target MathFunctions
Scanning dependencies of target Tutorial
[ 75%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number
$ ./Tutorial 12
The square root of 12 is 3.4641(use tutorial mysqrt())
使用系統的sqrt():
$ mkdir build
$ ls
build CMakeLists.txt MathFunctions TutorialConfig.h.in tutorial.cxx
$ cd build/
$ cmake -DUSE_MYMATH=False ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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: /work/study/Studied_Module/Module/cmake/04_basic_options/build
$ make
Scanning dependencies of target Tutorial
[ 50%] Building CXX object CMakeFiles/Tutorial.dir/tutorial.cxx.o
[100%] Linking CXX executable Tutorial
[100%] Built target Tutorial
[study@konishi build]$ ./Tutorial
./Tutorial Version 1.0
Usage: ./Tutorial number
$ ./Tutorial 13
The square root of 13 is 3.60555(use system sqrt())
總結:添加配置選項的流程如下: