g++制作C++动态库的简洁例程

g++制作C++动态库的简洁例程

在这里插入图片描述

code review!

文章目录

  • g\++制作C++动态库的简洁例程
    • 1. 创建 C++ 动态库
      • 1.1 动态库源文件
      • 1.2 编译动态库
    • 2. 使用动态库
      • 2.1 命令行编译链接然后运行
      • 2.2 使用 CMake 编译链接然后运行
    • 3.附加笔记:关于运行时是否能找到libmylib.so的问题汇总
      • 3.1.`g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib `详解
        • 命令详解
          • 1. `g++`
          • 2. `-L.`
          • 3. `-Wl,-rpath=.`
          • 4. `-o main`
          • 5. `main.cpp`
          • 6. `-lmylib`
        • 总结
        • 为什么需要这些选项
      • 3.2.`g++ -o main main.cpp -lmylib`直接这样可以编译成功吗?
        • 具体情况分析
          • 1. 默认库路径
          • 2. 当前目录下的库文件
        • 推荐的命令
      • 3.3.`g++ -o main main.cpp -L. -lmylib`直接这样可以编译成功吗?
        • 命令详解
        • 编译阶段
        • 运行阶段
        • 解决方法
        • 推荐的命令
      • 3.4.通过cmake编译,运行时不需要先`export LD_LIBRARY_PATH=.`,直接`./main`可以运行成功吗?
        • 主要问题
        • 解决方法
        • 修改后的 `CMakeLists.txt`
        • 步骤
        • 解释
    • 4.补充笔记:创建一个包含类的C++动态库,并分别使用命令行和CMake进行编译、链接和运行
      • 4.1. 创建C++动态库
        • 4.1.1 文件结构
        • 4.1.2 MyClass.h
        • 4.1.3 MyClass.cpp
        • 4.1.4 main.cpp
      • 4.2. 使用命令行编译和链接
        • 4.2.1 编译动态库
        • 4.2.2 编译主程序并链接动态库
        • 4.2.3 运行主程序
      • 4.3. 使用CMake编译和链接
        • 4.3.1 创建CMakeLists.txt
        • 4.3.2 编译项目
        • 4.3.3 运行主程序

下面是一个使用 g++ 制作 C++ 动态库的完整简洁例子,并展示了如何通过命令行和 CMake 使用该动态库。

1. 创建 C++ 动态库

1.1 动态库源文件

首先,我们创建一个简单的 C++ 动态库。假设我们有一个库文件 mylib.cpp

// mylib.cpp
#include <iostream>

void say_hello() {
    std::cout << "Hello, world!" << std::endl;
}

对应的头文件 mylib.h

// mylib.h
#ifndef MYLIB_H
#define MYLIB_H

void say_hello();

#endif // MYLIB_H

1.2 编译动态库

使用 g++ 编译并创建动态库 libmylib.so

g++ -shared -fPIC -o libmylib.so mylib.cpp

2. 使用动态库

2.1 命令行编译链接然后运行

首先,创建一个使用该库的应用程序 main.cpp

// main.cpp
#include "mylib.h"

int main() {
    say_hello();
    return 0;
}

编译并链接应用程序:

g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib

运行应用程序:

./main

2.2 使用 CMake 编译链接然后运行

首先,创建一个 CMake 项目文件 CMakeLists.txt

# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyApp)

# 添加库的路径
link_directories(${CMAKE_SOURCE_DIR})

# 添加头文件路径
include_directories(${CMAKE_SOURCE_DIR})

# 添加可执行文件
add_executable(main main.cpp)

# 链接动态库
target_link_libraries(main mylib)

然后,在项目目录下创建 main.cpp

// main.cpp
#include "mylib.h"

int main() {
    say_hello();
    return 0;
}

编译并运行应用程序:

# 创建构建目录
mkdir build
cd build

# 运行 CMake 配置
cmake ..

# 编译项目
make

# 运行应用程序
./main

3.附加笔记:关于运行时是否能找到libmylib.so的问题汇总

3.1.g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib 详解

下面是对命令 g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib 的详细解释:

命令详解
g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib
1. g++

g++ 是 GNU 编译器集合(GCC)中用于编译 C++ 代码的编译器。

2. -L.

