準(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.h 和 hello.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.so 和 libhello_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.txt。src/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 ()