最基本的工程是將源碼文件編譯成一個可執行程序。對於一個很簡單的工程,CMakeLists.txt只須要以下幾行文件便可。這將是咱們教程的開始。CMakeLists.txt文件就像這樣。c++
cmake_minimum_required (VERSION 2.6) project (Tutorial) add_executable(Tutorial tutorial.cxx)
上面的cmake是採用小寫寫成的。cmake支持採用大寫,也能夠採用小寫或者混合大小寫的命令來。這個源碼將會計算一個數的平方根。初版是比較簡單的。as follow:app
// A simple program that computes the square 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; }
第一個特徵將會提供給可執行程序一個版本號。你能夠將這個版本號提供在程序裏。固然也能夠寫在cmake裏。寫在cmake裏面會更靈活一些。ide
cmake_minimum_required (VERSION 2.6) 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)
由於配置文件會被寫入binary tree。咱們必須添加目錄到頭文件的搜索目錄。咱們在源碼路徑下建立一個TutorialConfig.h.in的文件。函數
// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
When CMake configures this header file the values for @Tutorial_VERSION_MAJOR@ and @Tutorial_VERSION_MINOR@ will be replaced by the values from the CMakeLists.txt file. Next we modify tutorial.cxx to include the configured header file and to make use of the version numbers. The resulting source code is listed below.測試
當cmake的配置這些頭文件的值時,@Tutorial_VERSION_MAJOR@ 和@Tutorial_VERSION_MINOR@將會把cmakelists.txt的值替換調。如今咱們修改tutorial.cxx的文件以下所示。ui
// A simple program that computes the square 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; }
step2.添加運行時庫this
如今咱們將添加一個庫到咱們的工程中。這個工程將包含咱們本身實現的計算一個書數的平方根。這個程序可以利用庫去替換編譯器提供的標準求根函數。對於這個教程咱們將把這個庫放在一個叫mathfunctions的子目錄下。cmakelists.file是以下所示。spa
add_library(MathFunctions mysqrt.cxx)
源碼文件有一個叫mysqrt的函數提供相似編譯器的求根函數。確保利用咱們的新庫。咱們把add_subdirectory放在了CMakeLists.txt放在了庫的前面。這樣庫將會被構建。咱們也添加了另一個include directory ,添加MathFunctions/MathFunctions.h 的頭文件/這樣可以找到函數的原型。最後要連接函數庫到咱們的可執行程序裏。code
include_directories ("${PROJECT_SOURCE_DIR}/MathFunctions") add_subdirectory (MathFunctions) # add the executable add_executable (Tutorial tutorial.cxx) target_link_libraries (Tutorial MathFunctions)
如今添加一個MathFunctions庫的可行性。在這個教程裏雖然沒有什麼理由這樣作。可是在更大的庫或者依賴第三方庫的時候,你可能會須要。你在CMakeLists.txt 文件的頂層添加一個選項。orm
# should we use our own math functions? option (USE_MYMATH "Use tutorial provided math implementation" ON)
這個會顯示在CMake的GUI裏,默認是ON,使用者能夠按須要改變 。設置後會被保存在cache裏,客戶每次cmake工程的時候,都不須要去設置。下一個改變是構建和連接MathFunctions。
# 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去決定是否編譯和連接它。注意變量EXTRA_LIBS,它是用於收集庫以便於後面連接可執行程序時使用。這是一個廣泛的方法使用選項,讓一個大的工程保持簡潔的方法 。代碼裏相應的改變也是比較簡單直白地。
// A simple program that computes the square root of a number #include <stdio.h> #include <stdlib.h> #include <math.h> #include "TutorialConfig.h" #ifdef USE_MYMATH #include "MathFunctions.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); #else double outputValue = sqrt(inputValue); #endif fprintf(stdout,"The square root of %g is %g\n", inputValue, outputValue); return 0; }
在源碼裏咱們設置了USE_MYMATH。這是設置給CMake的,經過配置文件TutorialConfig.h.in來設置。
#cmakedefine USE_MYMATH
接下來,咱們會添加安裝規則和測試支持咱們的項目。安裝的規則是至關直白的。對於MathFunctions庫,咱們安裝頭文件和庫添加以下如何兩行到MathFunctions的CMakeLists.txt文件:
install (TARGETS MathFunctions DESTINATION bin) install (FILES MathFunctions.h DESTINATION include)
For the application,這兩行添加頂層的CMakeLists.txt,去安裝可執行程序和配置文件
# add the install targets install (TARGETS Tutorial DESTINATION bin) install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" DESTINATION include)
下載你就能夠構建tutorial,而後輸入make install (或者構建IDE中的INSTALL目標),它將會將頭文件和庫和可執行程序安裝在合適的位置。CMake的變量CMAKE_INSTALL_PREFIX是用於決定文件安裝的根目錄。添加測試也是至關簡單地一項工程。在頂層的CMakeLists.txt文件底部咱們能夠添加a number of basic tests去驗證應用是否正確。
include(CTest) # does the application run add_test (TutorialRuns Tutorial 25) # does it sqrt of 25 add_test (TutorialComp25 Tutorial 25) set_tests_properties (TutorialComp25 PROPERTIES PASS_REGULAR_EXPRESSION "25 is 5") # does it handle negative numbers add_test (TutorialNegative Tutorial -25) set_tests_properties (TutorialNegative PROPERTIES PASS_REGULAR_EXPRESSION "-25 is 0") # does it handle small numbers add_test (TutorialSmall Tutorial 0.0001) set_tests_properties (TutorialSmall PROPERTIES PASS_REGULAR_EXPRESSION "0.0001 is 0.01") # does the usage message work? add_test (TutorialUsage Tutorial) set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")
在組建後,能夠運行ctest命令運行測試。第一個測試是簡單地驗證應用運行,沒有段錯誤或其餘的崩潰問題(does not segfault or otherwise crash),而且有一個0的返回值。或者有一個返回值是0。這是CTest的基礎測試。下面的測試使用了PASS_REGULAR_EXPRESSION來測試輸出信息是否包含有字符串。在這個案例裏驗證計算平方根是不然正確,在提供錯誤的參數時,打印信息是否正確。若是你想添加大量的測試去驗證不一樣的輸入參數,你能夠考慮建立 macro.
接下來咱們考慮添加一些代碼到咱們的工程裏,在有些平臺裏可能沒有的特性。在這個例子裏咱們根據目標平臺是否有log和exp函數添加一些代碼。固然差很少每一個平臺都有這些函數,但對於這個教程咱們假設他們是很不普通的。若是平臺裏有log函數,那咱們將優先使用它。咱們首先利用CheckFunctionExists.cmake測試這些函數的可用性。
# does this system provide the log and exp functions? include (CheckFunctionExists) check_function_exists (log HAVE_LOG) check_function_exists (exp HAVE_EXP)
在TutorialConfig.h.in定義宏,cmake可以發現他們在各個平臺下面。
// does the platform provide exp and log functions? #cmakedefine HAVE_LOG #cmakedefine HAVE_EXP
在使用配置文件TutorialConfig.h前,測試log和exp。配置文件會當即使用cmake當中的設置。最終在mysqrt函數咱們裏咱們提供了兩種實現方式。
// if we have both log and exp then use them #if defined (HAVE_LOG) && defined (HAVE_EXP) result = exp(log(x)*0.5); #else // otherwise use an iterative approach . . .
在這節中,咱們添加一個生成的源文件到應用程序的構建中去。咱們建立一個預先生成的平方根表做爲構建過程的一部分,編譯它到application。爲了達到這一點,咱們須要一個程序去生成這個表。在MathFunctions 的目錄裏添加一個新文件MakeTable.cxx作這個。
// A simple program that builds a sqrt table #include <stdio.h> #include <stdlib.h> #include <math.h> int main (int argc, char *argv[]) { int i; double result; // make sure we have enough arguments if (argc < 2) { return 1; } // open the output file FILE *fout = fopen(argv[1],"w"); if (!fout) { return 1; } // create a source file with a table of square roots fprintf(fout,"double sqrtTable[] = {\n"); for (i = 0; i < 10; ++i) { result = sqrt(static_cast<double>(i)); fprintf(fout,"%g,\n",result); } // close the table with a zero fprintf(fout,"0};\n"); fclose(fout); return 0; }
注意:這個表是由c++代碼產生的,輸出文件名是一個輸入參數。下一步咱們要在MathFunctions的CMakeLists.txt文件添加適當的命令來構建MakeTable可執行程序。而且在構建時,運行它。須要添加的命令以下所示:
# first we add the executable that generates the table add_executable(MakeTable MakeTable.cxx) # add the command to generate the source code add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h DEPENDS MakeTable ) # add the binary tree directory to the search path for # include files include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) # add the main library add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h )
首先,MakTable就像其餘可執行程序同樣是被視爲可執行程序。而後咱們添加一個自定義命令來指定如何生。 接下來,咱們須要讓cmake知道mysqrt.cxx依賴Table.h。這是經過往MahFuncitons庫添加生成的文件Table.h來實現的。把mysqrt。cxx添加當前的生成目錄到搜索路徑中。
當這個工程被構建時,首先它會構建MakeTable。運行MakeTable產生Table.h。最後,它會編譯mysqrt.cxx來生成MathFunctions庫。咱們修改頂層的cmakeLists.txt以下所示:
cmake_minimum_required (VERSION 2.6) project (Tutorial) include(CTest) # The version number. set (Tutorial_VERSION_MAJOR 1) set (Tutorial_VERSION_MINOR 0) # does this system provide the log and exp functions? include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake) check_function_exists (log HAVE_LOG) check_function_exists (exp HAVE_EXP) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) # 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 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}) # add the install targets install (TARGETS Tutorial DESTINATION bin) install (FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" DESTINATION include) # does the application run add_test (TutorialRuns Tutorial 25) # does the usage message work? add_test (TutorialUsage Tutorial) set_tests_properties (TutorialUsage PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number" ) #define a macro to simplify adding tests macro (do_test arg result) add_test (TutorialComp${arg} Tutorial ${arg}) set_tests_properties (TutorialComp${arg} PROPERTIES PASS_REGULAR_EXPRESSION ${result} ) endmacro (do_test) # do a bunch of result based tests do_test (4 "4 is 2") do_test (9 "9 is 3") do_test (5 "5 is 2.236") do_test (7 "7 is 2.645") do_test (25 "25 is 5") do_test (-25 "-25 is 0") do_test (0.0001 "0.0001 is 0.01")
TutorialConfig.h.in looks like:
// the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ #cmakedefine USE_MYMATH // does the platform provide exp and log functions? #cmakedefine HAVE_LOG #cmakedefine HAVE_EXP
MathFunctions的CMakeLists.txt以下所示:
# first we add the executable that generates the table add_executable(MakeTable MakeTable.cxx) # add the command to generate the source code add_custom_command ( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h DEPENDS MakeTable COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h ) # add the binary tree directory to the search path # for include files include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) # add the main library add_library(MathFunctions mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h) install (TARGETS MathFunctions DESTINATION bin) install (FILES MathFunctions.h DESTINATION include)
咱們想要發佈咱們的程序讓其餘人可以使用它。咱們想要提供給他們不一樣平臺的二進制文件和代碼。這裏的安裝是和咱們步驟3提供的安裝方式有點不肯意的。在步驟3咱們是從源代碼中構建安裝二進制文件。咱們要構建安裝包來支持二進制安裝和包管理,例如cygwin, debian, RPMs等等。咱們會使用CPack來建立平臺相關的安裝包。咱們須要在頂層的CMakeLists.txt file添加以下幾行。
# build a CPack driven installer package include (InstallRequiredSystemLibraries) set (CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") set (CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") set (CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") include (CPack)
咱們首先包含了InstallRequiredSystemLibraries.。這個模塊將會提供當前平臺須要的任何的運行時庫。接下來咱們設置CPack的變量,來保持工程的信息和license。版本信息是利用了咱們早先設置的變量。最終咱們包含了CPack模塊,它將會使用全部的變了和一些在系統裏已經設置的屬性。來指定安裝包。
接下來運行這個命令來構建二進制安裝包。
cpack --config CPackConfig.cmake
建立一個源碼包你要以下命令。
cpack --config CPackSourceConfig.cmake
支持上傳測試結果到dashboard是很是簡單的。咱們已經定義了一些測試案例。咱們只須要運行這些測試而後提交他們到dashboard。咱們只須要在頂層的CMakeLists包含CTest模塊,咱們就能夠支持上傳測試結果到Dashboard。
# enable dashboard scripting include (CTest)
咱們建立一個CTestConfig.cmake文件,那樣咱們能夠指定dashboard上這個工程的名字。
set (CTEST_PROJECT_NAME "Tutorial")
CTest將會閱讀這個和執行它。建立一個簡單的dashboard,你能夠運行CMake在你的工程裏,改變生成文件的路徑,而後運行ctest –D Experimental。而後你的測試結果會被上傳到Kitware的公共dashboard中。
最後整個工程的源代碼在cmake的源碼路徑Tests/Tutorial下面。