-L 选项指定链接器搜索库文件的目录。. 表示当前目录。这意味着链接器将在当前目录中查找库文件。

3. -Wl,-rpath=.

-Wl 选项将参数传递给链接器(ld)。-rpath 选项指定运行时库搜索路径。. 表示当前目录。这意味着在运行时,程序会在当前目录中查找动态库。

4. -o main

-o 选项指定输出文件的名称。在这个例子中,输出文件名为 main,即生成的可执行文件名为 main

5. main.cpp

这是源文件的名称,包含 main 函数。在这个例子中,main.cpp 是要编译的源文件。

6. -lmylib

-l 选项用于指定要链接的库。mylib 是库的名称,链接器会寻找名为 libmylib.so 的动态库文件进行链接。

总结

综上所述,这个命令的作用是:

  1. 使用 g++ 编译 main.cpp
  2. 在当前目录中搜索库文件(-L.)。
  3. 在生成的可执行文件中指定运行时库搜索路径为当前目录(-Wl,-rpath=.)。
  4. 输出文件名为 main-o main)。
  5. 链接名为 libmylib.so 的动态库(-lmylib)。
为什么需要这些选项
  • -L.-lmylib:确保编译器能够找到并链接 libmylib.so 动态库。
  • -Wl,-rpath=.:确保生成的可执行文件在运行时能够找到并加载 libmylib.so 动态库。运行时库路径指定为当前目录,这对于开发和测试环境很有用,但在生产环境中通常会使用更安全和标准的库路径。

通过这些选项,确保了在编译和运行时都能正确找到和使用动态库。

3.2.g++ -o main main.cpp -lmylib直接这样可以编译成功吗?

g++ -o main main.cpp -lmylib 这个命令在某些情况下可能会编译成功,但通常还需要指定库文件的搜索路径以及运行时库路径,特别是在使用自定义库(如当前目录下的 libmylib.so)时。

具体情况分析
1. 默认库路径

如果 libmylib.so 位于系统的默认库路径(例如 /usr/lib/usr/local/lib),那么这个命令可能会成功,因为链接器能够自动找到库文件。

2. 当前目录下的库文件

如果 libmylib.so 位于当前目录,则需要显式告诉链接器在哪里查找库文件,以及在运行时如何找到动态库。为了确保编译和运行成功,建议使用以下更完整的命令:

推荐的命令
g++ -L. -Wl,-rpath=. -o main main.cpp -lmylib

这条命令确保了编译器和运行时都能正确找到库文件。具体解释如下:

  • -L.:指定链接器在当前目录查找库文件。
  • -Wl,-rpath=.:告诉运行时加载器在当前目录查找动态库。
  • -o main:指定生成的可执行文件名为 main
  • main.cpp:要编译的源文件。
  • -lmylib:指定要链接的库 libmylib.so

虽然 g++ -o main main.cpp -lmylib 在某些特定情况下可能会成功,但通常需要指定库文件的搜索路径和运行时路径,以确保编译和运行时都能正确找到库文件。推荐使用更完整的命令来避免潜在的问题。

3.3.g++ -o main main.cpp -L. -lmylib直接这样可以编译成功吗?

g++ -o main main.cpp -L. -lmylib 这个命令可以在编译阶段成功,但在运行时可能会遇到问题,特别是如果 libmylib.so 位于当前目录且未包含在系统默认的库路径中。

命令详解
g++ -o main main.cpp -L. -lmylib
  • g++:使用 GNU 编译器编译 C++ 代码。
  • -o main:指定输出文件的名称为 main
  • main.cpp:要编译的源文件。
  • -L.:指定链接器在当前目录查找库文件。
  • -lmylib:指定要链接的库 libmylib.so
编译阶段

在编译阶段,这个命令会成功,因为 -L. 告诉链接器在当前目录查找库文件 libmylib.so

运行阶段

在运行阶段,生成的可执行文件需要找到并加载 libmylib.so。如果 libmylib.so 不在系统默认的库路径中(例如 /usr/lib/usr/local/lib),运行时会出现类似以下错误:

./main: error while loading shared libraries: libmylib.so: cannot open shared object file: No such file or directory
解决方法

