CMAKE使用總結

參考文檔

CMake Practice.pdflinux

最簡單的例子

目錄結構

.
├── CMakeLists.txt
└── main.cpp

main.cpp

#include <iostream>
int main()
{
    std::cout <<"Hello World" << std::endl;
    return 0;
}

CMakeLists.txt

PROJECT (PRACTISE1)
SET(SRC_LIST main.cpp)
MESSAGE(STATUS "This is BINARY dir "${PRACTISE1_BINARY_DIR})
MESSAGE(STATUS "This is BINARY dir "${PROJECT_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${PRACTISE1_SOURCE_DIR})
MESSAGE(STATUS "This is SOURCE dir "${PROJECT_SOURCE_DIR})
ADD_EXECUTABLE(practise1 ${SRC_LIST})

在目錄執行cmake命令

$ cmake .

輸出

...
-- This is BINARY dir xxx/practise1
-- This is BINARY dir xxx/practise1
-- This is SOURCE dir xxx/practise1
-- This is SOURCE dir xxx/practise1
...

總結

  • CMAKE語法中的指令關鍵字不分大小寫,可是傳入的參數是分大小寫的, 若是傳入的參數是列表能夠用空格或者分號隔開, 參數也可使用雙引號傳入(處理帶有空格字符的參數的時候頗有用)。
  • PROJECT用來設置工程名字,能夠與後面ADD_EXECUTABLE中的目標文件名不同。
  • SET用來定義一個變量,若是定義的是列表能夠用空格或者分號隔開,定義的變量能夠在後面用${變量名}來進行取值。
  • MESSAGE用來打印日誌,分別有SEND_ERROR | STATUS | FATAL_ERROR三中類型,其中FATAL_ERROR會讓構建程序終止。
  • ADD_EXECUTABLE根據設置生成指定的可執行文件。
  • 默認變量${PROJECT_BINARY_DIR}指的是目標make文件的生成目錄。
  • 默認變量${PROJECT_SOURCE_DIR}指的是工程CMakeLists.txt所在目錄。
  • <工程名>_BINARY_DIR和<工程名>_SOURCE_DIR是 PROJECT 指令隱式定義的兩個變量, 等同於PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,通常推薦使用後面這兩個,由於工程名會變更。
  • cmake以後若是運行make命令會發現目標文件生成在${PROJECT_BINARY_DIR}
  • 清理使用 make clean

工程化組織

目錄結構

.
├── bin
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

根目錄下面的CMakeLists.txt

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin
ADD_EXECUTABLE(practise2 main.cpp)

src目錄下面的CMakeLists.txt

PROJECT(PRACTISE2)
MESSAGE(STATUS "PROJECT_BINARY_DIR= "${PROJECT_BINARY_DIR})
MESSAGE(STATUS "PROJECT_SOURCE_DIR= "${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src)

到build目錄下面進行cmake

$ cd build
$ cmake ..
$ make

輸出

-- PROJECT_BINARY_DIR= xxx/practise2/build
-- PROJECT_SOURCE_DIR= xxx/practise2

practise2最後生成在bin目錄中ios

總結

  • 運行cmake命令所在的目錄將是目標make文件的生成目錄,即${PROJECT_BINARY_DIR}。
  • ADD_SUBDIRECTORY指令第一個參數指的是須要添加的子目錄, 子目錄下面也因該有CMakeLists.txt, 第二個指make生成的最終文件存放目錄,實際執行時文件被保存到了${PROJECT_BINARY_DIR}/bin下 第三個參數EXCLUDE_FROM_ALL,用來將這個目錄排除
  • 經過改變變量EXECUTABLE_OUTPUT_PATH來修改可執行文件的生成目錄,通常是結合ADD_EXECUTABLE指令使用, LIBRARY_OUTPUT_PATH修改庫的生成目錄,通常是結合ADD_LIBRARY指令使用。

生成動態庫和靜態庫

基本指令

  • 生成庫文件
ADD_LIBRARY(庫名 SHARED 源文件列表)

把上面的ADD_EXECUTABLE修改成ADD_LIBRARY就能夠生成庫文件了, 第二個參數SHARED表示生成動態庫,STATIC表示生成靜態庫shell

  • 指定庫文件的生成目錄
SET(LIBRARY_OUTPUT_PATH <路徑>)
  • 修改輸出名字
ADD_LIBRARY(hello_static STATIC hello.c)
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")

本來會輸出 libhello_static.a,加上後面這個後,庫文件名變爲libhello.awindows

  • 設置動態庫的版本號
SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

VERSION 指代動態庫版本,SOVERSION 指代 API 版本。函數

  • 同時生成動態庫和靜態庫的CMakeLists.txt
SET(LIBHELLO_SRC hello.cpp)
SET(LIBRARY_OUTPUT_PATH lib)  #目標文件生成目錄設置爲lib
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello") #對目標文件重命名
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)  #不清理上個版本的生成文件
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1) #不清理上個版本的生成文件

make以後會同時生成兩個文件ui

├── lib
    │   ├── libhello.a
    │   └── libhello.so

