CMakeLists.txt語法規則匯總


//聲明要求的cmake最低版本,終端輸入cmake -version可查看cmake的版本
cmake_minimum_required( VERSION 2.8 )

//聲明cmake工程名字
project(slam)

//設置使用g++編譯器,這是添加變量的用法set(KEY VALUE)接收兩個參數,用來聲明變量。在camke語法中使用${KEY}這種寫法來取到VALUE
set( CMAKE_CXX_COMPILER "g++")

//設置cmake編譯模式有debug和release兩種PROJECT_SOURCE_DIR項目根目錄也就是是CmakeLists.txt的絕對路徑
set( CMAKE_BUILD_TYPE "Release" )

//設定生成的可執行二進制文件存放的存放目錄
set( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

//設定生成的庫文件的存放目錄
set( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

//參數CMAKE_CXX_FLAGS含義是: set compiler for c++ language
//添加c++11標准支持,*.CPP文件編譯選項,-march=native指定目標程序的cpu架構來進行程序優化
//native就是相當於自檢測cpu,-march是gcc優化選項,后面的-O3是用來調節編譯時的優化程度的,最高為-O3,最低為-O0即不做優化
//-Ox這個參數只有在CMake -DCMAKE_BUILD_TYPE=release時有效
//因為debug版的項目生成的可執行文件需要有調試信息並且不需要進行優化,而release版的不需要調試信息但需要優化
set( CMAKE_CXX_FLAGS “-std=c++11 -march=native -O3”)

//調試手段message打印信息,類似於echo/printf,主要用於查cmake文件的語法錯誤
set(use_test ${SOURCES_DIRECTORY}/user_accounts.cpp)
message("use_test : ${use_test}")

//在CMakeLists.txt中指定安裝位置, 在編譯終端指定安裝位置:cmake -DCMAKE_INSTALL_PREFIX=/usr ..
set(CMAKE_INSTALL_PREFIX < install_path >)

//增加子文件夾,也就是進入源代碼文件夾繼續構建
add_subdirectory(${PROJECT_SOURCE_DIR}/src)

//添加依賴,去尋找該庫的頭文件位置、庫文件位置以及庫文件名稱,並將其設為變量,返回提供給CMakeLists.txt其他部分使用。
//cmake_modules.cmake文件是把CMakeLists.txt里用來尋找特定庫的內容分離出來,如果提示沒有找到第三方依賴庫可以嘗試安裝或者暴力指定路徑
// 尋找OpenCV庫
find_package( OpenCV REQUIRED )

//在CMakeLists.txt中使用第三方庫的三部曲:find_package、include_directories、target_link_libraries
include_directories(${OpenCV_INCLUDE_DIRS})// 去哪里找頭文件
link_directories()// 去哪里找庫文件(.so/.lib/.ddl等)
target_link_libraries( ${OpenCV_LIBRARIES})// 需要鏈接的庫文件
message("OpenCV_INCLUDE_DIRS: \n" ${OpenCV_INCLUDE_DIRS})
message("OpenCV_LIBS: \n" ${OpenCV_LIBS})

// find_package(Eigen3 REQUIRED), 假如找不到Eigen3庫,我們就設置變量來指定Eigen3的頭文件位置
set(Eigen3_DIR /usr/lib/cmake/eigen3/Eigen3Config.cmake)
include_directories(/usr/local/include/eigen3)

CMake

說明

cmake的定義是什么 ?-----高級編譯配置工具

當多個人用不同的語言或者編譯器開發一個項目,最終要輸出一個可執行文件或者共享庫(dll,so等等)這時候神器就出現了-----CMake!

所有操作都是通過編譯CMakeLists.txt來完成的—簡單

官 方網站是 www.cmake.org,可以通過訪問官方網站獲得更多關於 cmake 的信息

學習CMake的目的,為將來處理大型的C/C++/JAVA項目做准備

CMake安裝

1、絕大多數的linux系統已經安裝了CMake

2、Windows或某些沒有安裝過的linux系統,去http://www.cmake.org/HTML/Download.html 可以下載安裝

CMake一個HelloWord

1、步驟一,寫一個HelloWord

#main.cpp

#include <iostream>

int main(){
std::cout <<  "hello word" << std::endl;
}

2、步驟二,寫CMakeLists.txt

#CMakeLists.txt

PROJECT (HELLO)

SET(SRC_LIST main.cpp)

MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})

MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})

ADD_EXECUTABLE(hello ${SRC_LIST})

3、步驟三、使用cmake,生成makefile文件

cmake .

輸出:
[root@localhost cmake]# cmake .
CMake Warning (dev) in CMakeLists.txt:
  Syntax Warning in cmake code at

    /root/cmake/CMakeLists.txt:7:37

  Argument not separated from preceding token by whitespace.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- The C compiler identification is GNU 10.2.1