为了在运行时能够找到 libmylib.so,有几种方法:

  1. 使用 LD_LIBRARY_PATH 环境变量

    在运行程序之前,将当前目录添加到 LD_LIBRARY_PATH 环境变量:

    export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
    ./main
    
  2. 使用 -Wl,-rpath 链接选项

    在编译时指定运行时库路径:

    g++ -o main main.cpp -L. -lmylib -Wl,-rpath=.
    
  3. 将库文件移动到系统默认库路径

    libmylib.so 移动到系统默认的库路径,如 /usr/lib/usr/local/lib,并运行 ldconfig 来更新库缓存。

推荐的命令

为了确保编译和运行都能顺利进行,推荐使用以下命令:

g++ -o main main.cpp -L. -lmylib -Wl,-rpath=.

虽然 g++ -o main main.cpp -L. -lmylib 可以在编译阶段成功,但为了确保在运行时也能找到动态库,建议使用 -Wl,-rpath=. 链接选项,或者在运行时设置 LD_LIBRARY_PATH 环境变量。

3.4.通过cmake编译,运行时不需要先export LD_LIBRARY_PATH=.,直接./main可以运行成功吗?

直接使用提供的 CMakeLists.txt 文件,生成的可执行文件 main 在运行时是否需要设置 LD_LIBRARY_PATH 环境变量,取决于系统和 CMake 的配置。

主要问题

默认情况下,CMake 生成的可执行文件并不会自动包含运行时库路径(rpath)。因此,如果 libmylib.so 不在系统默认的库路径中,运行时会找不到这个库,导致无法运行。

解决方法

为了确保生成的可执行文件可以在运行时找到 libmylib.so,需要在 CMakeLists.txt 中显式设置 rpath

修改后的 CMakeLists.txt

可以修改 CMakeLists.txt 文件来包含运行时库路径信息。以下是修改后的版本:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(MyApp)

# 添加库的路径
link_directories(${CMAKE_SOURCE_DIR})

# 添加头文件路径
include_directories(${CMAKE_SOURCE_DIR})

# 添加可执行文件
add_executable(main main.cpp)

# 链接动态库
target_link_libraries(main mylib)

# 设置运行时库路径(rpath)
set_target_properties(main PROPERTIES
    BUILD_RPATH "${CMAKE_SOURCE_DIR}"
    INSTALL_RPATH "${CMAKE_SOURCE_DIR}"
    INSTALL_RPATH_USE_LINK_PATH TRUE
)
步骤
  1. 创建构建目录并进入

    mkdir build
    cd build
    
  2. 运行 CMake 配置

    cmake ..
    
  3. 编译项目

    make
    
  4. 运行应用程序

    ./main
    
解释
  • set_target_properties:为目标 main 设置属性。
    • BUILD_RPATH:设置构建时的 rpath,即在编译生成的可执行文件中包含的库路径。
    • INSTALL_RPATH:设置安装时的 rpath,对于这个示例,设置与 BUILD_RPATH 相同。
    • INSTALL_RPATH_USE_LINK_PATH:确保安装时使用链接路径。

通过这种方式,生成的可执行文件将包含运行时库路径信息,不需要在运行时设置 LD_LIBRARY_PATH 环境变量,直接运行 ./main 即可找到并加载 libmylib.so

通过在 CMakeLists.txt 中设置 rpath,可以确保生成的可执行文件在运行时能够找到所需的动态库,不需要额外设置 LD_LIBRARY_PATH 环境变量。这种方法对于开发和测试环境非常方便。

4.补充笔记:创建一个包含类的C++动态库,并分别使用命令行和CMake进行编译、链接和运行

4.1. 创建C++动态库

4.1.1 文件结构
├── MyLibrary
│   ├── MyClass.h
│   └── MyClass.cpp
├── main.cpp
├── build (编译输出目录)
4.1.2 MyClass.h
// MyClass.h

#ifndef MYCLASS_H
#define MYCLASS_H

class MyClass {
public:
    MyClass();
    void sayHello();
};

#endif // MYCLASS_H
4.1.3 MyClass.cpp
// MyClass.cpp

#include "MyClass.h"
#include <iostream>

MyClass::MyClass() {}

void MyClass::sayHello() {
    std::cout << "Hello from MyClass!" << std::endl;
}
4.1.4 main.cpp
// main.cpp

#include "MyClass.h"

int main() {
    MyClass myClass;
    myClass.sayHello();
    return 0;
}

