CMake 的基本使用

準(zhǔn)備工作

  • 最新版的 CMake(3.8)。
  • C/C++ 編譯器(GCC,MSVC,clang)。
  • 編輯器(CLion,Vim,Sublime Text)。

Hello World

  • 建立一個(gè) CMakeDemo 文件夾,作為項(xiàng)目的根文件夾。
  • 新建一個(gè)主文件 main.cpp
#include <iostream>

int main() {
    std::cout << "Hello, World!" << std::endl;
    return 0;
}
  • 在文件夾內(nèi)新建一個(gè) CMakeLists.txt 文件
cmake_minimum_required(VERSION 3.8)
project(CMakeDemo)

set(CMAKE_CXX_STANDARD 11)

set(SOURCE_FILES main.cpp)
add_executable(Demo ${SOURCE_FILES})

第一行代表運(yùn)行此項(xiàng)目需要的 CMake 最小版本為 3.8,第二行為項(xiàng)目名,第三行和第四行的 set 表示設(shè)置一個(gè)變量,括號(hào)里的第一個(gè)值為 key,后續(xù)的值為 value,最后一行表示添加一個(gè)可執(zhí)行文件。
bash 中輸入以下命令。

cmake .
make

第一行表示生成 Makefile 文件,第二行代表編譯。
輸入 ./Demo,運(yùn)行結(jié)果

Hello, World!

這是一個(gè)簡(jiǎn)單的 demo,下面開始正式的內(nèi)容。

標(biāo)準(zhǔn) C++ 工程的目錄結(jié)構(gòu)

通常的,一個(gè) C++ 項(xiàng)目包含以下幾個(gè)目錄:

  • 源代碼目錄
  • 第三方庫的包含目錄
  • 第三方庫的庫目錄
  • 文檔目錄
  • 二進(jìn)制目錄
  • README 和 License 等

所以我們?cè)?CMakeDemo 的根目錄新建一個(gè) src 文件夾,用來放置源碼,將 main.cpp 移入其中,并新建一個(gè) CMakeLists.txt。

CMakeDemo
└─src
|  └─main.cpp
|  └─CMakeLists.txt
└─CMakeLists.txt

我們?cè)?CMakeDemo/src/CMakeLists.txt 寫入如下內(nèi)容

add_executable(Demo main.cpp)

CMakeDemo/CMakeLists.txt 的內(nèi)容修改為

cmake_minimum_required(VERSION 3.8)
project(CMakeDemo)

set(CMAKE_CXX_STANDARD 11)

add_subdirectory(src bin)

add_subdirectory 表示生成一個(gè)子目錄,src 是目錄名,bin 是生成二進(jìn)制的位置(可缺?。?。
我們采用 out-of-source 外部構(gòu)建,即將編譯后的文件與源代碼分離。所以在 CMakeDemo 文件夾下新建一個(gè) build 文件夾,并 cd 進(jìn)入(即當(dāng)前的文件夾位置為 CMakeDemo/build),在 bash 中輸入

cmake ..
make

可以看到在 build/bin 目錄下,生成了二進(jìn)制文件。

動(dòng)態(tài)鏈接庫

src 目錄的下的內(nèi)容刪除,新建 hello.hhello.cpp,內(nèi)容如下:

hello.h

#ifndef CMAKEDEMO_HELLO_H
#define CMAKEDEMO_HELLO_H

#ifdef __cplusplus
extern "C" {
#endif

void say(const char *str);

#ifdef __cplusplus
}
#endif

#endif //CMAKEDEMO_HELLO_H

hello.cpp

#include <cstdio>
#include "hello.h"

void say(const char *str) {
    printf("%s\n", str);
}

修改 src/CMakeLists.txt

set(LIBHELLO hello.cpp hello.h)

add_library(hello_static STATIC ${LIBHELLO})
add_library(hello SHARED ${LIBHELLO})
set_target_properties(hello PROPERTIES LINKER_LANGUAGE C)

add_library 表示生成一個(gè)庫,SHARED 表示生成的是動(dòng)態(tài)庫,STATIC 表示生成的是靜態(tài)庫,在這里我們?nèi)窟x擇。最后一行為設(shè)置目標(biāo)參數(shù) LINKER_LANGUAGE C 表示 C 語言導(dǎo)出。

