很久沒用C++了,從C又換到C++編譯器遇到的一個小問題,但是也困擾了很久...
在C的complier上,struct或enum,可以指定初值且不按順序,但在C++上指定初值時
並須按順序且不能跳過。
這是因為C++指援不定引數的功能,例如在function上傳的引數,可以在runtime時
決定要傳幾個。例如void fun(int a, int b=1, int c=2),而在使用時可決定只用fun(10)或fun(10,11,12)。 但是不能跳過,例如void fun(int a=2, int b, int c=3),只能從最右邊開始
給定初值 。
這次程式中在定義enum並指定初值的時後,有一個值未defined造成有一個值跳過去,故
一直出現此錯誤,但這個寫法在C的complier上是很常見的。
補充:
non-trivial constructor/destructor
意思是指class或struct的非默認建構/解構子
code style
2016年11月27日 星期日
2016年11月1日 星期二
Ubuntu - change shell from dash to bash
因為Ubuntu 16的預設shell 是dash,和之前Fedora的bash不同,在語法上也有差異。
dash是bash的輕量版,執行速度較快,Ubuntu建議使用dash來獲得
dash是bash的輕量版,執行速度較快,Ubuntu建議使用dash來獲得
更好的效能。但是之前寫的script也懶的改了,還是更改預設的shell比較快。
更改方法:
1.在執行前加bash, bash ./your_shell_script,但每次都要加
2.sudo dpkg-reconfigure dash,選no,default就會跳會bash,此法一勞永逸
更改方法:
1.在執行前加bash, bash ./your_shell_script,但每次都要加
2.sudo dpkg-reconfigure dash,選no,default就會跳會bash,此法一勞永逸
2016年10月27日 星期四
linux指令 - 列出指定目錄下的所有目錄路徑
為了要使用kdevelop來看code,要手動加入所有include路徑,只好改用指令過瀘出路徑,再存成一個檔案,最後用batch edit來加入。
下面這指令是列出指定目錄下的所有目錄路徑,並忽略隱藏檔,還有要忽略build這個資料夾(包含其子目綠),最後存到include_dirs
find /home/hughes/CEServices-4.00.01/src -type d ! -name ".*" | grep -v build > /home/hughes/include_dirs
下面這指令是列出指定目錄下的所有目錄路徑,並忽略隱藏檔,還有要忽略build這個資料夾(包含其子目綠),最後存到include_dirs
find /home/hughes/CEServices-4.00.01/src -type d ! -name ".*" | grep -v build > /home/hughes/include_dirs
簡單的拆開來看:
1. 找出src底下的目錄並忽略隱藏檔
2. 結果重導給grep,並找尋路徑中不含"build"的內容
3.存到include_dirs
2016年10月26日 星期三
kubuntu16 安裝問題
使用vmware安裝 kubuntu16 時,出現Unable to find a medium containing a live file system。
上網查了一下,有可能是檔案下載不完全或者光碟機老舊或光碟機不支援。
重新下載了一次,也是一樣結果。後來把vmware的光碟機由sata 變為ide就可以了。
上網查了一下,有可能是檔案下載不完全或者光碟機老舊或光碟機不支援。
重新下載了一次,也是一樣結果。後來把vmware的光碟機由sata 變為ide就可以了。
2016年10月24日 星期一
CMake筆記(6) - 編譯選項
Makefile的建置資訊:
在預設的情況下,CMake 生成的 makefile 只會顯示編譯的進度,並不會把各步驟實際調用的命令、參數一一列出。如果需要這類資訊的話,就可設定makefile中的verbose,有3種方法:
1.在CMakeList.txt 中加入, set(CMAKE_VERBOSE_MAKEFILE ON)
2.在cmake執行時加入,$ cmake -DCMAKE_VERBOSE_MAKEFILE=ON ...options...
3.在make執行時加入,make VERBOSE=1
編譯組態:
連結選項:
上例的各種組態都採用 -static 來連結可執行檔,並且只有在 Release 情況下另外加入 -s 連結選項,亦即 Release 的連結選項為 -static -s
Preprocessor:
編譯器搜尋路徑:
使用屬性控制編譯選項:
以上介紹的變數和指令都是屬於全域範圍的設定,如果希望選項僅對一個 target 有效,就必須從 target 的屬性(properties)下手。
在 CMake 裡一個 target 最終的輸出檔名、編譯連結選項等等都是由屬性控制,若沒有手動設定這些屬性,則 CMake 會由相關的全域變數來決定屬性值。我們可以利用 set_target_properties() 指令單獨指定一個 target 的屬性,如此一來就可以蓋過全域變數的設定。
set_target_properties() 指令格式如下:
例如下例,這些屬性會蓋過原先全域變數的設定,而且僅作用在 app 這個 target 上:
注意事項:
1. 小心覆寫變數
像 CMAKE_C_FLAGS_RELEASE、CMAKE_C_FLAGS_DEBUG 這些變數,CMake 會自動依照 Generator 指定的編譯器初始化。例如在 gcc 下 CMAKE_C_FLAGS_RELEASE 預設的值為 -O3 -DNDEBUG,而 CMAKE_C_FLAGS_DEBUG 預設值為 -g。
小心下面這種寫法:
(1) 會傳遞 -static -s 給編譯器 (2) 會傳遞 -static;-s 給編譯器
實際應用的範例:
設定g++為編譯器,並build release的版本:
在預設的情況下,CMake 生成的 makefile 只會顯示編譯的進度,並不會把各步驟實際調用的命令、參數一一列出。如果需要這類資訊的話,就可設定makefile中的verbose,有3種方法:
1.在CMakeList.txt 中加入, set(CMAKE_VERBOSE_MAKEFILE ON)
2.在cmake執行時加入,$ cmake -DCMAKE_VERBOSE_MAKEFILE=ON ...options...
3.在make執行時加入,make VERBOSE=1
編譯組態:
透過指定 CMAKE_BUILD_TYPE 變數即可改變編譯組態,預設的 CMAKE_BUILD_TYPE 是 None,即不加上任何額外編譯選項。內建的 CMAKE_BUILD_TYPE 支援以下幾種組態:
- None : 編譯器預設值
- Debug : 產生除錯資訊
- Release : 進行執行速度最佳化
- RelWithDebInfo : 進行執行速度最佳化,但仍然會啟用 debug flag
- MinSizeRel : 進行程式碼最小化
也可以從cmake執行時才加入,例如:
cmake -DCMAKE_BUILD_TYPE=Release ./src
編譯選項:
變數 CMAKE_C_FLAGS 存放的內容會被傳給 C 編譯器,作用在所有的編譯組態上。如果希望只針對特定一種組態有效,可以設定 CMAKE_C_FLAGS_<編譯組態>,例如 CMAKE_C_FLAGS_RELEASE、CMAKE_C_FLAGS_DEBUG。如果是C++編譯器,則是CMAKE_CXX_FLAGS 和 CMAKE_CXX_FLAGS_<編譯組態>。
舉個具體的例子,在 Visual C++ 底下編譯含有 sprintf 的原始碼時,常常收到 C4996 警告,除了可以在原始碼中使用 #pragma 關閉,也可以透過編譯選項搞定。在 CMakeLists.txt 設定編譯選項的方式如下:
if(MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4996") endif()
連結選項:
CMAKE_EXE_LINKER_FLAGS 變數決定了連結執行檔時傳給編譯器的選項,同樣也有各種不同編譯組態的變形。下例為加入靜態連結:
if(MINGW) set(CMAKE_EXE_LINKER_FLAGS "-static") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s") endif()
上例的各種組態都採用 -static 來連結可執行檔,並且只有在 Release 情況下另外加入 -s 連結選項,亦即 Release 的連結選項為 -static -s
Preprocessor:
add_definitions("-DFOO -DBAR")
以下兩個指令分別用來加入編譯器尋找標頭檔、程式庫的路徑,在 gcc 相當於 -I 和 -L 選項。
include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...) link_directories(dir1 dir2 ...)
以上介紹的變數和指令都是屬於全域範圍的設定,如果希望選項僅對一個 target 有效,就必須從 target 的屬性(properties)下手。
在 CMake 裡一個 target 最終的輸出檔名、編譯連結選項等等都是由屬性控制,若沒有手動設定這些屬性,則 CMake 會由相關的全域變數來決定屬性值。我們可以利用 set_target_properties() 指令單獨指定一個 target 的屬性,如此一來就可以蓋過全域變數的設定。
set_target_properties() 指令格式如下:
set_target_properties(target1 target2 ... PROPERTIES 屬性名稱1 值 屬性名稱2 值 ... )
例如下例,這些屬性會蓋過原先全域變數的設定,而且僅作用在 app 這個 target 上:
set_target_properties(app PROPERTIES LINK_FLAGS -static LINK_FLAGS_RELEASE -s )
注意事項:
1. 小心覆寫變數
像 CMAKE_C_FLAGS_RELEASE、CMAKE_C_FLAGS_DEBUG 這些變數,CMake 會自動依照 Generator 指定的編譯器初始化。例如在 gcc 下 CMAKE_C_FLAGS_RELEASE 預設的值為 -O3 -DNDEBUG,而 CMAKE_C_FLAGS_DEBUG 預設值為 -g。
小心下面這種寫法:
set(CMAKE_C_FLAGS_RELEASE "-fno-inline")
原意可能是希望在做最佳化時忽略 inline 關鍵字,但是這樣一來其實會把原本的 -O3 -DNDEBUG 給覆寫掉,所以程式並不會做任何最佳化。
比較好的寫法應該是:
原意可能是希望在做最佳化時忽略 inline 關鍵字,但是這樣一來其實會把原本的 -O3 -DNDEBUG 給覆寫掉,所以程式並不會做任何最佳化。
比較好的寫法應該是:
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fno-inline")
2.注意字串和串列的不同
set(CMAKE_EXE_LINKER_FLAGS "-static") # ... (1) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") # ... (2) set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-s")
(1) 會傳遞 -static -s 給編譯器 (2) 會傳遞 -static;-s 給編譯器
實際應用的範例:
設定g++為編譯器,並build release的版本:
cmake_minimum_required (VERSION 2.6)
project (Test)
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS_DEBUG "-g3")
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
if(${CMAKE_BUILD_TYPE} MATCHES "debug")
message("debug version")
else()
message("release version")
endif()
include_directories(lib/include)
set(TEST_SOURCES src/main.cxx)
set(LIB_SOURCES lib/lib.cxx)
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
add_library(MyLib ${LIB_SOURCES})
add_executable(TestRun ${TEST_SOURCES})
target_link_libraries(TestRun MyLib)
CMake筆記(4) - 運算子
邏輯運算:
數值比較:
字串比較:
字串比較依照 字母順序決定大小。 LESS、GREATER、EQUAL、STRLESS、
STRGREATER、STREQUAL 會分別檢查左右運算元是否為已定義過的變數,若是則採用變數值,否則視為字串。這點在比較中通用,只要不是變數,就視為字串。
Regular Expression 比對:
檔案相關:
只支援絕對路徑
其它:
當 expr 值為 FALSE 時成立。 if(NOT <expr> ) 當 expr1 和 expr2 同時為 TRUE 時成立。 if(<expr1> AND <expr2> ) 當 expr1 和 expr2 至少其中之一為 TRUE 時成立。 if(<expr1> OR <expr2> )
數值比較:
if(variable LESS number) if(string LESS number) if(variable GREATER number) if(string GREATER number) if(variable EQUAL number) if(string EQUAL number)
字串比較:
if(variable STRLESS string) if(string STRLESS string) if(variable STRGREATER string) if(string STRGREATER string) if(variable STREQUAL string) if(string STREQUAL string)
字串比較依照 字母順序決定大小。 LESS、GREATER、EQUAL、STRLESS、
STRGREATER、STREQUAL 會分別檢查左右運算元是否為已定義過的變數,若是則採用變數值,否則視為字串。這點在比較中通用,只要不是變數,就視為字串。
Regular Expression 比對:
if(EXISTS file-name) if(EXISTS directory-name)
檔案相關:
只支援絕對路徑
判斷檔案和資料夾是否存在。 if(EXISTS file-name) if(EXISTS directory-name) 當 file1 比 file2 新,或者其中一個檔案不存在時。 if(file1 IS_NEWER_THAN file2) 判斷給定的path是否是絕對路徑。 if(IS_ABSOLUTE path)
其它:
判斷給定的 command-name 是否屬於指令、function、macro。 if(COMMAND command-name) 判斷給定的 variable-name 是否已經被定義過。 if(DEFINED variable-name)
2016年10月21日 星期五
CMake筆記(5) - 將建置資訊分類
CMake的build有2種:
In-source build:build的資料夾和source code在同一個資料夾,不推薦
out-of-source build:build的資料夾和source code在不同個資料夾,推薦,source code裡不會有cmake產生的cache,可單獨打包發佈。
注意事項: 在執行 Out-of-source build 之前必須先確定所指定的源碼根目錄是否乾淨,若是該目錄下含有前次留下的 CMakeCache.txt 仍會執行 In-source build。
開始前我們先清除之前CMake產生的cache,而因為CMake似乎沒有相關命令清除cache,我們自已寫一個簡單的script來清除:
out-of-source build:
我們將資料夾整理一下:
src:放source code
lib:放library的source code
lib/include:放library的header file
bin:放build 好的執行檔
build:放build好的lib檔
Project資料夾:放CMake產生 的cache
CMakeLists.txt:
路徑資訊:
In-source build:build的資料夾和source code在同一個資料夾,不推薦
out-of-source build:build的資料夾和source code在不同個資料夾,推薦,source code裡不會有cmake產生的cache,可單獨打包發佈。
注意事項: 在執行 Out-of-source build 之前必須先確定所指定的源碼根目錄是否乾淨,若是該目錄下含有前次留下的 CMakeCache.txt 仍會執行 In-source build。
開始前我們先清除之前CMake產生的cache,而因為CMake似乎沒有相關命令清除cache,我們自已寫一個簡單的script來清除:
#!/bin/bash # usage: bash clean_cmake_cache.sh echo "remove cmake cache...." if [ -f ./cmake_install.cmake ]; then rm ./cmake_install.cmake fi if [ -d ./CMakeFiles ]; then rm -r ./CMakeFiles fi if [ -f ./Makefile ]; then rm ./Makefile fi if [ -f ./CMakeCache.txt ]; then rm ./CMakeCache.txt fi
out-of-source build:
我們將資料夾整理一下:
src:放source code
lib:放library的source code
lib/include:放library的header file
bin:放build 好的執行檔
build:放build好的lib檔
Project資料夾:放CMake產生 的cache
CMakeLists.txt:
cmake_minimum_required (VERSION 2.6) project (Test) include_directories(lib/include) set(TEST_SOURCES src/main.cxx) set(LIB_SOURCES lib/lib.cxx) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) add_library(MyLib ${LIB_SOURCES}) add_executable(TestRun ${TEST_SOURCES}) target_link_libraries(TestRun MyLib)
路徑資訊:
CMake 提供了幾個變數讓使用者在撰寫 CMakeLists 時取得路徑資訊。
- CMAKE_SOURCE_DIR
- 內容為 source tree 根目錄的完整路徑,也就是 CMake 開始建置過程的進入點。
- CMAKE_BINARY_DIR
- 內容為 binary tree 根目錄的完整路徑,在 in-source build 的時候值與 CMAKE_SOURCE_DIR 相同。
- PROJECT_SOURCE_DIR
- 目前所屬專案的原始碼根目錄,即內含 project() 指令的 CMakeLists 所在資料夾。前面的例子沒有階層之分,所以 PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 相同;更複雜的專案會包含數個子專案,子專案下面還可能會有多個資料夾,PROJECT_SOURCE_DIR 內容為目前正在處理中的專案最上層目錄。
- PROJECT_BINARY_DIR
- 目前所屬專案的建置根目錄,專案意義同上。在 in-source build 時和 PROJECT_SOURCE_DIR 相同。
- CMAKE_CURRENT_SOURCE_DIR
- 目前正在處理的 CMakeLists.txt 所在位置。
- CMAKE_CURRENT_BINARY_DIR
- 目前正在處理的 CMakeLists.txt 對應的建置資料夾位置。當然,在 in-source build 時和 CMAKE_CURRENT_SOURCE_DIR 相同。
這裡要注意的是,CMake 中都使用絕對路徑來表示檔案位置。
CMake筆記(3) - 流程控制
條件敘述:
else中的expr可不填,這樣比較不會有語意上的誤會,例如:
在條件式當中變數即使不加 ${},if 也會先嘗試解釋成變數。
迴圈:
CMake 的迴圈有兩種:
foreach ... endforeach
while ... endwhile
function ... endfunction
macro ... endmacro
主要的差別在於 function 會建立 local的變數,而 macro 則會影響 global 變數。
CMake的條件敘述為 if、elseif、else、endif。
# 當 expr 值為下列其中之一時,執行 command1: # ON, 1, YES, TRUE, Y # 當 expr 值為下列其中之一時,執行 command2: # OFF, 0, NO, FALSE, N, NOTFOUND, *-NOTFOUND, IGNORE if(expr) command1(arg) else(expr) command2(arg) endif(expr)
else中的expr可不填,這樣比較不會有語意上的誤會,例如:
if(WIN32) command1(arg) else(WIN32) command2(arg) endif(expr)以為WIN32為真時執行command2...
# 下面兩行意義相同 if (foo) if (${foo})實務上個人覺得還是加比較好,可從語法上就得知這個是變數,不會誤以為是個字串。
迴圈:
CMake 的迴圈有兩種:
foreach ... endforeach
while ... endwhile
set(V alpha beta gamma) message(${V}) foreach(i ${V}) message(${i}) endforeach()Output:
alphabetagamma alpha beta gamma函數與巨集: CMake 有兩種設計子程序的方式:
function ... endfunction
macro ... endmacro
主要的差別在於 function 會建立 local的變數,而 macro 則會影響 global 變數。
# 定義名為 print1 的 macro macro(print1 MESSAGE) set(k ${MESSAGE}) message(${MESSAGE}) endmacro(print1) # 定義名為 print2 的 function function(print2 MESSAGE) set(k ${MESSAGE}) message(${MESSAGE}) endfunction(print2) print1("from print1") print2("from print2") message("k=${k}") 輸出結果為 from print1 from print2 k="from print1"
CMake筆記(2) - 基本語法
CMake基本語法
基本觀念,command不分大小寫,但參數和變數是有分大小寫的。
輸出訊息
變數
使用set來設定變數值,使用${}符號來get 變數值
字串與串列
字串(string)是 CMake 當中的基本的資料型態,將字串用空白或分號分隔則表示串列
a 等於一個串列,內容為 alpha、beta、gamma 三個字串
b 等於一個字串,內容為 alpha beta gamma
c 等於一個字串,內容為以換行為分隔的 alpha beta gamma
跳脫字元Escapes
CMake 大致上相容 C 語言當中的 Escape Sequence,如 \t \n 等等。如欲表示 CMake 當中的特殊字元時也可用 \ 標記
上面程式碼輸出
布林值:
以下這些會被視為 TRUE:
基本觀念,command不分大小寫,但參數和變數是有分大小寫的。
輸出訊息
message(helloworld)
變數
使用set來設定變數值,使用${}符號來get 變數值
set(var hello) message(${var})
字串與串列
字串(string)是 CMake 當中的基本的資料型態,將字串用空白或分號分隔則表示串列
set(foo this is a list) set(foo this;is;a;list)在字串當中需要空白、換行、分號等字元時,可以使用 " " 將文字內容框住,如此就會被解釋成同一個字串
set(a alpha beta gamma) set(b "alpha beta gamma") set(c "alpha beta gamma" ) message("a = ${a}") message("b = ${b}") message("c = ${c}")
a 等於一個串列,內容為 alpha、beta、gamma 三個字串
b 等於一個字串,內容為 alpha beta gamma
c 等於一個字串,內容為以換行為分隔的 alpha beta gamma
跳脫字元Escapes
CMake 大致上相容 C 語言當中的 Escape Sequence,如 \t \n 等等。如欲表示 CMake 當中的特殊字元時也可用 \ 標記
set(bar "alpha beta gamma") message("\${bar}: ${bar}")
上面程式碼輸出
${bar}: alpha beta gamma
布林值:
在 CMake 當中有些字串被賦予了布林值的意義,大小寫差異會被忽略:
以下這些會被視為 FALSE:
- OFF
- FALSE
- N
- NO
- 0
- "" (空字串)
- 沒被指派值的變數
- NOTFOUND
- 任何結尾是 -NOTFOUND 的字串
以下這些會被視為 TRUE:
- ON
- TRUE
- Y
- YE
- YES
- 1
- 其他不歸類為 FALSE 的字串
數字計算:
CMake 當中並沒有提供直接的數學運算子,所有的符號組合最終都會形成字串或串列。數學計算必須透過 math 指令解釋:
math(EXPR var "1 + 2 * 3") message("var = ${var}")輸出結果為7
2016年10月20日 星期四
CMake筆記(1)
CMake
語法簡介
由指令(command)和註解所組成,所有的空白、換行、tab 都沒有特殊作用,僅為語彙元素的區隔。
#為註解用。
指令為指令名稱加上小括號,括號內可以有零或若干個參數,指令則依照出現在 CMakeLists 當中的順序執行。所有指令名稱大小寫都一視同仁,例如 Command、COMMAND 皆視為同一個指令。
首先新建一個CMakeLists.txt,並輸入下面內容:
第一行是檢查cmake version,第二行是project name ,主要作用的第三行,會產生makefile,之後下make來compiler main.cxx產生一個TestRun的執行檔。
新建main.cxx,並輸入下面內容:
在當前console下輸入cmake .,成功後再輸入make,如無錯誤的話,可看到TestRun的執行檔生成。
語法簡介
由指令(command)和註解所組成,所有的空白、換行、tab 都沒有特殊作用,僅為語彙元素的區隔。
#為註解用。
指令為指令名稱加上小括號,括號內可以有零或若干個參數,指令則依照出現在 CMakeLists 當中的順序執行。所有指令名稱大小寫都一視同仁,例如 Command、COMMAND 皆視為同一個指令。
在撰寫 CMakeLists 時可以使用變數(Variable)儲存資料,嚴格說起來 CMake 只有字串和串列兩種資料形態,數值和布林值本質上只是帶有特殊意義的字串。變數大小寫不同視為相異,內建的變數都必須要全大寫。
首先新建一個CMakeLists.txt,並輸入下面內容:
cmake_minimum_required (VERSION 2.6) project (CMake1) add_executable(TestRun main.cxx)
第一行是檢查cmake version,第二行是project name ,主要作用的第三行,會產生makefile,之後下make來compiler main.cxx產生一個TestRun的執行檔。
新建main.cxx,並輸入下面內容:
#includeint main(int argc, char **argv) { std::cout << "Hello, world!" << std::endl; return 0; }
在當前console下輸入cmake .,成功後再輸入make,如無錯誤的話,可看到TestRun的執行檔生成。
訂閱:
文章 (Atom)