4.2. 使用命令行编译和链接

4.2.1 编译动态库
g++ -fPIC -shared -o build/libMyClass.so MyLibrary/MyClass.cpp
4.2.2 编译主程序并链接动态库
g++ -o build/main main.cpp -Lbuild -lMyClass
4.2.3 运行主程序
LD_LIBRARY_PATH=build ./build/main

4.3. 使用CMake编译和链接

4.3.1 创建CMakeLists.txt

在项目根目录下创建 CMakeLists.txt 文件。

cmake_minimum_required(VERSION 3.10)
project(MyProject)

# 设置C++版本
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 添加库
add_library(MyClass SHARED MyLibrary/MyClass.cpp)

# 添加可执行文件
add_executable(main main.cpp)

# 链接库
target_link_libraries(main MyClass)
4.3.2 编译项目
mkdir -p build
cd build
cmake ..
make
4.3.3 运行主程序
LD_LIBRARY_PATH=. ./main

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/737391.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TLS握手中的RTT

文章目录 TLS 1.2 握手过程中的 RTT 次数TLS 1.3 1-RTT 初次TLS1.3 0-RTT 握手过程总结 TLS 1.2 握手过程中的 RTT 次数 TLS 1.2 握手通常需要2 RTT 才能完成。具体步骤如下&#xff1a; 第一次 RTT&#xff1a; 客户端发送 ClientHello&#xff1a;客户端生成一个随机数&…

【离散数学】图的随机生成和欧拉(回)路的确定(c语言实现)

实验要求 变量定义 因为如果我们使用局部变量&#xff0c;每一个函数都会使用这些变量&#xff0c;会让函数的参数越变越多。所以我们定义全局变量&#xff0c;这样就不用在参数中调用了。 #define MAX 100 int arrMap[MAX][MAX] { 0 };//图的矩阵 int degree[MAX] { 0 };…

GEO数据挖掘-富集分析、TinyArray简化流程、多组样本分析more

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 富集分析一些理论知识具体代码 富集不到的补救措施更多资料---问题数据和常见错误分析Part4-复杂数据及其分析多分组数据分析流程 tinyarray简化版本分析流程多分组…

ROS机器人虚拟仿真挑战赛持续学习笔记-20240619

cartographer 需要全手工编译……比较麻烦。 如果使用新版ceres-solver&#xff0c;版本2.x&#xff0c;需要修改源码&#xff0c;部分“接口代码”有改动。 稳妥使用ceres-solver-1.13.0&#xff0c;且需要安装abseil-cpp。 验证是否成功&#xff0c;使用roscd或roslaunch…

C语言| 数组元素的删除

同数组元素的插入差不多。 数组元素的插入&#xff0c;是先移动要插入元素位置后面的所有元素&#xff0c;再插入新元素&#xff0c;长度1。 C语言| 数组的插入-CSDN博客 数组元素的删除&#xff0c;是先删除元素&#xff0c;再把后面的元素往前移动一位&#xff0c;而本程序…

三国之家网站的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;论坛管理&#xff0c;公告管理&#xff0c;三国视频管理&#xff0c;基础数据管理&#xff0c;三国图文管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#…

2.树莓派4b+ubuntu18.04(ros版本melodic)+arduino mega自制两轮差速小车,实现建图导航功能

这篇文章介绍arduino使用和安装arduino_bridge 将arduino与树莓派连接 查看arduino的端口号&#xff0c;我们这里查看到的时ttyUSB0 ll /dev/ttyUSB*将当前用户添加进dialout组 sudo usermod -a -G dialout your_user_name然后重启树莓派&#xff0c;然后才能生效 然后如果你…

“Driver not loaded“问题解决方案

这两天又碰到了离谱的&#xff0c;愚蠢的&#xff0c;莫名其妙的&#xff0c;丧尽天良的错误。 之前已经解决过这个问题。这几天又碰上了&#xff0c;明明都已经把相应的dll放到了exe的同级目录&#xff0c;NND还是有问题&#xff01;&#xff01;&#xff01;卡了我一个晚上加…

Linux C/C++ socket函数

目录 socket函数 函数原型 头文件 功能 返回值 参数 错误码 socket函数 函数原型 int socket(int domain, int type, int protocol); 头文件 #include <sys/types.h> #include <sys/socket.h> 功能 创建一个用于通信的端点&#xff0c;并返回一个文件描述符…

