C++ Cmake Tutorial On Mac OS

本文详细介绍了如何在MacOS上使用Cmake构建C++项目,从简单的HelloWorld到包含目录结构的项目,再到动态库和静态库的编译。通过五个经典案例,阐述了Cmake在项目构建过程中的作用,包括设置源文件、生成Makefile、编译及安装库文件。此外,还展示了如何使用静态库和动态库。这些案例对于理解和使用Cmake构建C++工程具有指导意义。
摘要由CSDN通过智能技术生成

1 环境准备
在MacOS上面已经安装了Xcode,确保C++的构建环境没有问题。

2 Cmake简介
cmake的亮点在于编译复杂项目上的应用 —— cmake是一个跨平台的Makefile 生成工具! 一言以蔽之——cmake 为项目自动生成Makefile, 虽然cmake功能远不止步于此,但是本文聚焦于此。

3 经典案例
这里有5个非常经典短小的案例,但却足以窥探C++在工程项目构建中是如何使用Cmake的,相信这对于Java程序员来说会是非常好的入门案例,因为对于C++,编程语言本身复杂,但构建也是让人一头雾水,因此非常需要这样一份quickstart的指南。

3.1 HelloWorld
第一个例子源代码只有一个文件HelloWorld.cpp:

#include<iostream>

int main(int argc, char *argv[]){
   std::cout << "Hello World!" << std::endl;
   return 0;
}

CMakeLists.txt也只有三行而已(使用cmake管理项目的过程,也就是编写CMakeLists.txt的过程):

cmake_minimum_required(VERSION 3.21)
project(hello)
add_executable(hello helloworld.cpp)

第一行用于指定cmake最低版本
第二行指定项目名称(这个名称是任意的)
第三行指定编译一个可执行文件,hello是第一个参数,表示生成可执行文件的文件名(这个文件名也是任意的),第二个参数helloworld.cpp则用于指定源文件。

1.用cmake生成Makefile文件

cmake命令后边跟的就是CMakelist.txt所在的目录,这个目录不必是当前目录,你也可以新建一个build目录或者其他名字的目录来生成build文件,实际项目中也都是这么做的,这样代码会很干净也便于git管理:

leafMacBook:helloworld xpleaf$ mkdir build
leafMacBook:helloworld xpleaf$ cd build/
leafMacBook:build xpleaf$ cmake ..
……
leafMacBook:build xpleaf$ ls
CMakeCache.txt          CMakeFiles              Makefile                cmake_install.cmake

2.使用make编译程序

leafMacBook:build xpleaf$ make
[ 50%] Building CXX object CMakeFiles/hello.dir/helloworld.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello
leafMacBook:build xpleaf$ ls
CMakeCache.txt          CMakeFiles              Makefile                cmake_install.cmake     hello

3.测试程序

leafMacBook:build xpleaf$ ./hello 
Hello World!

3.2 包含目录结构的项目
在例1中完全体现不出cmake的任何优势,用g++一行可以解决的问题我们绕了一大圈。可是cmake本来的优势就是管理庞大的项目的。这个例子用最小的程序来体现一个带目录结构的项目。其中有源文件目录,头文件目录。

代码路径结构如下:

leafMacBook:c++ xpleaf$ tree student
student
├── CMakeLists.txt
├── include
│   └── Student.h
└── src
    ├── Sutdent.cpp
    └── mainapp.cpp

2 directories, 4 files

各文件内容如下:

include/Student.h

#include<string>

