【CMake】CMakeLists.txt的超傻瓜手把手教程(附實例源碼)

新手寫CMakeLists.txt簡直就是實力勸退,各種命令讓很多人頭大,如何寫一個最基礎的CMakeLists.txt呢?本文從一個實例出發,教你編寫的基本流程。

本文附實例的源碼地址。

CMakeLists.txt的基本結構

編寫CMakeLists.txt最常用的功能就是調用其他的.h頭文件和.so/.a庫文件,將.cpp/.c/.cc文件編譯成可執行文件或者新的庫文件

命令的官方網站:CMake Reference Documentation

最常用的命令如下(僅供後期查詢,初期不需要細看):

# 本CMakeLists.txt的project名稱
# 會自動創建兩個變量,PROJECT_SOURCE_DIR和PROJECT_NAME
# ${PROJECT_SOURCE_DIR}:本CMakeLists.txt所在的文件夾路徑
# ${PROJECT_NAME}:本CMakeLists.txt的project名稱
project(xxx)

# 獲取路徑下所有的.cpp/.c/.cc文件,並賦值給變量中
aux_source_directory(路徑 變量)

# 給文件名/路徑名或其他字符串起別名,用${變量}獲取變量內容
set(變量 文件名/路徑/...)

# 添加編譯選項
add_definitions(編譯選項)

# 打印消息
message(消息)

# 編譯子文件夾的CMakeLists.txt
add_subdirectory(子文件夾名稱)

# 將.cpp/.c/.cc文件生成.a靜態庫
# 注意,庫文件名稱通常爲libxxx.so,在這裏只要寫xxx即可
add_library(庫文件名稱 STATIC 文件)

# 將.cpp/.c/.cc文件生成可執行文件
add_executable(可執行文件名稱 文件)

# 規定.h頭文件路徑
include_directories(路徑)

# 規定.so/.a庫文件路徑
link_directories(路徑)

# 對add_library或add_executable生成的文件進行鏈接操作
# 注意,庫文件名稱通常爲libxxx.so,在這裏只要寫xxx即可
target_link_libraries(庫文件名稱/可執行文件名稱 鏈接的庫文件名稱)

通常一個CMakeLists.txt需按照下面的流程

project(xxx)                                          #必須

add_subdirectory(子文件夾名稱)                         #父目錄必須,子目錄不必

add_library(庫文件名稱 STATIC 文件)                    #通常子目錄(二選一)
add_executable(可執行文件名稱 文件)                     #通常父目錄(二選一)

include_directories(路徑)                              #必須
link_directories(路徑)                                 #必須

target_link_libraries(庫文件名稱/可執行文件名稱 鏈接的庫文件名稱)       #必須

除了這些之外,就是些set變量的語句,if判斷的語句,或者其他編譯選項的語句,但基本結構都是這樣的。


實例

我以自己曾經寫的一段實際代碼爲例,來講解究竟該怎麼寫CMakeLists

實例地址:

碼雲https://gitee.com/yngzMiao/protobuf-parser-tool

GitHubhttps://github.com/yngzMiao/protobuf-parser-tool

實例的功能是生成和解析proto文件,分爲C++python版本。其中,C++版本就是採用CMakeLists.txt編寫的,目錄結構如下:

|---example_person.cpp
|---proto_pb2
        |--Person.pb.cc
        |--Person.pb.h
|---proto_buf
        |---General_buf_read.h
        |---General_buf_write.h
|---protobuf
        |---bin
                |---...
        |---include
                |---...
        |---lib
                |---...

目錄結構含義:

  1. protobufGoogle提供的相關解析庫和頭文件,被proto_pb2文件夾內引用;
  2. proto_pb2:封裝的Person結構和Person相關的處理函數,被proto_buf文件夾內引用;
  3. proto_buf:封裝的readwrite函數,被example_persom.cpp文件引用。

也就是說:

example_person.cpp–>proto_buf文件夾–>proto_pb2文件夾–>protobuf文件夾


步驟

CMakeLists.txt的創建

在需要進行編譯的文件夾內編寫CMakeLists.txt,即含有.cpp/.c/.cc的文件夾內:

即目錄結構如下:

|---example_person.cpp
|---CMakeLists.txt
|---proto_pb2
        |--Person.pb.cc
        |--Person.pb.h
        |--CMakeLists.txt
|---proto_buf
        |---General_buf_read.h
        |---General_buf_write.h
|---protobuf
        |---bin
                |---...
        |---include
                |---...
        |---lib
                |---...

CMakeLists.txt的編寫

本項目的CMakeLists.txt的文件數量是2個,目錄層次結構爲上下層關係。通常的解決方案,就是將下層目錄編譯成一個靜態庫文件,讓上層目錄直接讀取和調用,而上層目錄就直接生成一個可執行文件

上層CMakeLists.txt的內容爲:

cmake_minimum_required(VERSION 3.0)
project(example_person)

# 如果代碼需要支持C++11,就直接加上這句
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
# 如果想要生成的可執行文件擁有符號表,可以gdb調試,就直接加上這句
add_definitions("-Wall -g")

# 設置變量,下面的代碼都可以用到
set(GOOGLE_PROTOBUF_DIR ${PROJECT_SOURCE_DIR}/protobuf)
set(PROTO_PB_DIR ${PROJECT_SOURCE_DIR}/proto_pb2)
set(PROTO_BUF_DIR ${PROJECT_SOURCE_DIR}/proto_buf)

# 編譯子文件夾的CMakeLists.txt
add_subdirectory(proto_pb2)

# 規定.h頭文件路徑
include_directories(${PROJECT_SOURCE_DIR}
    ${PROTO_PB_DIR} ${PROTO_BUF_DIR}
)

# 生成可執行文件
add_executable(${PROJECT_NAME} example_person.cpp )

# 鏈接操作
target_link_libraries(${PROJECT_NAME}
    general_pb2)

如果是初學者,這一段可能看不到兩個地方,第一是鏈接操作的general_pb2,第二是按照上文的CMakeLists.txt的流程,並沒有規定link_directories的庫文件地址啊,這是什麼道理?

這兩個其實是一個道理,add_subdirectory起到的作用

當運行到add_subdirectory這一句時,會先將子文件夾進行編譯,而libgeneral_pb2.a是在子文件夾中生成出來的庫文件。子文件夾運行完後,父文件夾就已經知道了libgeneral_pb2.a這個庫,因而不需要link_directories了。

同時,另一方面,在add_subdirector之前set的各個變量,在子文件夾中是可以調用的

下層CMakeLists.txt的內容爲:

project(general_pb2)

aux_source_directory(${PROJECT_SOURCE_DIR} PB_FILES)

add_library(${PROJECT_NAME} STATIC ${PB_FILES})

include_directories(${PROJECT_SOURCE_DIR}
    ${GOOGLE_PROTOBUF_DIR}/include
)

link_directories(${GOOGLE_PROTOBUF_DIR}/lib/)

target_link_libraries(${PROJECT_NAME}
    protobuf
)

在這裏,GOOGLE_PROTOBUF_DIR是上層CMakeLists.txt中定義的,libprotobuf.a是在${GOOGLE_PROTOBUF_DIR}/lib/目錄下的。

顯然可見,這就是一個標準的CMakeLixts.txt的流程。

CMakeLists.txt的編譯

一般CMakeLists.txt是,在最頂層創建build文件夾,然後編譯。即:

mkdir build && cd build
cmake ..
make

最終生成可執行文件example_person

可以通過以下命令來運行該可執行文件:

./example_person
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章