cmake

一 cmake基础-生成可执行文件和库

在编写 CMake 之前,要确保你已经清楚了如何运行 CMake 来构建文件。 几乎所有 CMake 项目都一样。

这是经典的构建流程:

1 mkdir build
2 cd build
3 cmake ..
4 make

不是每个项目都必须这样做,你也可以建立一个奇奇怪怪的文件夹名。但我们默认遵守这个规则,即建立一个build文件夹来存生成的构建项。

现在来将一个源文件编译为可执行文件,这是源文件,文件名为main.cpp:

#include<iostream>
using namespace std;
int main()
{
        cout<<"hello cmake"<<endl;
     return 0;
}

同时,在这个源文件的目录写CMakeLists.txt文件:

#第一行,设置CMake所需的最低版本。如果使用的CMake版本低于该版本,则会发出致命错误:
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

#第二行,声明了项目的名称(recipe-01)和支持的编程语言(CXX代表C++):
project(recipe-01 LANGUAGES CXX)

#指示CMake创建一个新目标:可执行文件main.cpp。这个可执行文件是通过编译和链接源文件main.cpp生成的。CMake将为编译器使用默认设置,并自动选择生成工具: add_executable(hello main.cpp)

现在,建立一个build目录,并在其中配置项目:

$ mkdir -p build
$ cd build
$ cmake ..
-- The CXX compiler identification is GNU 8.1.0
-- 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: /home/user/cmake-cookbook/chapter-01/recipe-01/cxx-example/build

如果一切顺利,项目的配置已经在build目录中生成。我们现在可以编译可执行文件:

$ cmake --build .
Scanning dependencies of target main
[ 50%] Building CXX object CMakeFiles/main.dir/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

NOTE:CMake语言不区分大小写,但是参数区分大小写。

NOTE:在与CMakeLists.txt相同的目录中执行cmake .,原则上足以配置一个项目。然而,CMake会将所有生成的文件写到项目的根目录中。这将是一个源代码内构建,通常是不推荐的,因为这会混合源代码和项目的目录树。我们首选的是源外构建。

 

构建和链接静态库和动态库

NOTE:可执行文件和目标文件没有什么本质的不同,可执行文件区别于目标文件的地方在于,可执行文件有一个入口函数,这个函数也就是我们在C语言当中定义的main函数,main函数在执行过程中会用到所有可执行文件当中的代码和数据。而这个main函数是被谁调用执行的呢,答案就是操作系统(Operating System) [1] 彻底理解链接器:三,库与可执行文件 - SegmentFault 思否

回看第一个例子,这里并不再为可执行文件提供单个源文件,我们现在将引入一个类,用来包装要打印到屏幕上的消息。更新一下的main.cpp:

#include "Message.hpp"
#include <cstdlib>
#include <iostream>
int main() {
  Message say_hello("Hello, CMake World!");
  std::cout << say_hello << std::endl;
  Message say_goodbye("Goodbye, CMake World");
  std::cout << say_goodbye << std::endl;
  return EXIT_SUCCESS;
}

Message类包装了一个字符串,并提供重载过的<<操作,并且包括两个源码文件:Message.hpp头文件与Message.cpp源文件。Message.hpp中的接口包含以下内容:

#pragma once
#include <iosfwd>
#include <string>
class Message {
public:
  Message(const std::string &m) : message_(m) {}
  friend std::ostream &operator<<(std::ostream &os, Message &obj) {
    return obj.printObject(os);
  }
private:
  std::string message_;
  std::ostream &printObject(std::ostream &os);
};

NOTE:以上代码的 std::ostream &printObject(std::ostream &os); 声明了一个函数printObject,返回的是一个ostream对象的引用,具体看 c++中引用作为返回值 - 知乎 (zhihu.com)

Message.cpp实现如下:

#include "Message.hpp"
#include <iostream>
#include <string>
std::ostream &Message::printObject(std::ostream &os) {
  os << "This is my very nice message: " << std::endl;
  os << message_;
  return os;
}

这里有两个文件需要编译,所以CMakeLists.txt必须进行修改。本例中,先把它们编译成一个库,而不是直接编译成可执行文件:

#创建目标——静态库。库的名称和源码文件名相同,具体代码如下:
add_library(message
  STATIC
    Message.hpp
    Message.cpp
  )

#创建main可执行文件的目标部分不需要修改:
add_executable(main main.cpp)

#最后,将目标库链接到可执行目标:
target_link_libraries(main message)

NOTE:必须先生成可执行文件再链接库.

CMake接受其他值作为add_library的第二个参数的有效值,我们来看下会用到的值:

  • STATIC:用于创建静态库,即编译文件的打包存档,以便在链接其他目标时使用,例如:可执行文件。
  • SHARED:用于创建动态库,即可以动态链接,并在运行时加载的库。可以在CMakeLists.txt中使用add_library(message SHARED Message.hpp Message.cpp)从静态库切换到动态共享对象(DSO)。
  • OBJECT:可将给定add_library的列表中的源码编译到目标文件,不将它们归档到静态库中,也不能将它们链接到共享对象中。如果需要一次性创建静态库和动态库,那么使用对象库尤其有用。我们将在本示例中演示。
  • MODULE:又为DSO组。与SHARED库不同,它们不链接到项目中的任何目标,不过可以进行动态加载。该参数可以用于构建运行时插件。

现在展示OBJECT库的使用,修改CMakeLists.txt,如下:

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(recipe-03 LANGUAGES CXX)
add_library(message-objs
    OBJECT
        Message.hpp
        Message.cpp
    )
# this is only needed for older compilers
# but doesn't hurt either to have it
set_target_properties(message-objs
    PROPERTIES
        POSITION_INDEPENDENT_CODE 1
    )
add_library(message-shared
    SHARED
        $<TARGET_OBJECTS:message-objs>
    )
add_library(message-static
    STATIC
        $<TARGET_OBJECTS:message-objs>
    )
add_executable(main main.cpp)
target_link_libraries(main message-static)

 

posted @ 2023-11-10 17:04  —_—Zed  阅读(37)  评论(0)    收藏  举报