Skip to content

CMake与静态库和动态库

如何生成静/动态库

  • 静态库

    在链接阶段会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

    对函数库的链接是在编译时完成的!

    静态库对空间的浪费是巨大的!

  • 动态库

    动态库不是在编译时被链接到目标代码中,而是运行时才被载入。

命名

  • 动态库的命名

    lib<name>.so/dll/dylib

  • 静态库的命名

    lib<name>.a/lib

动静态库的后缀名

  • 在Windows系统中动静态库的后缀名分别为 dll lib
  • 在Linux系统中动静态库的后缀名分别为 so a
  • 在Mac系统中动静态库的后缀名分别为 dylib a

命令

  • find():常用于搜索源文件
  • add_library(<库名> STATIC ${SRC}):生成静态库
  • add_library(<库名> SHARED ${SRC}):生成动态库
  • ${LIBRARY_OUTPUT_PATH}:导出目录

直接测试

现在有以下目录结构及代码环境

cmake
# 配置CMake的最小版本
cmake_minimum_required(VERSION 3.20.0)

# 配置项目名称
project(test)

# 将src目录下的所有cpp文件添加到SRC变量中
file(GLOB SRC ${PROJECT_SOURCE_DIR}/src/*.cpp)

include_directories(${PROJECT_SOURCE_DIR}/include)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

# 生成静态库
add_library(animal_static STATIC ${SRC})
add_library(cat STATIC ${PROJECT_SOURCE_DIR}/src/cat.cpp)
# 在cmake中,同时生成静态库与动态库的时候,需要一些技巧;因为cmake中不能生成同名的静态库和动态库,只能先生成不同名的库之后再把其中一个库的名字改名。
# set_target_properties(animal_static PROPERTIES OUTPUT_NAME "animal")

# 生成动态库
add_library(animal SHARED ${SRC})
add_library(dog SHARED ${PROJECT_SOURCE_DIR}/src/dog.cpp)
cpp
#pragma once
#include <string>

class Cat {
private:
    std::string name_;
    std::string bark_;

public:
    Cat(std::string name, std::string bark = "Miao~ miao~");
    void bark();
};
cpp
#pragma once

#include <string>

class Dog {
private:
    std::string name_;
    std::string bark_;

public:
    Dog(std::string name, std::string bark = "Wang! Wang wang wang");
    void barking();
};
cpp
#include "cat.h"
#include <iostream>

Cat::Cat(std::string name, std::string bark) : name_(name), bark_(bark) {}

void Cat::bark() {
    std::cout << bark_ << std::endl;
}
cpp
#include "dog.h"
#include <iostream>

Dog::Dog(std::string name, std::string bark) : name_(name), bark_(bark) {}
void Dog::barking() {
    std::cout << bark_ << std::endl;
}

使用CMake进行构建并运行

shell
$ ls
CMakeLists.txt  include  src

$ cmake -B build
-- The C compiler identification is GNU 12.3.0
-- The CXX compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zm/code/cmake/projects/ch04_01/build

$ cmake --build build
[ 16%] Building CXX object CMakeFiles/animal_static.dir/src/cat.cpp.o
[ 33%] Building CXX object CMakeFiles/animal_static.dir/src/dog.cpp.o
[ 50%] Linking CXX static library /home/zm/code/cmake/projects/ch04_01/lib/libanimal.a
[ 50%] Built target animal_static
[ 66%] Building CXX object CMakeFiles/animal.dir/src/cat.cpp.o
[ 83%] Building CXX object CMakeFiles/animal.dir/src/dog.cpp.o
[100%] Linking CXX shared library /home/zm/code/cmake/projects/ch04_01/lib/libanimal.so
[100%] Built target animal

$ ls
CMakeLists.txt  build  include  lib  src

$ tree -I build
.
├── CMakeLists.txt
├── include
   ├── cat.h
   └── dog.h
├── lib
   ├── libanimal.a
   └── libanimal.so
└── src
 ├── cat.cpp
 └── dog.cpp

4 directories, 7 files

CMake如何调用静/动态库

静态库调用流程

  1. 引入头文件
  2. 链接静态库
  3. 生成可执行二进制文件

动态库调用流程

  1. 引入头文件
  2. 声明库目录
  3. 生成可执行二进制文件
  4. 链接动态库

直接测试

现在有以下目录结构及代码环境

cmake
# 配置CMake的最小版本
cmake_minimum_required(VERSION 3.20.0)

# 配置项目名称
project(test)

# 添加了头文件引入目录,编写代码的时间可以省略目录前缀了
include_directories(test PUBLIC ${PROJECT_SOURCE_DIR}/include)

# 链接静态库
# link_directories(${PROJECT_SOURCE_DIR}/lib)
# link_libraries(animal)
# add_executable(test main.cpp)

# 链接动态库
# link_directories(${PROJECT_SOURCE_DIR}/lib)
# add_executable(test main.cpp)
# target_link_libraries(test PUBLIC animal)

link_directories(${PROJECT_SOURCE_DIR}/lib)

add_executable(test main.cpp)

# 链接动静态库
target_link_libraries(test PUBLIC cat dog)
cpp
#pragma once
#include <string>

class Cat {
private:
    std::string name_;
    std::string bark_;

public:
    Cat(std::string name, std::string bark = "Miao~ miao~");
    void bark();
};
cpp
#pragma once

#include <string>

class Dog {
private:
    std::string name_;
    std::string bark_;

public:
    Dog(std::string name, std::string bark = "Wang! Wang wang wang");
    void barking();
};
cpp
#include "cat.h"
#include "dog.h"

int main(int argc, char *argv[]) {
    Dog dog("旺财");
    dog.barking();

    Cat cat("小橘");
    cat.bark();

    return 0;
}

使用CMake进行构建并运行

shell
$ cmake -B build
-- The C compiler identification is GNU 12.3.0
-- The CXX compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/zm/code/cmake/projects/ch04_02/build

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

$ build/test 
Wang! Wang wang wang
Miao~ miao~