-- The CXX compiler identification is GNU 10.2.1
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- This is BINARY dir /root/cmake
-- This is SOURCE dir /root/cmake
-- Configuring done
-- Generating done
-- Build files have been written to: /root/cmake

目錄下就生成了這些文件-CMakeFiles, CMakeCache.txt, cmake_install.cmake 等文件,並且生成了Makefile.
現在不需要理會這些文件的作用,以后你也可以不去理會。最關鍵的是,它自動生成了Makefile.

4、使用make命令編譯

root@localhost cmake]# make
Scanning dependencies of target hello
[100%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
Linking CXX executable hello
[100%] Built target hello

5、最終生成了Hello的可執行程序

CMake一個HelloWord-的語法介紹

PROJECT關鍵字

可以用來指定工程的名字和支持的語言,默認支持所有語言

PROJECT (HELLO) 指定了工程的名字,並且支持所有語言—建議

PROJECT (HELLO CXX) 指定了工程的名字,並且支持語言是C++

PROJECT (HELLO C CXX) 指定了工程的名字,並且支持語言是C和C++

該指定隱式定義了兩個CMAKE的變量

_BINARY_DIR,本例中是 HELLO_BINARY_DIR

_SOURCE_DIR,本例中是 HELLO_SOURCE_DIR

MESSAGE關鍵字就可以直接使用者兩個變量,當前都指向當前的工作目錄,后面會講外部編譯

問題:如果改了工程名,這兩個變量名也會改變

解決:又定義兩個預定義變量:PROJECT_BINARY_DIR和PROJECT_SOURCE_DIR,這兩個變量和HELLO_BINARY_DIR,HELLO_SOURCE_DIR是一致的。所以改了工程名也沒有關系

SET關鍵字

用來顯示的指定變量的

SET(SRC_LIST main.cpp) SRC_LIST變量就包含了main.cpp

也可以 SET(SRC_LIST main.cpp t1.cpp t2.cpp)

MESSAGE關鍵字

向終端輸出用戶自定義的信息

主要包含三種信息:

  • SEND_ERROR,產生錯誤,生成過程被跳過。
  • SATUS,輸出前綴為—的信息。
  • FATAL_ERROR,立即終止所有 cmake 過程.

ADD_EXECUTABLE關鍵字

生成可執行文件

ADD_EXECUTABLE(hello ${SRC_LIST}) 生成的可執行文件名是hello,源文件讀取變量SRC_LIST中的內容

也可以直接寫 ADD_EXECUTABLE(hello main.cpp)

上述例子可以簡化的寫成

PROJECT(HELLO)
ADD_EXECUTABLE(hello main.cpp)

注意:工程名的 HELLO 和生成的可執行文件 hello 是沒有任何關系的

語法的基本原則

  • 變量使用${}方式取值,但是在 IF 控制語句中是直接使用變量名

  • 指令(參數 1 參數 2...) 參數使用括弧括起,參數之間使用空格或分號分開。 以上面的 ADD_EXECUTABLE 指令為例,如果存在另外一個 func.cpp 源文件

    就要寫成:ADD_EXECUTABLE(hello main.cpp func.cpp)或者ADD_EXECUTABLE(hello main.cpp;func.cpp)

  • 指令是大小寫無關的,參數和變量是大小寫相關的。但,推薦你全部使用大寫指令

語法注意事項

  • SET(SRC_LIST main.cpp) 可以寫成 SET(SRC_LIST “main.cpp”),如果源文件名中含有空格,就必須要加雙引號
  • ADD_EXECUTABLE(hello main) 后綴可以不行,他會自動去找.c和.cpp,最好不要這樣寫,可能會有這兩個文件main.cpp和main

內部構建和外部構建

  • 上述例子就是內部構建,他生產的臨時文件特別多,不方便清理
  • 外部構建,就會把生成的臨時文件放在build目錄下,不會對源文件有任何影響強烈使用外部構建方式

外部構建方式舉例

//例子目錄,CMakeLists.txt和上面例子一致
[root@localhost cmake]# pwd
/root/cmake
[root@localhost cmake]# ll
total 8
-rw-r--r--. 1 root root 198 Dec 28 20:59 CMakeLists.txt
-rw-r--r--. 1 root root  76 Dec 28 00:18 main.cpp

1、建立一個build目錄,可以在任何地方,建議在當前目錄下

2、進入build,運行cmake .. 當然..表示上一級目錄,你可以寫CMakeLists.txt所在的絕對路徑,生產的文件都在build目錄下了

3、在build目錄下,運行make來構建工程

注意外部構建的兩個變量

1、HELLO_SOURCE_DIR 還是工程路徑

2、HELLO_BINARY_DIR 編譯路徑 也就是 /root/cmake/bulid

讓Hello World看起來更像一個工程

  • 為工程添加一個子目錄 src,用來放置工程源代碼
  • 添加一個子目錄 doc,用來放置這個工程的文檔 hello.txt
  • 在工程目錄添加文本文件 COPYRIGHT, README
  • 在工程目錄添加一個 runhello.sh 腳本,用來調用 hello 二進制
  • 將構建后的目標文件放入構建目錄的 bin 子目錄
  • 將 doc 目錄 的內容以及 COPYRIGHT/README 安裝到/usr/share/doc/cmake/

將目標文件放入構建目錄的 bin 子目錄

每個目錄下都要有一個CMakeLists.txt說明

[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

外層CMakeLists.txt

PROJECT(HELLO)
ADD_SUBDIRECTORY(src bin)

src下的CMakeLists.txt

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY 指令

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

  • 這個指令用於向當前工程添加存放源文件的子目錄,並可以指定中間二進制和目標二進制存放的位置

  • EXCLUDE_FROM_ALL函數是將寫的目錄從編譯中排除,如程序中的example

  • ADD_SUBDIRECTORY(src bin)

    將 src 子目錄加入工程並指定編譯輸出(包含編譯中間結果)路徑為bin 目錄

    如果不進行 bin 目錄的指定,那么編譯結果(包括中間結果)都將存放在build/src 目錄

更改二進制的保存路徑

SET 指令重新定義 EXECUTABLE_OUTPUT_PATH 和 LIBRARY_OUTPUT_PATH 變量 來指定最終的目標二進制的位置

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)

思考:加載哪個CMakeLists.txt當中

哪里要改變目標存放路徑,就在哪里加入上述的定義,所以應該在src下的CMakeLists.txt下寫

安裝

  • 一種是從代碼編譯后直接 make install 安裝
  • 一種是打包時的指定 目錄安裝。
    • 簡單的可以這樣指定目錄:make install DESTDIR=/tmp/test
    • 稍微復雜一點可以這樣指定目錄:./configure –prefix=/usr

如何安裝HelloWord

使用CMAKE一個新的指令:INSTALL

INSTALL的安裝可以包括:二進制、動態庫、靜態庫以及文件、目錄、腳本等

使用CMAKE一個新的變量:CMAKE_INSTALL_PREFIX

// 目錄樹結構
[root@localhost cmake]# tree
.
├── build
├── CMakeLists.txt
├── COPYRIGHT
├── doc
│   └── hello.txt
├── README
├── runhello.sh
└── src
    ├── CMakeLists.txt
    └── main.cpp

3 directories, 7 files

安裝文件COPYRIGHT和README

INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)