修改 CMakeDemo/CMakeLists.txt

cmake_minimum_required(VERSION 3.8)
project(CMakeDemo)

set(CMAKE_CXX_STANDARD 11)

add_subdirectory(src lib)

即將輸出文件夾命名為 lib。

在項(xiàng)目根目錄下新建一個(gè) build 文件,按照上節(jié)的方式編譯,可以看到,在 lib 目錄生成了 libhello.solibhello_static.a 兩個(gè)庫文件。

調(diào)用共享庫

按照如下目錄建立文件

CMakeDemo
└─src
|  └─CMakeLists.txt
|  └─hello
|    └─CMakeLists.txt
|    └─hello.h
|    └─hello.cpp
|  └─demo
|    └─CMakeLists.txt
|    └─demo.cpp
└─CMakeLists.txt

按照規(guī)范,我們應(yīng)為每個(gè)文件夾建立一個(gè) CMakeLists.txtsrc/hello 是我們的主項(xiàng)目,src/demo 是一個(gè)需要調(diào)用前者的 demo,下面填寫代碼

  • CMakeDemo/CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(CMakeDemo)

set(CMAKE_CXX_STANDARD 11)

add_subdirectory(src)
  • src/CMakeLists.txt
include_directories(hello)

add_subdirectory(demo bin)
add_subdirectory(hello lib)
  • src/demo/CMakeLists.txt
add_executable(hellodemo demo.cpp)
target_link_libraries(hellodemo hello)
  • src/demo/demo.cpp
#include <hello.h>
#include <cstdio>

int main()
{
    const char *p = "Hello";
    say(p);
    printf("Done\n");
    return 0;
}
  • src/hello 目錄的內(nèi)容不變

按照上一節(jié)的方式編譯,可以在 build/src/bin 目錄中找到 demo 文件,在 build/src/lib 中找到共享庫文件。
運(yùn)行 demo 文件

***@ubuntu:~/CMakeDemo/build/src/bin$ ./hellodemo
Hello
Done

使用外部共享庫

一般情況下,我們習(xí)慣將第三方包的頭文件放到 include 目錄下,庫文件放到 lib 目錄下。所以我們將 CMakeDemo 文件夾備份,然后清空,按照如下結(jié)構(gòu)建立文件

CMakeDemo
├── CMakeLists.txt
├── include
│   └── hello
│       ├── CMakeLists.txt
│       ├── hello.cpp
│       └── hello.h
├── lib
│   └── libhello.so
└── src
    ├── CMakeLists.txt
    └── main.cpp

將原文件中的 hello 目錄直接拷貝到 include 目錄,上一步生成的共享庫 libhello.so 拷貝到 lib 文件夾下。

  • CMakeDemo/CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(CMakeDemo)

set(CMAKE_CXX_STANDARD 11)

include_directories(include)
link_directories(lib)

add_subdirectory(src bin)
  • CMakeDemo/src/CMakeLists.txt
add_executable(main main.cpp)
target_link_libraries(main hello)
  • CMakeDemo/src/main.cpp
#include <hello/hello.h>
#include <cstdio>

int main()
{
    const char *p = "Hello";
    say(p);
    printf("Done\n");
    return 0;
}

編譯,運(yùn)行

***@ubuntu:~/CMakeDemo/bin$ ./main
Hello
Done

其他常用操作

添加 OpenMP 支持

IF (APPLE)
    message(STATUS "clang does not support OpenMP!")
ELSEIF (WIN32 OR UNIX)
    find_package(OpenMP REQUIRED)
    IF(OPENMP_FOUND)
        message(STATUS "OPENMP FOUND!")
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
    ENDIF()
ENDIF ()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容