C++中使用CMake编译管理项目

CMake是一个跨平台的Makefile生成工具,可以根据特定的规则生成相应的Makefile文件,并对C/C++源代码进行编译和管理。
有一篇博客介绍CMake的使用,比较通俗易懂,链接地址是:Cmake 详解
CMake的官方下载地址为:https://cmake.org/download/
官方文档地址为:CMake 3.16 Documentation
官方的CMake指南地址为:CMake Tutorial

一、CMake中添加对C++11的支持

1、在对应的CMakeLists.txt文件中加入以下语句:

add_definitions(-std=c++11)

或者

 if(CMAKE_COMPILER_IS_GNUCXX)
      set(CMAKE_CXX_FLAGS "-std=c++11 -g ${CMAKE_CXX_FLAGS}")
 endif(CMAKE_COMPILER_IS_GNUCXX)

2、延伸 如何写cmake使其包含c++11特性 (-std=c++11如何写进cmakeList.txt)

使用的g++版本和cmake版本分别是g++ 4.8.2和cmake 2.8
之前写cmkae编译带有c++11特性的代码有这么一句:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

但是总会出现cc1plus: error: unrecognized command line option "-std=c++11" 报错。
所以set(QMAKE_CXXFLAGS "-std=c++11") 类似的写法肯定不行。
后来发现是std=c++11 这种写法老版本不支持。
ok
直接测试新写法 CMakeLists.txt文件如下所示:

#CMakeLists.txt
project(test)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST}${PROJECT_NAME}.cpp)

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
       set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

测试c++11代码如下:

//test.cc
#include <iostream>
#include<vector>
using namespace std; 
int main()
{
    const std::vector<int>v(1);
    auto a = v[0];//a为int类型
        cout <<"a : "<< a <<endl;
    decltype(v[0]) b = 0;//b为const int&类型,即std::vector<int>::operator[](size_type)const的返回类型
    auto c = 0;//c为int类型
    auto d = c;//d为int类型
    decltype(c) e;//e为int类型,c实体的类型
    decltype((c)) f = e;//f为int&类型,因为(c)是左值
    decltype(0) g;//g为int类型,因为0是右值
    
    return 0;
}

examples_CMake项目

github上面有一个韩国人jacking75写的简单的cmake使用示例,
examples_CMake项目地址是:https://github.com/jacking75/examples_CMake

CMake例子

范例介绍

示例代码在CMake_example目录中。

01 helloworld 一个简单文件中的-C ++代码
  • main.cpp
#include <iostream>

