0
点赞
收藏
分享

微信扫一扫

C++ Cmake Tutorial On Mac OS

1 环境准备

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

2 Cmake简介

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

3 经典案例

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

3.1 HelloWorld

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

```C++
#include<iostream>

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


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

```cmake
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

```C++
#include<string>

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


- **src/Student.cpp**

```C++
#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

```C++
#include "Student.h"

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


- **CMakeLists.txt**

```cmake
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

```C++
#include "Student.h"

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


- **CMakeLists.txt**

```cmake
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 条评论