windows下DLL生成說明

因爲windows調用dll通常是須要dll文件,帶有symbol的lib文件,以及函數聲明的頭文件,所以須要作額外的配置,CMAKE在動態庫編譯的以前會預約義一個宏 {庫名}_EXPORTS,判斷這個宏來決定dll中的函數是否是導出函數,有了導出函數vs纔會額外的生成lib文件。debug

如下代碼兼容windows和linux dynamic.h日誌

#ifndef __DYNAMIC_H_
#define __DYNAMIC_H_

#ifdef _WIN32
#ifdef dynamic_EXPORTS
#define __DLL_API __declspec(dllexport)
#else
#define __DLL_API __declspec(dllimport)
#endif
#endif //_WINDOWS

#ifdef  __linux__
#ifdef dynamic_EXPORTS
#define __DLL_API  __attribute__((visibility("default")))
#else
#define __DLL_API
#endif
#endif //__linux__

__DLL_API void fun_dynamic();

#endif

dynamic_EXPORTS這個宏是cmake自動根據庫名生成的,正好能夠用來做爲是導出函數的判斷code

dynamic.cppci

#include "dynamic.h"
#include <iostream>

__DLL_API void fun_dynamic()
{
	std::cout << "msg from dynamic" << std::endl;
}

引用外部頭文件和庫文件

指令語法

  • 引用外部頭文件
INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)

這條指令能夠用來向工程添加多個特定的頭文件搜索路徑,路徑之間用空格分割,若是路徑 中包含了空格,可使用雙引號將它括起來,默認的行爲是追加到當前的頭文件搜索路徑的 後面,你能夠經過兩種方式來進行控制搜索路徑添加的方式: 1,CMAKE_INCLUDE_DIRECTORIES_BEFORE,經過 SET 這個 cmake 變量爲 on,能夠 將添加的頭文件搜索路徑放在已有路徑的前面。 2,經過 AFTER 或者 BEFORE 參數,也能夠控制是追加仍是置前。

  • 連接庫文件

添加非標準的共享庫搜索路徑

LINK_DIRECTORIES(directory1 directory2 ...)

爲 target 添加須要連接的庫,target能夠是可執行文件,也能夠是庫文件

TARGET_LINK_LIBRARIES(target library1
                     <debug | optimized> library2
                     ...)

目錄結構

├── bin
├── build
├── CMakeLists.txt
├── libs
└── src
    ├── CMakeLists.txt
    ├── libdynamic
    │   ├── CMakeLists.txt
    │   ├── dynamic.cpp
    │   └── dynamic.h
    ├── libstatic
    │   ├── CMakeLists.txt
    │   ├── static.cpp
    │   └── static.h
    └── main
        ├── CMakeLists.txt
        └── main.cpp

本工程由一個可執行文件和一個靜態庫和一個動態庫構成,可執行文件調用了這兩個庫文件,可執行文件和動態庫最後生成在bin目錄下,靜態庫生成在libs目錄。

根目錄的 CMakeLists.txt

PROJECT(PRACTISE3)
MESSAGE(STATUS "PROJECT_BINARY_DIR= "${PROJECT_BINARY_DIR})
MESSAGE(STATUS "PROJECT_SOURCE_DIR= "${PROJECT_SOURCE_DIR})
ADD_SUBDIRECTORY(src)

src目錄的CMakeLists.txt

ADD_SUBDIRECTORY(libstatic)
ADD_SUBDIRECTORY(libdynamic)
ADD_SUBDIRECTORY(main)

動態庫的CMakeLists.txt

SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
ADD_LIBRARY(dynamic SHARED dynamic.cpp)

設定生成目錄爲根目錄下面的bin

靜態庫的CMakeLists.txt

SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/libs)
ADD_LIBRARY(static STATIC static.cpp)

設定生成目錄爲根目錄下面的libs

可執行文件的CMakeLists.txt

INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/libstatic ${PROJECT_SOURCE_DIR}/src/libdynamic)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
ADD_EXECUTABLE(practise3 main.cpp)
TARGET_LINK_LIBRARIES(practise3 static)
TARGET_LINK_LIBRARIES(practise3 dynamic)

設定了頭文件的查找目錄,並在最後指定了須要連接的動態庫和靜態庫,庫的名字應該與ADD_LIBRARY指令中使用的名字一致

make的輸出

Scanning dependencies of target static
[ 33%] Building CXX object src/libstatic/CMakeFiles/static.dir/static.o
Linking CXX static library ../../../libs/libstatic.a
[ 33%] Built target static
Scanning dependencies of target dynamic
[ 66%] Building CXX object src/libdynamic/CMakeFiles/dynamic.dir/dynamic.o
Linking CXX shared library ../../../bin/libdynamic.so
[ 66%] Built target dynamic
Scanning dependencies of target practise3
[100%] Building CXX object src/main/CMakeFiles/practise3.dir/main.o
Linking CXX executable ../../../bin/practise3
[100%] Built target practise3

自動根據各個項目的包含關係決定構建的順序

相關文章
相關標籤/搜索