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

news2024/10/6 12:31:58

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vite: 前端环境的基础搭建

Vite初始化前端项目 初始化 $ pnpm create viteLibrary/pnpm/store/v3/tmp/dlx-42133 | Progress: resolved 1, reused 0, downlLibrary/pnpm/store/v3/tmp/dlx-42133 | 1 Library/pnpm/store/v3/tmp/dlx-42133 | Progress: resolved 1, reused 0, downlLib…

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

题目&#xff1a; 题解&#xff1a; int maxProfit(int k, int* prices, int pricesSize) {int n pricesSize;if (n 0) {return 0;}k fmin(k, n / 2);int buy[k 1], sell[k 1];memset(buy, 0, sizeof(buy));memset(sell, 0, sizeof(sell));buy[0] -prices[0];sell[0] 0…

193.回溯算法:组合总和(力扣)

代码解决 class Solution { public:vector<int> res; // 当前组合的临时存储vector<vector<int>> result; // 存储所有符合条件的组合// 回溯函数void backtrcing(vector<int>& nums, int target, int flag, int index) {// 如果当前组合的和超过了…

如何下载油管视频

文章目录 1、IDM下载1.1 安装IDM工具1.2 浏览器安装IDM插件 2、命令行工具下载2.1 youtube-dl工具2.1.1 安装使用2.1.2 更新工具 2.2 yt-dlp 工具2.2.1 安装使用2.2.2 保存路径查看当前工作目录指定下载目录示例 2.2.3 保存文件名2.2.4 避坑指南1、请求被拒绝2、其他问题 在全球…

如何打包数据库文件

使用 mysqldump 命令&#xff1a; mysqldump -u username -p database_name > output_file.sql username 是数据库的用户名。database_name 是要导出的数据库名称。output_file.sql 是导出的 SQL 文件名&#xff0c;可以自定义。 示例&#xff1a; mysqldump -u root -p…

Ubuntu/Linux SSH 端口转发

文章目录 Ubuntu/Linux SSH 端口转发概述本地端口转发场景一场景二 参考资料 Ubuntu/Linux SSH 端口转发 概述 SSH, Secure Shell 是一种在网络上用于安全远程登录到另一台机器的工具。除了远程登录以外&#xff0c;ssh 的端口转发是它的另一项强大功能。通过 ssh 端口转发功…

[spring] Spring MVC Thymeleaf(下)

[spring] Spring MVC & Thymeleaf&#xff08;下&#xff09; 上篇笔记讲了一下怎么使用 thymeleaf 作为 HTML 模板&#xff0c;与 Spring MVC 进行沟通&#xff0c;这里主要说一下验证的部分 常用表单验证 一些 Spring MVC 内置的常用验证注解如下&#xff1a; Annota…

【深度学习】智能手写数字识别系统

文章目录 一&#xff0e;实验课题背景说明1.1实验目的1.2实验环境1.2.1安装PyTorch1.2.2安装其他必要的库 二&#xff0e;模型说明2.1模型概述2.2模型结构 三&#xff0e;数据说明3.1 输入数据3.1.1输入数据特征3.1.2输入数据维度3.1.3输入数据预处理 3.2 数据格式3.2.1输出数据…

两个方法,批量替换PPT中的字体

经常制作ppt的朋友可能会遇到需要批量替换字体的情况&#xff0c;如果我们想要更换ppt中的字体&#xff0c;今天分享PPT批量替换字体的两个方法。 方法一&#xff1a; 找到功能栏中的编辑选项卡&#xff0c;点击替换 – 替换字体&#xff0c;在里面选择我们想要替换的字体就可…

【因果推断python】51_去偏/正交机器学习3

目录 What is Non-Parametric About? What is Non-Parametric About? 在我们继续之前&#xff0c;我只想强调一个常见的误解。当我们考虑使用非参数 Double-ML 模型来估计 CATE 时&#xff0c;我们似乎会得到一个非线性治疗效果。例如&#xff0c;让我们假设一个非常简单的数…

LeetCode665.非递减数列

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路⌨C代码 &#x1f4dc;题目描述 给你一个长度为 n 的整数数组 nums &#xff0c;请你判断在 最多 改变 1 个元素的情况下&#xff0c;该数组能否变成一个非递减数列。 我们是这样定义一个非递减数列的&am…

昆明理工大学24计算机考研各专业复试线大幅下降,B区国家线即可复试!

昆明理工大学&#xff08;Kunming University of Science and Technology&#xff09;&#xff0c;位于云南省昆明市&#xff0c;是云南省综合性重点大学&#xff0c;由国防科技工业局与云南省人民政府共建高校&#xff0c;入选“中西部高校基础能力建设工程”、国家建设高水平…

第10关:视图1 、第11关:视图2 、第12关:用户。

目录 第10关&#xff1a;视图1 任务描述 知识补充 答案 第11关&#xff1a;视图2 任务描述 知识补充 答案 第12关&#xff1a;用户 任务描述 知识补充 答案 本篇博客声明&#xff1a;所有题的答案不在一起&#xff0c;可以去作者博客专栏寻找其它文章。 第10关&…

Phi-3 模型手机部署教程(微软发布的可与GPT-3.5媲美的小模型)

前面几篇博文&#xff0c;老牛同学和大家一起在个人电脑部署了Qwen2、GLM4、Llama3、ChatTTS和Stable Diffusion等 LLM 大模型&#xff0c;也通过 API 和 WebUI 的方式完成了体验。 但是这些大模型因为部署在个人电脑本地&#xff0c;不能够随时携带。如果能在手机上部署大模型…

EtherCAT笔记(三) —— 主站与从站的硬件组成

1. EtherCAT 主站的硬件组成 EtherCAT主站使用标准以太网控制器&#xff0c;也即EtherCAT主站可以使用以太网控制器的任何设备。当我们有一台带网口的笔记本、工控机&#xff0c;甚至是树莓派也可以作为EtherCAT主站。 EtherCAT协议是对Ethernet协议在实时控制等方面的优化&am…

一篇文章带你快速入门java

文章目录 一、一个简单的java代码1.1 Java程序的结构由三个不成组成&#xff1a;1.2 运行java程序1.3 JDK,JRE,JVM之间的关系&#xff1f;(面试题)1.4 标识符1.5 注释1.6 关键字 一、一个简单的java代码 public class HelloJava {public static void main(String[] args) {Sys…

【建议收藏】Android中高级大厂面试源码秘籍,为你备战2021金三银四,直通大厂

首先来说下为什么要读源码&#xff0c;有学习源码的必要吗&#xff1f; 为什么要阅读源码&#xff1f; 关于为什么阅读和学习源码&#xff0c;我个人认为可能有以下几点&#xff1a; &#xff08;一&#xff09;吊打面试官&#xff0c;应对面试 为了找到更好的工作&#xff…

Linux配置中文环境

文章目录 前言中文语言包中文输入法中文字体 前言 在Linux系统中修改为中文环境&#xff0c;通常涉及以下几个步骤&#xff1a; 中文语言包 更新源列表&#xff1a; 更新系统的软件源列表和语言环境设置&#xff0c;确保可以安装所需的语言包。 sudo apt update sudo apt ins…

Python+Pytest+Yaml+Request+Allure框架源代码之(一)common公共方法封装

common模块&#xff1a; get_path.py&#xff1a;获取路径方法 # -*- coding: UTF-8 -*- import os# 项目根目录 BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__)))# 配置文件目录 CONFIG_DIR os.path.join(BASE_DIR,config)# 测试用例文件目录 TESTCA…

康奈尔大学之论文审稿模型Reviewer2及我司七月对其的实现(含PeerRead)

前言 自从我司于23年7月开始涉足论文审稿领域之后「截止到24年6月份&#xff0c;我司的七月论文审稿GPT已经迭代到了第五版&#xff0c;详见此文的8.1 七月论文审稿GPT(从第1版到第5版)」&#xff0c;在业界的影响力越来越大&#xff0c;所以身边朋友如发现业界有相似的工作&a…