FILES:文件

DESTINATION:

1、寫絕對路徑

2、可以寫相對路徑,相對路徑實際路徑是:${CMAKE_INSTALL_PREFIX}/<DESTINATION 定義的路徑>

CMAKE_INSTALL_PREFIX 默認是在 /usr/local/

cmake -DCMAKE_INSTALL_PREFIX=/usr 在cmake的時候指定CMAKE_INSTALL_PREFIX變量的路徑

安裝腳本runhello.sh

PROGRAMS:非目標文件的可執行程序安裝(比如腳本之類)

INSTALL(PROGRAMS runhello.sh DESTINATION bin)

說明:實際安裝到的是 /usr/bin

安裝 doc 中的 hello.txt

  • 一、是通過在 doc 目錄建立CMakeLists.txt ,通過install下的file

  • 二、是直接在工程目錄通過

    INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)

DIRECTORY 后面連接的是所在 Source 目錄的相對路徑

注意:abc 和 abc/有很大的區別

目錄名不以/結尾:這個目錄將被安裝為目標路徑下的

目錄名以/結尾:將這個目錄中的內容安裝到目標路徑

安裝過程

cmake ..

make

make install

靜態庫和動態庫的構建

任務:

1,建立一個靜態庫和動態庫,提供 HelloFunc 函數供其他程序編程使用,HelloFunc 向終端輸出 Hello World 字符串。

2,安裝頭文件與共享庫。

靜態庫和動態庫的區別

  • 靜態庫的擴展名一般為“.a”或“.lib”;動態庫的擴展名一般為“.so”或“.dll”。
  • 靜態庫在編譯時會直接整合到目標程序中,編譯成功的可執行文件可獨立運行
  • 動態庫在編譯時不會放到連接的目標程序中,即可執行文件無法單獨運行。

構建實例

[root@localhost cmake2]# tree
.
├── build
├── CMakeLists.txt
└── lib
    ├── CMakeLists.txt
    ├── hello.cpp
    └── hello.h

hello.h中的內容