int main()
{
  auto name = "jacking";
  std::cout << "hello world: " << name << std::endl;
  return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_definitions(-std=c++11)
add_executable(Main main.cpp)
02 helloworld-设置编译器选项。 -Wall,C ++ 14
  • main.cpp
#include <iostream>

int main()
{
  auto name = "jacking";
  std::cout << "hello world: " << name << std::endl;
  return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_definitions("-Wall -std=c++14")
add_executable(Main main.cpp)
03 helloworld-如果您有除主代码文件以外的其他代码文件
  • main.cpp
#include "test.h"

int main()
{
    TEST test;
    test.Print();
    return 0;
}
  • test.h
class TEST
{
public:
    void Print();
};
  • test.cpp
#include "test.h"

#include <iostream>

void TEST::Print()
{
    std::cout << "Test::Print" << std::endl;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_executable(Main
  main.cpp
  test.cpp
)
04 helloworld-如果mai.cpp以外的文件位于其他目录中

源代码04_helloworld目录结构如下:

[root@ltcos01 04_helloworld]$ tree -L 2
.
├── CMakeLists.txt
├── main.cpp
├── test01
│   ├── test01.cpp
│   └── test01.h
└── test02
    ├── test02.cpp
    └── test02.h

2 directories, 6 files
  • main.cpp
#include "test01/test01.h"
#include "test02/test02.h"

int main()
{
  TEST01 test01;
  test01.Print();

  TEST02 test02;
  test02.Print();
  return 0;
}

test01目录下 有test01.h和test01.cpp这两个文件

  • test01/test01.h
class TEST01
{
public:
  void Print();
};
  • test01/test01.cpp
#include "test01.h"
#include <iostream>

void TEST01::Print()
{
    std::cout << "Test01::Print" << std::endl;
}

test02目录下有test02.h和test02.cpp这两个文件

  • test02/test02.h
class TEST02
{
public:
    void Print();
};
  • test02/test02.cpp
#include "test02.h"
#include <iostream>

void TEST02::Print()
{
    std::cout << "Test02::Print" << std::endl;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_executable(Main
  main.cpp
  test01/test01.cpp
  test02/test02.cpp
)
05 helloworld-reference 创建静态文件后

05_helloworld源代码目录树结构如下所示:

[root@ltcos01 05_helloworld]$ tree -L 2
.
├── CMakeLists.txt
├── main.cpp
├── test01
│   ├── CMakeLists.txt
│   ├── test01.cpp
│   └── test01.h
└── test02
    ├── CMakeLists.txt
    ├── test02.cpp
    └── test02.h

2 directories, 8 files
  • main.cpp
#include "test01/test01.h"
#include "test02/test02.h"

int main()
{
    TEST01 test01;
    test01.Print();

    TEST02 test02;
    test02.Print();
    return 0;
}
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_subdirectory(test01)                
add_subdirectory(test02)                
add_executable(Main main.cpp)
target_link_libraries(Main Test01 Test02)

test01目录下有test01.h和test01.cpp以及相应的CMakeLists.txt文件

  • test01/test01.h
class TEST01
{
public:
    void Print();
};
  • test01/test01.cpp
#include "test01.h"

#include <iostream>

void TEST01::Print()
{
    std::cout << "Test01::Print" << std::endl;
}
  • test01/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_library(Test01 STATIC
  test01.cpp
)

上面的test01目录下的CMakeLists.txt的add_library(Test01 STATIC test01.cpp)指令会生成相应的静态库文件libTest01.a

test02目录下和test01目录结构一样,也有test02.h和test02.cpp以及相应的CMakeLists.txt文件

  • test01/test02.h
class TEST02
{
public:
    void Print();
};
  • test02/test02.cpp
#include "test02.h"

#include <iostream>

void TEST02::Print()
{
    std::cout << "Test02::Print" << std::endl;
}
  • test02/CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
add_library(Test02 STATIC
  test02.cpp
)

同样的,在上面的test02目录下执行cmake命令会生成相应的静态库文件libTest02.a。具体操作过程如下:新建一个build目录,然后进入到build目录下执行cmake ..运行上一级目录即test02下的CMakeLists.txt文件,操作如下:

[root@ltcos01 test02]$ ls
build  CMakeLists.txt  test02.cpp  test02.h
[root@ltcos01 test02]$ cd build/
[root@ltcos01 build]$ ls
[root@ltcos01 build]$ cmake ..
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- 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
-- Detecting C compile features
-- Detecting C compile features - 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
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /data/public/home/cchufeng/GithubProjects/examples_CMake/CMake_example/05_helloworld/test02/build
[root@ltcos01 build]$ make
Scanning dependencies of target Test02
[ 50%] Building CXX object CMakeFiles/Test02.dir/test02.cpp.o
[100%] Linking CXX static library libTest02.a
[100%] Built target Test02
[root@ltcos01 build]$ ls
CMakeCache.txt  CMakeFiles  cmake_install.cmake  libTest02.a  Makefile
[root@ltcos01 build]$ 
06 helloworld-指定编译器
  • main.cpp
#include <iostream>

int main()
{
    auto name = "jacking";
  std::cout << "hello world: " << name << std::endl;
  return 0;
}
  • CMakeLists.txt
PROJECT(hello)

set(CMAKE_CXX_COMPILER g++)
add_definitions("-Wall -std=c++14")

ADD_EXECUTABLE(main main.cpp)
07 helloworld-使用外部库(此处为Boost库)
  • main.cpp
#include <boost/thread.hpp>
#include <iostream>

int main()
{
    std::cout << "Boost.Thread !!!" << std::endl;
    boost::thread Thread1( [] ()
    {
        for( int i = 0; i < 5; ++i )
        {
            std::cout << "Thread Num : " << i << std::endl;
        }
    } );

    Thread1.join();
    return 0;
}
  • CMakeLists.txt
PROJECT(hello)

set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_FLAGS "-m64")
add_definitions("-Wall -std=c++14")

INCLUDE_DIRECTORIES(/$ENV{HOME}/Dev/C++/ThirdParty/boost_1_60_0)
LINK_DIRECTORIES(/$ENV{HOME}/Dev/C++/ThirdParty/boost_1_60_0/stage/gcc/lib)

ADD_EXECUTABLE(hello-boost hello-boost.cpp)

TARGET_LINK_LIBRARIES(hello-boost pthread boost_thread boost_system boost_chrono)

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343