1. 程式人生 > >Cmake新手使用日記(1)【C++11下的初體驗】

Cmake新手使用日記(1)【C++11下的初體驗】

pen 如何 其他 err ++ targe 使用 可執行文件 使用教程

  第一次使用Cmake,搜索了很多使用教程,包括《Cmake實踐》、《Cmake手冊》等,但是在針對最新的C++11條件下編程還是會存在一點點問題,需要實驗很多次錯誤並搜索大量文章才能解決問題。這裏用新手日記的方式告訴一個Cmake小白如何在C++11下使用Cmake。

  一般情況下,直接閱讀文檔會不太適應新手,沒有感官的認識,沒有經驗。這裏將自己的學習過程記錄下來,方便自己查閱,也方便其他新手學習。

  首先先聲明一下Cmake腳本,其實就是CMakeLists.txt的基本語法規則:

  •  變量使用${}方式取值,但是在 IF 控制語句中是直接使用變量名
  •  指令(參數 1 參數 2...) 參數使用括弧括起,參數之間使用空格或分號分開。   
  •  指令是大小寫無關的,參數和變量是大小寫相關的。但,推薦你全部使用大寫指令。

  一、單文件編譯

  (1)操作過程

  <1>創建一個目錄t1.  

  <2>編寫代碼:

  main.cpp

 1 #include <iostream>
 2 #include <vector>
 3 int main()
 4 {
 5 
 6         using namespace std;
 7         vector<int> V(5,3);
 8         for(auto e:V)
 9                 cout << e << endl;
10 cout << "OK" << endl; 11 return 0; 12 13 }

  <3>編寫CMakeLists.txt

  【註意】不要忘記“CMakeLists.txt”中“.”前還有一個“s”,如果你很粗心,估計會在這裏抓耳撓腮。

  

PROJECT (HELLO)
SET(CMAKE_C_COMPILER g++)
if(CMAKE_COMPILER_IS_GNUCXX) add_compile_options(-std=c++11)
  message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)
SET(SRC_LIST main.cpp)
ADD_EXECUTABLE(hello ${SRC_LIST})

  <4>在t1文件夾下編譯

  先運行,註意Cmake後面的小點點“.”表示當前目錄。

  

Cmake .

  再運行

  

make

  <5>運行程序  

  此時,再t1文件夾下會產生hello文件,運行

./hello

程序就正確運行啦。

  輸出

@ubuntu:~/t1$ ./hello
3
3
3
3
3
OK

  (2)過程解釋

  首先,在CMakeLists.txt中,命令可以使用大寫、小寫、混寫。

  PROJECT (HELLO)是CMakeLists.txt的第一句,告訴編譯器這個工程名叫hello。

  SET(CMAKE_C_COMPILER g++)聲明使用g++編譯器,因為如果是.c文件的話通常使用默認的gcc編譯器。

  add_compile_options(-std=c++11)告訴編譯器使用的是c++11,但是如果不設置g++編譯器,又不判斷一下編譯器的話會出現下面的運行結果:

@ubuntu:~/t1$ make
Scanning dependencies of target hello
[ 50%] Building CXX object CMakeFiles/hello.dir/main.o
c++: error: unrecognized command line option ‘-std=C++11’
CMakeFiles/hello.dir/build.make:62: recipe for target ‘CMakeFiles/hello.dir/main.o‘ failed
make[2]: *** [CMakeFiles/hello.dir/main.o] Error 1
CMakeFiles/Makefile2:67: recipe for target ‘CMakeFiles/hello.dir/all‘ failed
make[1]: *** [CMakeFiles/hello.dir/all] Error 2
Makefile:83: recipe for target ‘all‘ failed
make: *** [all] Error 2

  有的博客裏說能夠編譯完成,但是在這裏有時候就完不成。當然有時候也能完成,這個可能和具體的系統有關吧。

  當出現上述問題時,可以使用設置編譯器的方式解決,也可以使用if語句進行判斷,這裏為了能夠將所有情況都講清楚,就暫時多此一舉這個寫了。其中CMAKE_COMPILER_IS_GNUCXX用於判斷編譯器類型。

  但是作者也碰到這樣的問題,如果不設置編譯器為g++,第一次設置編譯器為std=c++11屬性時報錯,但是一旦設置完成功運行之後,即使吧編譯器設置的語句去掉,把t1下面除了main.cpp和CMakeLists.txt之外的語句去掉,也能正常編譯。真的有些奇怪。

  message(STATUS "optional:-std=c++11")可以用於打印一些提示信息,這裏在運行完CMake .之後,就把“”中的文字打印出來了。實際上, 除了用STATUS打印普通標識,message還有一些其他的打印功能,如用SEND_ERROR,產生錯誤信息,生成過程被跳過。如果使用 FATAL_ERROR,立即終止所有 cmake 過程。

  接著SET(SRC_LIST main.cpp) 和ADD_EXECUTABLE(hello ${SRC_LIST}) 語句。定義了這個工程會生成一個文件名為 hello 的可執行文件,相關的源文件是 SRC_LIST 中 定義的源文件列表, 本例中也可以直接寫成 ADD_EXECUTABLE(hello main.c)。

  ${}來引用變量,這是 cmake 的變量應用方式,但是,有一些例外,比 如在 IF 控制語句,變量是直接使用變量名引用(如這裏的CMAKE_COMPILER_IS_GNUCXX),而不需要${}。如果使用了${}去應用變量,其實 IF 會去判斷名為${}所代表的值的變量,那當然是不存在的了。

  (3)一點註意

  在CMakeLists.txt腳本中,設置編譯選項可以通過add_compile_options命令,也可以通過set命令修改CMAKE_CXX_FLAGSCMAKE_C_FLAGS

  使用這兩種方式在有的情況下效果是一樣的,但請註意它們還是有區別的:
  add_compile_options命令添加的編譯選項是針對所有編譯器的(包括c和c++編譯器),而set命令設置CMAKE_C_FLAGSCMAKE_CXX_FLAGS變量則是分別只針對c和c++編譯器的。因此,下面的代碼也是一樣的效果哦!

PROJECT (HELLO)

SET(CMAKE_C_COMPILER g++)
if(CMAKE_COMPILER_IS_GNUCXX)
   set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
endif(CMAKE_COMPILER_IS_GNUCXX)

SET(SRC_LIST main.cpp)
ADD_EXECUTABLE(hello ${SRC_LIST})

Cmake新手使用日記(1)【C++11下的初體驗】