#ifndef HELLO_H
#define Hello_H

void HelloFunc();

#endif

hello.cpp中的內容

#include "hello.h"
#include <iostream>
void HelloFunc(){
    std::cout << "Hello World" << std::endl;
}

項目中的cmake內容

PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

lib中CMakeLists.txt中的內容

SET(LIBHELLO_SRC hello.cpp)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

ADD_LIBRARY

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

  • hello:就是正常的庫名,生成的名字前面會加上lib,最終產生的文件是libhello.so
  • SHARED,動態庫 STATIC,靜態庫
  • ${LIBHELLO_SRC} :源文件

同時構建靜態和動態庫

// 如果用這種方式,只會構建一個動態庫,不會構建出靜態庫,雖然靜態庫的后綴是.a
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello STATIC ${LIBHELLO_SRC})

// 修改靜態庫的名字,這樣是可以的,但是我們往往希望他們的名字是相同的,只是后綴不同而已
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

SET_TARGET_PROPERTIES

這條指令可以用來設置輸出的名稱,對於動態庫,還可以用來指定動態庫版本和 API 版本

同時構建靜態和動態庫

SET(LIBHELLO_SRC hello.cpp)

ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})

//對hello_static的重名為hello
SET_TARGET_PROPERTIES(hello_static PROPERTIES  OUTPUT_NAME "hello")
//cmake 在構建一個新的target 時,會嘗試清理掉其他使用這個名字的庫,因為,在構建 libhello.so 時, 就會清理掉 libhello.a
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

SET_TARGET_PROPERTIES(hello PROPERTIES  OUTPUT_NAME "hello")
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

動態庫的版本號

一般動態庫都有一個版本號的關聯

libhello.so.1.2
libhello.so ->libhello.so.1
libhello.so.1->libhello.so.1.2

CMakeLists.txt 插入如下

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

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

安裝共享庫和頭文件

本例中我們將 hello 的共享庫安裝到 /lib目錄,

將 hello.h 安裝到 /include/hello 目錄

//文件放到該目錄下
INSTALL(FILES hello.h DESTINATION include/hello)

//二進制,靜態庫,動態庫安裝都用TARGETS
//ARCHIVE 特指靜態庫,LIBRARY 特指動態庫,RUNTIME 特指可執行目標二進制。
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

注意:

安裝的時候,指定一下路徑,放到系統下

cmake -DCMAKE_INSTALL_PREFIX=/usr ..

使用外部共享庫和頭文件

准備工作,新建一個目錄來使用外部共享庫和頭文件

[root@MiWiFi-R4CM-srv cmake3]# tree
.
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    └── main.cpp

main.cpp

#include <hello.h>

int main(){
	HelloFunc();
}

解決:make后頭文件找不到的問題

PS:include <hello/hello.h> 這樣include是可以,這么做的話,就沒啥好講的了

關鍵字:INCLUDE_DIRECTORIES 這條指令可以用來向工程添加多個特定的頭文件搜索路徑,路徑之間用空格分割

在CMakeLists.txt中加入頭文件搜索路徑

INCLUDE_DIRECTORIES(/usr/include/hello)

感謝:

網友:zcc720的提醒

解決:找到引用的函數問題

報錯信息:undefined reference to `HelloFunc()'

關鍵字:LINK_DIRECTORIES 添加非標准的共享庫搜索路徑

指定第三方庫所在路徑,LINK_DIRECTORIES(/home/myproject/libs)

關鍵字:TARGET_LINK_LIBRARIES 添加需要鏈接的共享庫

TARGET_LINK_LIBRARIES的時候,只需要給出動態鏈接庫的名字就行了。

在CMakeLists.txt中插入鏈接共享庫,主要要插在executable的后面

查看main的鏈接情況

[root@MiWiFi-R4CM-srv bin]# ldd main 
	linux-vdso.so.1 =>  (0x00007ffedfda4000)
	libhello.so => /lib64/libhello.so (0x00007f41c0d8f000)
	libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f41c0874000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f41c0572000)
	libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f41c035c000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f41bff8e000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f41c0b7c000)

鏈接靜態庫

TARGET_LINK_LIBRARIES(main libhello.a)

特殊的環境變量 CMAKE_INCLUDE_PATH 和 CMAKE_LIBRARY_PATH

注意:這兩個是環境變量而不是 cmake 變量,可以在linux的bash中進行設置

我們上面例子中使用了絕對路徑INCLUDE_DIRECTORIES(/usr/include/hello)來指明include路徑的位置

我們還可以使用另外一種方式,使用環境變量export CMAKE_INCLUDE_PATH=/usr/include/hello

補充:生產debug版本的方法:
cmake .. -DCMAKE_BUILD_TYPE=debug


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM