c++ 动态库&静态库 使用cmakelist注意事项

在 C++ 项目中使用 CMake 构建系统来管理动态库和静态库时,有一些重要的注意事项。以下是一些关键点和示例,帮助您正确地使用 CMake 构建和链接动态库和静态库。

基本概念

  • 静态库:在编译时将所有代码链接到最终的可执行文件中。静态库的文件扩展名通常是 .a(在 Unix 系统上)或 .lib(在 Windows 系统上)。

  • 动态库:在运行时加载,文件扩展名通常是 .so(在 Unix 系统上)或 .dll(在 Windows 系统上)。

CMakeLists.txt 基本结构

1. 创建静态库假设我们有一个库 libfoo,包含源文件 foo.cpp 和头文件 foo.h。```cpp

// foo.h #ifndef FOO_H #define FOO_H

void foo();#endif // FOO_H

// foo.cpp #include "foo.h" #include void foo() { std::cout << "Hello from foo!" << std::endl; }

CMakeLists.txt 文件:

```cmake
cmake_minimum_required(VERSION 3.10)
project(FooLibrary)set(CMAKE_CXX_STANDARD 11)

# 添加源文件
set(SOURCES foo.cpp)

# 创建静态库
add_library(foo STATIC ${SOURCES})# 设置库的可见性
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
```#### 2. 创建动态库

创建动态库的过程类似,只需将 `STATIC` 改为 `SHARED`。

```cmake
cmake_minimum_required(VERSION 3.10)
project(FooLibrary)set(CMAKE_CXX_STANDARD 11)

# 添加源文件
set(SOURCES foo.cpp)# 创建动态库
add_library(foo SHARED ${SOURCES})

# 设置库的可见性
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

3. 使用库

假设我们有一个主程序 main.cpp,使用 libfoo 库。```cpp // main.cpp #include "foo.h"int main() { foo(); return 0; }


```cmake
cmake_minimum_required(VERSION 3.10)
project(MainProgram)

set(CMAKE_CXX_STANDARD 11)

# 添加源文件
set(SOURCES main.cpp)

# 添加子目录
add_subdirectory(foo)

# 创建可执行文件
add_executable(main ${SOURCES})

# 链接库
target_link_libraries(main foo)

注意事项

1. 库的可见性

在跨平台开发时,确保导出的符号具有适当的可见性。使用宏来控制符号导出:

// foo.h
#ifndef FOO_H
#define FOO_H

#if defined(_WIN32) || defined(_WIN64)
  #ifdef BUILDING_FOO
    #define FOO_API __declspec(dllexport)
  #else
    #define FOO_API __declspec(dllimport)
  #endif
#else
  #define FOO_API
#endif

FOO_API void foo();#endif // FOO_H
```在 CMakeLists.txt 文件中定义 `BUILDING_FOO` 宏:```cmake
add_library(foo SHARED ${SOURCES})
target_compile_definitions(foo PRIVATE BUILDING_FOO)

2. 设置 RPATH

在使用动态库时,确保运行时能找到库文件。可以通过设置 RPATH 来实现:

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

3. 安装目标

使用 install 命令来设置库和头文件的安装路径:

# 安装库
install(TARGETS foo
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)

# 安装头文件
install(FILES foo.h DESTINATION include)

4. 导出和导入库

使用 exportimport 功能来支持库的导出和导入:

# 导出库
install(EXPORT FooLibraryConfig
        FILE FooLibraryConfig.cmake
        DESTINATION lib/cmake/FooLibrary)

# 导入库
find_package(FooLibrary CONFIG REQUIRED)
target_link_libraries(main FooLibrary::foo)

示例项目结构

project/
├── CMakeLists.txt
├── foo/
│   ├── CMakeLists.txt
│   ├── foo.cpp
│   └── foo.h
└── main.cpp

顶层 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.10)
project(MyProject)

set(CMAKE_CXX_STANDARD 11)

# 添加子目录
add_subdirectory(foo)

# 创建主程序
add_executable(main main.cpp)# 链接库
target_link_libraries(main foo)

foo 目录下的 CMakeLists.txt 文件:

cmake_minimum_required(VERSION 3.10)
project(FooLibrary)

set(CMAKE_CXX_STANDARD 11)

# 添加源文件
set(SOURCES foo.cpp)

# 创建动态库
add_library(foo SHARED ${SOURCES})

# 设置库的可见性
target_include_directories(foo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

# 安装库
install(TARGETS foo
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib)

# 安装头文件
install(FILES foo.h DESTINATION include)

总结

使用 CMake 管理动态库和静态库时,确保正确设置库的可见性、RPATH 和安装路径,并处理好库的导出和导入。通过遵循这些注意事项,可以有效避免常见的构建和链接问题。

常见问题和解决方法

1. 未定义的引用

如果遇到未定义的引用错误,通常是因为:

  • 没有正确链接所需的库。

  • 链接顺序错误。(特别注意,静态库需要严格按照链接顺序)

  • 库版本不匹配。

确保所有依赖库都已正确链接,并且顺序正确。

2. 符号冲突

如果多个库中包含相同的符号,可能会导致符号冲突。解决方法包括:

  • 使用命名空间来隔离符号。

  • 使用 nm 工具检查库中的符号。

3. 符号可见性

在跨平台开发时,确保导出的符号具有适当的可见性。使用宏来控制符号导出,如前文所述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值