基本元素
首先cmaklist必須包括以下幾個部分:
#工程名
project(study_case)
#cmake最低版本需求
cmake_minimum_required(VERSION 2.8.3)
#添加添加需要的庫
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "/usr/local/share/OpenCV")
find_package(OpenCV 3.2.0 REQUIRED)
#確定需要的頭文件
include_directories(
include
)
#確定編譯語言
#1
set(CMAKE_CXX_STANDARD 11)
#2. or
add_definitions(-std=c++11)
#設置二進制文件目錄
SET(BIN_DESTINATION ${PROJECT_SOURCE_DIR}/bin)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DESTINATION})
#如果多個文件相關,則添加源代碼(可選)
set(SRC
${PROJECT_SOURCE_DIR}/src/detector.cpp
${PROJECT_SOURCE_DIR}/src/demo.cpp
${PROJECT_SOURCE_DIR}/src/test.cpp
)
#如果需要編譯動態庫並鏈接庫文件(可選)
link_directories(${PROJECT_SOURCE_DIR})
add_library(overload SHARED ${SRC})
target_link_libraries(overload -llianghao -lpthread -lm -lstdc++)
#生成可執行文件
link_directories(${PROJECT_SOURCE_DIR})
#添加可執行文件
#1. 如果文件之間沒有關聯
add_executable(overload src/overload.cpp)
#2. or 如果多個文件相關
add_executable(overload src/overload.cpp ${SRC})
#如果有依賴外部庫則需要添加以下命令(可選)
target_link_libraries(overload -llianghao -lpthread -lm -lstdc++)
其他功能
1. 使其包含c++11特性(-std=c++11如何寫進cmakeList.txt)
#1
set(CMAKE_CXX_STANDARD 11)
#2. or
add_definitions(-std=c++11)
#3. or
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
2. 設定可執行文件的輸出目錄
SET(BIN_DESTINATION ${PROJECT_SOURCE_DIR}/bin)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${BIN_DESTINATION})
3. 生成so庫
3.1 想生成多個so庫
# 設置構建本地庫所需的最小版本的cbuild。
cmake_minimum_required(VERSION 3.4.1)
# 創建並命名一個庫,將其設置為靜態
# 或者共享,並提供其源代碼的相對路徑。
# 您可以定義多個庫,而cbuild為您構建它們。
# Gradle自動將共享庫與你的APK打包。
add_library( hello-lib #設置庫的名稱。即SO文件的名稱,生產的so文件為“libhello-lib.so”,在加載的時候“System.loadLibrary("hello-lib");”
SHARED # 將庫設置為共享庫。
src/main/jni/hello.cpp # 提供一個源文件的相對路徑
src/main/jni/helloJni.cpp # 提供同一個SO文件中的另一個源文件的相對路徑
)
#搜索指定的預構建庫,並將該路徑存儲為一個變量。因為cbuild默認包含了搜索路徑中的系統庫,所以您只需要指定您想要添加的公共NDK庫的名稱。cbuild在完成構建之前驗證這個庫是否存在。
find_library(log-lib # 設置path變量的名稱。
log # 指定NDK庫的名稱 你想讓CMake來定位。
)
#指定庫的庫應該鏈接到你的目標庫。您可以鏈接多個庫,比如在這個構建腳本中定義的庫、預構建的第三方庫或系統庫。
target_link_libraries( hello-lib #指定目標庫中。與 add_library的庫名稱一定要相同
${log-lib} # 將目標庫鏈接到日志庫包含在NDK。
)
#如果需要生產多個SO文件的話,寫法如下
add_library( natave-lib #設置庫的名稱。另一個so文件的名稱
SHARED # 將庫設置為共享庫。
src/main/jni/nataveJni.cpp # 提供一個源文件的相對路徑
)
target_link_libraries( natave-lib #指定目標庫中。與 add_library的庫名稱一定要相同
${log-lib} # 將目標庫鏈接到日志庫包含在NDK。
)
這里還有一個坑在里面,就是如果你的庫的名字起得不是叫xx-lib的話,編譯是通不過的,親測,比如起個so庫名叫test,cpp文件叫做test.cpp,這樣是編譯不過的,不會生成多個so庫。
3.1 生成一個so庫,多個cpp文件
# 查找cpp目錄下的所有源文件
# 並將名稱保存到 DIR_LIB_SRCS 變量
aux_source_directory(src/main/cpp/ DIR_LIB_SRCS)
# 生成鏈接庫
add_library (native-lib SHARED ${DIR_LIB_SRCS})
# 導入cpp目錄下的所有頭文件
include_directories(src/main/cpp/)
替換原有的add_library命令就可以了,其實就是生成一個變量,指定cpp的文件路徑
4. 設置編譯類型
#set release
if (NOT CMAKE_BUILD_TYPE)
message("not defined Build Type:auto define it to Debug" )
set (CMAKE_BUILD_TYPE Debug)
endif (NOT CMAKE_BUILD_TYPE)
if (CMAKE_BUILD_TYPE MATCHES "Debug" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
elseif (CMAKE_BUILD_TYPE MATCHES "Release" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 ")
elseif (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O2 ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O2 ")
else()
message("unkown defined Build Type:same handle with Debug" )
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
endif (CMAKE_BUILD_TYPE MATCHES "Debug")
5. 外部庫FIND_PACKAGE
格式:
FIND_PACKAGE(<name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )
5.1 查找*.cmake的順序
1、 find_package(<Name>)命令首先會在模塊路徑中尋找Find<name>.cmake
這是查找庫的一個典型方式,具體查找路徑依次為CMake:
變量${CMAKE_MODULE_PATH}中的所有目錄。
如果沒有, 然后再查看它自己的模塊目錄: /share/cmake-x.y/Modules/ 。
這稱為模塊模式。
2、如果沒找到這樣的文件:
find_package()會在:
~/.cmake/packages/
或/usr/local/share/
中的各個包目錄中查找,尋找:
<庫名字的大寫>Config.cmake
或 <庫名字的小寫>-config.cmake
(比如庫Opencv,它會查找/usr/local/share/OpenCV中的OpenCVConfig.cmake或opencv-config.cmake)。**這稱為配置模式。
不管使用哪一種模式,只要找到.cmake,.cmake里面都會定義下面這些變量:
例子<NAME>: OpenCVConfig.cmake
<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS
注意大部分包的這些變量中的包名是全大寫的,如 LIBFOO_FOUND ,有些包則使用包的實際大小寫,如 LibFoo_FOUND
如果找到這個包,則可以通過在工程的頂層目錄中的CMakeLists.txt 文件添加 include_directories(_INCLUDE_DIRS) 來包含庫的頭文件,添加target_link_libraries(源文件 _LIBRARIES)命令將源文件與庫文件鏈接起來。
5.2 使用外部庫的方式
為了能支持各種常見的庫和包,CMake自帶了很多模塊。可以通過命令cmake --help-module-list得到你的CMake支持的模塊的列表,或者直接查看模塊路徑。比如Ubuntu上,模塊的路徑是:
/usr/share/cmake/Modules/
讓我們以bzip2庫為例。CMake中有個FindBZip2.cmake 模塊。只要使用 find_package(BZip2) 調用這個模塊,cmake會自動給一些變量賦值,然后就可以在CMakelists.txt中使用它們了。變量的列表可以查看cmake模塊文件,或者使用命令 cmake –help-module FindBZip2 。
比如一個使用bzip2的簡單程序,編譯器需要知道 bzlib.h 的位置,鏈接器需要找到bzip2庫(動態鏈接的話,Unix上是 libbz2.so 類似的文件,Windows上是 libbz2.dll )。
cmake_minimum_required(VERSION 2.8)
project(helloworld)
add_executable(helloworld hello.c)
find_package(BZip2)
if (BZIP2_FOUND)
include_directories(${BZIP_INCLUDE_DIRS})
target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)
5.3 find_package中的參數定義
FIND_PACKAGE(<name> [version] [EXACT] [QUIET] [[REQUIRED|COMPONENTS] [ componets... ] ] )
1 version參數
需要一個版本號,它是正在查找的包應該兼容的版本號。
eg:
find_package(Boost ${boost_version})
2 EXACT選項
要求版本號必須精確匹配。如果在find-module內部對該命令的遞歸調用沒有給定[version]參數,那么[version]和EXACT選項會自動地從外部調用前向繼承。對版本的支持目前只存在於包和包之間。
eg:
find_package(Boost ${boost_version} EXACT REQUIRED)
3 QUIET 參數:
會禁掉包沒有被發現時的警告信息。對應於Find.cmake模塊中的 NAME_FIND_QUIETLY。
eg:
find_package(Boost ${boost_version} EXACT QUIET)
4 REQUIRED 參數
其含義是指是工程必須的,表示如果報沒有找到的話,cmake的過程會終止,並輸出警告信息。對應於Find.cmake模塊中的 NAME_FIND_REQUIRED 變量。
eg:
find_package(Boost REQUIRED COMPONENTS system)
COMPONENTS參數
在REQUIRED選項之后,或者如果沒有指定REQUIRED選項但是指定了COMPONENTS選項,在它們的后面可以列出一些與包相關(依賴)的部件清單(components list)
eg:
find_package(Boost REQUIRED COMPONENTS system)
6. 其他
cmake中一些預定義變量
- PROJECT_SOURCE_DIR 工程的根目錄
- PROJECT_BINARY_DIR 運行cmake命令的目錄,通常是${PROJECT_SOURCE_DIR}/build
- CMAKE_INCLUDE_PATH 環境變量,非cmake變量
- CMAKE_LIBRARY_PATH 環境變量
- CMAKE_CURRENT_SOURCE_DIR 當前處理的CMakeLists.txt所在的路徑
- CMAKE_CURRENT_BINARY_DIR target編譯目錄
- 使用ADD_SURDIRECTORY(src bin)可以更改此變量的值
- SET(EXECUTABLE_OUTPUT_PATH <新路徑>)並不會對此變量有影響,只是改變了最終目標文件的存儲路徑
- CMAKE_CURRENT_LIST_FILE 輸出調用這個變量的CMakeLists.txt的完整路徑
- CMAKE_CURRENT_LIST_LINE 輸出這個變量所在的行
- CMAKE_MODULE_PATH 定義自己的cmake模塊所在的路徑
- SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令來調用自己的模塊
- EXECUTABLE_OUTPUT_PATH 重新定義目標二進制可執行文件的存放位置
- LIBRARY_OUTPUT_PATH 重新定義目標鏈接庫文件的存放位置
- PROJECT_NAME 返回通過PROJECT指令定義的項目名稱
- CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS 用來控制IF ELSE語句的書寫方式
系統信息
- CMAKE_MAJOR_VERSION cmake主版本號,如2.8.6中的2
- CMAKE_MINOR_VERSION cmake次版本號,如2.8.6中的8
- CMAKE_PATCH_VERSION cmake補丁等級,如2.8.6中的6
- CMAKE_SYSTEM 系統名稱,例如Linux-2.6.22
- CAMKE_SYSTEM_NAME 不包含版本的系統名,如Linux
- CMAKE_SYSTEM_VERSION 系統版本,如2.6.22
- CMAKE_SYSTEM_PROCESSOR 處理器名稱,如i686
- UNIX 在所有的類UNIX平台為TRUE,包括OS X和cygwin
- WIN32 在所有的win32平台為TRUE,包括cygwin
開關選項
- BUILD_SHARED_LIBS 控制默認的庫編譯方式。如果未進行設置,使用ADD_LIBRARY時又沒有指定庫類型,默認編譯生成的庫都是靜態庫 (可在t3中稍加修改進行驗證)
- CMAKE_C_FLAGS 設置C編譯選項
- CMAKE_CXX_FLAGS 設置C++編譯選項
運行
cmake .
make