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_Hvoid 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 PROPERTIESBUILD_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_Hclass 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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32项目分享:智能窗帘系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.c…

浅析缓存技术

缓存技术的原理 缓存技术通过在内存中存储数据副本来加速数据访问。当应用程序需要数据时&#xff0c;首先检查缓存是否存在数据副本&#xff0c;如果有则直接返回&#xff0c;否则再从原始数据源获取。这种机制大大减少了访问时间&#xff0c;提升了系统的响应速度和整体性能。…

谷歌手机刷机教学

注意&#xff1a;手机已经解开了oem锁和bl 1、adb基础命令 连接设备adb devices&#xff1a;列出当前连接的所有设备。 adb connect <设备IP>&#xff1a;通过IP地址连接设备&#xff08;用于无线连接&#xff09;。 设备信息adb shell getprop&#xff1a;获取设备的所…

Linux使用——查看发行版本、内核、shell类型等基本命令

先做快照 虚拟机中编辑网络 关机 普通账户和管理员账户 互相对照 localhost相当于IP 参数: 短格式:以减号(-)开头&#xff0c;参数字母 长格式:以2个减号(--)后跟上完整的参数单词 当前发行版本 [rootserver ~]# cat /etc/redhat-release Red Hat Enterprise Linux release 9.…

Langchain实战:构建高效的知识问答系统

引言 知识问答系统&#xff08;KQA&#xff09;是自然语言处理领域的核心技术之一&#xff0c;它能够帮助用户从大量数据中快速准确地检索到所需信息。知识问答系统成为了帮助个人和企业快速获取、筛选和处理信息的重要工具。它们在很多领域都发挥着重要作用&#xff0c;例如在…

每日一练:攻防世界:5-1 MulTzor

一、XorTool 基于 XOR&#xff08;异或&#xff09;运算实现。它可以帮助您快速地对文本、二进制文件进行加密解密操作。 认识XorTool工具&#xff1a; 让我们先去认识一下工具&#xff1a; xortool.py 是基于 python 的脚本&#xff0c;用于完成一些 xor 分析&#xff0c;…

TCP与UDP_三次握手_四次挥手

TCP vs UDP TCP数据 具体可以通过Cisco Packet Tracer工具查看&#xff1a; UDP数据 三次握手、四次挥手 为什么是3/4次&#xff1f;这牵扯到单工、双工通信的问题 TCP建立连接&#xff1a;表白 TCP释放连接&#xff1a;分手 TCP—建立连接—三次握手 解释&#xff1a; 首先&…

CSS+JS:通过修改filter实现图片颜色随时间渐变

原理&#xff1a;修改filter的hue-rotate属性 效果&#xff1a; 代码: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…

7.系统工具——黑马程序员Java最新AI+若依框架项目

目录 前言一、表单构建任务&#xff1a;设计添加课程表单 二、 代码生成1.任务&#xff1a;将部门表在页面端显示改为树形结构 三、系统接口任务&#xff1a;使用sagger进行接口测试 前言 提示&#xff1a;本篇讲解若依框架 系统工具 一、表单构建 功能&#xff1a;完成前端…

《web程序设计》课程大作业,XX地旅游景点网站【IDEA下JSP(前后端)+MySQL技术】

背景&#xff1a; 《web程序设计》课程大作业要求 一、课程目标&#xff1a;课程教学目的是让学生能够全面了解和掌握目前国内比较流行的交互式网页制作的理论知识与开发技术&#xff0c;能开发制作出有一定实用性的交互式网站&#xff0c;为将来继续学习和就业打下坚实基础。…

Linux系统及常用命令介绍

一.介绍 Linux一套免费使用和自由传播的类Unix操作系统&#xff0c;是一个遵循POSIX的多用户、多任务、支持多线程和多CPU的操作系统。Linux系统的说明可以自行百度&#xff0c;知道这几点即可&#xff1a; 1.Linux中一切都是文件&#xff1b; 2.Linux是一款免费操作系统&…

水滴型粉碎机:饲料加工关键设备

在现代饲料加工行业中&#xff0c;高效、精准的加工设备对于提升饲料品质和产量至关重要。水滴型粉碎机作为一种实用的饲料加工设备&#xff0c;凭借其设计和性能&#xff0c;在饲料加工领域发挥着不可替代的作用。 一、水滴型粉碎机的设计特点 水滴型粉碎机采用了水滴型设计&a…

[图解]企业应用架构模式2024新译本讲解16-行数据入口2

1 00:00:00,750 --> 00:00:02,470 好&#xff0c;我们来看代码 2 00:00:03,430 --> 00:00:06,070 我们一步一步执行 3 00:00:42,500 --> 00:00:45,000 先初始化数据 4 00:00:52,300 --> 00:00:53,650 创建连接 5 00:00:55,900 --> 00:00:56,970 这里面 6 0…

帝国cms批量取消文章审核-把已审核的文章改成未审核的方法

帝国cms很多人采集的时候&#xff0c;把文章弄成了审核过的文章&#xff0c;或者因为其他的原因&#xff0c;文章都是审核通过&#xff0c;为了seo又不能把全部文章放出来&#xff0c;所以需要把文章弄成未审核以下就是解决本问题的办法 首先来修改后台列表文件&#xff0c;自…

【SPSS】基于RFM+Kmeans的电商客户价值聚类分析

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Node.js 是一个开源的 跨平台的JavaScript运行环境

https://www.npmjs.com/ 中央仓库 Visual Studio Code - Code Editing. Redefined https://openjsf.org/ OpenJS 促进了关键 JavaScript 技术在全球范围内的广泛采用和持续发展。 Apache服务器 Nginx服务器 Tomcat服务器 Node.js服务器 Gunicorn服务器 uW…

【第13章】进阶调试思路:如何安装复杂节点IP-Adapter?(安装/复杂报错/节点详情页/精读)ComfyUI基础入门教程

🎈背景 IP-Adapter这个名字,大家可能听说过,可以让生成的结果从参考图中学习人物、画风的一致性,在目前是比较实用的一个节点,广泛的用于照片绘制、电商作图等方面。 但同时,这个节点也是比较难安装的一个节点。 所以,这节课,我们就通过一个案例,来学习如何在Comf…

RX8025/INS5T8025实时时钟-国产兼容RS4TC8025

该模块是一个符合I2C总线接口的实时时钟&#xff0c;包括一个32.768 kHz的DTCXO。 除了提供日历&#xff08;年、月、日、日、时、分、秒&#xff09;功能和时钟计数器功能外&#xff0c;该模块还提供了大量其他功能&#xff0c;包括报警功能、唤醒定时器功能、时间更新中断功能…

Java | Leetcode Java题解之第188题买卖股票的最佳时机IV

题目&#xff1a; 题解&#xff1a; class Solution {public int maxProfit(int k, int[] prices) {if (prices.length 0) {return 0;}int n prices.length;k Math.min(k, n / 2);int[] buy new int[k 1];int[] sell new int[k 1];buy[0] -prices[0];sell[0] 0;for (…

windows安装docker

【Docker】掌握 Docker魔法&#xff1a;Windows 11 平台上的完美容器部署终极指南_win11安装docker-CSDN博客https://blog.csdn.net/joeyoj/article/details/136427362Windows安装使用Docker&#xff0c;方便你的开发和部署(DockerDesktop篇)_windows docker安装部署-CSDN博客h…