Cmake新手使用日記(1)【C++11下的初體驗】
第一次使用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_FLAGS
或CMAKE_C_FLAGS
。
使用這兩種方式在有的情況下效果是一樣的,但請註意它們還是有區別的: add_compile_options
命令添加的編譯選項是針對所有編譯器的(包括c和c++編譯器),而set命令設置CMAKE_C_FLAGS
或CMAKE_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下的初體驗】