class Student{
private:
        std::string name;
public:
        Student(std::string);
        virtual void display();


src/Student.cpp

#include <iostream>
#include "Student.h"
using namespace std;

Student::Student(string name):name(name){}

void Student::display(){
        cout << "A student with name " << this->name << endl;


src/mainapp.cpp

#include "Student.h"

int main(int argc, char *argv[]){
   Student s("Joe");
   s.display();
   return 0;


CMakeLists.txt

cmake_minimum_required(VERSION 3.21)
project(directory_test)

#Bring the headers, such as Student.h into the project
include_directories(include)

#Can manually add the sources using the set command as follows:
#set(SOURCES src/mainapp.cpp src/Student.cpp)

#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")


相对于第一个例子,CMakelist.txt有如下改变:

1.使用include_directories() 包含头文件目录
2.使用set(SOURCES … ) 或GLOB (or GLOB_RECURSE) 设置源文件SOURCES
3.add_executable 使用变量SOURCES ,而不是具体的文件名

接下来执行编译和运行:

leafMacBook:student xpleaf$ mkdir build
leafMacBook:student xpleaf$ cd build/
leafMacBook:build xpleaf$ cmake ..
……
leafMacBook:build xpleaf$ make
……
leafMacBook:build xpleaf$ ./testStudent 
A student with name Joe


3.3 动态库编译(.so或.dylib)
在Mac OS当中,编译出来的动态库的后缀名为.dylib,而不是.so,这点需要注意。

代码结构如下:

leafMacBook:c++ xpleaf$ tree studentlib_shared/
studentlib_shared/
├── CMakeLists.txt
├── include
│   └── Student.h
└── src
    ├── Sutdent.cpp
    └── mainapp.cpp

2 directories, 4 files


其实与student项目是一样的,只是CmakeLists.txt不同,如下:

cmake_minimum_required(VERSION 3.21)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
 
#Bring the headers, such as Student.h into the project
include_directories(include)
 
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
 
#Generate the shared library from the sources
add_library(testStudent SHARED ${SOURCES})
 
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /Users/xpleaf/projects/c++/studentlib_shared/build/lib)


两个重要变化:

1.我们不再使用add_executable() 而是使用add_library()
2.install 指定安装目录,执行sudo make install时动态库将被安装在指定目录

编译安装:

leafMacBook:studentlib_shared xpleaf$ mkdir build
leafMacBook:studentlib_shared xpleaf$ cd build/
leafMacBook:build xpleaf$ cmake ..
……
leafMacBook:build xpleaf$ make install
……
leafMacBook:build xpleaf$ ls lib
libtestStudent.dylib


3.4 静态库编译(.a)
有了前两个例子的基础,接下来的例子我们只需要看一下目录结构:

leafMacBook:c++ xpleaf$ tree studentlib_static
studentlib_static
├── CMakeLists.txt
├── include
│   └── Student.h
└── src
    ├── Sutdent.cpp
    └── mainapp.cpp

2 directories, 4 files


代码跟前面还是一样的,只是CMakeLists.txt有所不同,如下:

cmake_minimum_required(VERSION 3.21)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
 
#Bring the headers, such as Student.h into the project
include_directories(include)
 
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "src/*.cpp")
 
#Generate the shared library from the sources
add_library(testStudent STATIC ${SOURCES})
 
#Set the location for library installation -- i.e., /usr/lib in this case
# not really necessary in this example. Use "sudo make install" to apply
install(TARGETS testStudent DESTINATION /Users/xpleaf/projects/c++/studentlib_static/build/lib)


可以看到,只是在add_library中把SHARED修改为STATIC(当然安装路径也做了相应修改).

接下来编译安装:

leafMacBook:studentlib_static xpleaf$ mkdir build
leafMacBook:studentlib_static xpleaf$ cd build/
leafMacBook:build xpleaf$ cmake ..
……
leafMacBook:build xpleaf$ make install
……
leafMacBook:build xpleaf$ ls lib
libtestStudent.a


3.5 使用静态库或动态库
接下来测试一下使用前面编译的库,代码结构如下:

leafMacBook:c++ xpleaf$ tree usestudentlib/
usestudentlib/
├── CMakeLists.txt
└── libtest.cpp

0 directories, 2 files


libtest.cpp

#include "Student.h"

int main(int argc, char *argv[]){
   Student s("Joe");
   s.display();
   return 0;
}


CMakeLists.txt

cmake_minimum_required(VERSION 3.21)
project (TestLibrary)

#For the shared library:
set ( PROJECT_LINK_LIBS libtestStudent.dylib )
link_directories( /Users/xpleaf/projects/c++/studentlib_shared/build/lib )

#For the static library:
#set ( PROJECT_LINK_LIBS libtestStudent.a )
#link_directories( /Users/xpleaf/projects/c++/studentlib_static/build/lib )

include_directories(/Users/xpleaf/projects/c++/studentlib_shared/include)

add_executable(libtest libtest.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )


编译运行如下:

leafMacBook:usestudentlib xpleaf$ mkdir build
leafMacBook:usestudentlib xpleaf$ cd build/
leafMacBook:build xpleaf$ cmake ..
……
leafMacBook:build xpleaf$ make
……
leafMacBook:build xpleaf$ ls
CMakeCache.txt          CMakeFiles              Makefile                cmake_install.cmake     libtest
leafMacBook:build xpleaf$ ./libtest 
A student with name Joe


那么这样的话,从如何通过Cmake构建项目成可执行文件或库文件,到最后如何通过Cmake引入构建的库,这里的案例都做了完整的介绍,相信对于理解在C++当中是如何基于Cmake来构建工程级项目,会有一个整体的认识,这对于阅读基于Cmake构建的C++开源项目源码会有非常大的帮助!

附录:参考文档
本文参考了下面的文档内容:

https://blog.csdn.net/iceboy314159/article/details/80398084

http://derekmolloy.ie/hello-world-introductions-to-cmake

感谢源作者的无私分享!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值