tensorRT C++使用pt转engine模型进行推理

目录 1. 前言2. 模型转换3. 修改Binding4. 修改后处理 1. 前言 本文不讲tensorRT的推理流程&#xff0c;因为这种文章很多&#xff0c;这里着重讲从标准yolov5的tensort推理代码&#xff08;模型转pt->wts->engine&#xff09;改造成TPH-yolov5&#xff08;pt->onnx-…

Linux - 探秘 Linux 的 /proc/sys/vm 常见核心配置

文章目录 PreLinux 的 /proc/sys/vm 简述什么是 /proc/sys/vm&#xff1f;主要的配置文件及其用途参数调整对系统的影响dirty_background_ratio 和 dirty_ratioswappinessovercommit_memory 和 overcommit_ratiomin_free_kbytes 实例与使用建议调整 swappiness设置 min_free_kb…

6.XSS-钓鱼攻击展示(存储型xss)

xss钓鱼演示 钓鱼攻击利用页面 D:\phpStudy\WWW\pikachu\pkxss\xfish 修改配置文件里面对应自己的入侵者的IP地址或者域名&#xff0c;对应的路径下的fish.php脚本如下&#xff1a; <?php error_reporting(0); // var_dump($_SERVER); if ((!isset($_SERVER[PHP_AUTH_USE…

分类预测 | Matlab实现GWO-CNN-SVM灰狼冰算法优化卷积支持向量机分类预测

分类预测 | Matlab实现GWO-CNN-SVM灰狼冰算法优化卷积支持向量机分类预测 目录 分类预测 | Matlab实现GWO-CNN-SVM灰狼冰算法优化卷积支持向量机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现GWO-CNN-SVM灰狼冰算法优化卷积支持向量机分类预测&…

嵌入式学习——数据结构(队列)——day50

1. 查找二叉树、搜索二叉树、平衡二叉树 2. 哈希表——人的身份证——哈希函数 3. 哈希冲突、哈希矛盾 4. 哈希代码 4.1 创建哈希表 4.2 5. 算法设计 5.1 正确性 5.2 可读性&#xff08;高内聚、低耦合&#xff09; 5.3 健壮性 5.4 高效率&#xff08;时间复杂度&am…

线程封装,互斥

文章目录 线程封装线程互斥加锁、解锁认识接口解决问题理解锁 线程封装 C/C代码混编引起的问题 此处pthread_create函数要求传入参数为void * func(void * )类型,按理来说ThreadRoutine满足,但是 这是在内类完成封装,所以ThreadRoutine函数实际是两个参数,第一个参数Thread* …

Python | Leetcode Python题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; class Solution:def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:n, m len(dungeon), len(dungeon[0])BIG 10**9dp [[BIG] * (m 1) for _ in range(n 1)]dp[n][m - 1] dp[n - 1][m] 1for i in range(n - 1, -1, …

Redis的实战常用一、验证码登录(解决session共享问题)(思路、意识)

一、基于session实现登录功能 第一步&#xff1a;发送验证码&#xff1a; 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff1a; 如果不合法&#xff0c;则要求用户重新输入手机号如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行…

C语言 | Leetcode C语言题解之第187题重复的DNA序列

题目&#xff1a; 题解&#xff1a; #define MAXSIZE 769/* 选取一个质数即可 */ typedef struct Node {char string[101];int index;struct Node *next; //保存链表表头 } List;typedef struct {List *hashHead[MAXSIZE];//定义哈希数组的大小 } MyHashMap;List * …

【百问大模型02】一文讲透RAG实战全解析

1.实时性无法更新&#xff0c;知识容易自相矛盾 2.大模型的缺点有哪些&#xff1f; 3.一个人的能力可以分为两种&#xff1a; 1&#xff09;大模型&#xff1a;推理能力&#xff0c;聪明&#xff0c;知识&#xff1b;很聪明但是缺少知识 2&#xff09;知识库&#xff1a;辅…

第一个Flask程序

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 一切准备就绪&#xff0c;现在我们开始编写第一个Flask程序&#xff0c;由于是第一个Flask程序&#xff0c;当然要从最简单的“Hello World&#xff…