当前位置: 首页 > article >正文

C/C++ 模板与so

在Linux系统中,将相同的模板代码编译到两个不同的共享库(.so 文件)中是一种相对复杂的操作,通常并不推荐,因为这样做可能会导致符号冲突和二进制膨胀。然而,如果你确实有这样的需求,可以通过一些技巧来实现。

假设你有一个C++模板类 MyClass,并希望将其编译到两个不同的共享库中 libA.solibB.so。以下是实现这一目标的步骤:

  1. 创建模板类源代码

    创建一个头文件 MyClass.h,其中包含模板类的定义:

    // MyClass.h
    #ifndef MYCLASS_H
    #define MYCLASS_H
    
    template <typename T>
    class MyClass {
    public:
        MyClass(T value) : value_(value) {}
        T getValue() const { return value_; }
    
    private:
        T value_;
    };
    
    #endif // MYCLASS_H
    
  2. 创建源文件(可选)

    通常情况下,模板类的实现是放在头文件中的,因为模板实例化需要在编译时完成。但如果你有模板类的实现需要放在源文件中,你可以这样做:

    // MyClass.cpp (可选)
    #include "MyClass.h"
    
    // 如果模板实现复杂,可以放在这里(但通常不推荐)
    

    注意:如果你选择将实现放在源文件中,你需要确保每个使用模板的编译单元(即每个 .cpp 文件)都能看到模板定义,这通常意味着你需要将头文件包含在每个使用模板的 .cpp 文件中。

  3. 创建两个共享库

    为了创建两个不同的共享库,你需要两个独立的构建脚本(如 MakefileCMakeLists.txt)。

    Makefile 示例

    # Makefile for libA.so
    CC = g++
    CFLAGS = -fPIC -shared
    TARGET_A = libA.so
    
    all:
        $(CC) $(CFLAGS) -o $(TARGET_A) MyClass.h  # 注意:这里通常不需要MyClass.cpp,除非有非模板代码
    
    clean:
        rm -f $(TARGET_A)
    
    # Makefile for libB.so
    # 可以复制上面的Makefile,然后重命名变量
    CC = g++
    CFLAGS = -fPIC -shared
    TARGET_B = libB.so
    
    all:
        $(CC) $(CFLAGS) -o $(TARGET_B) MyClass.h
    
    clean:
        rm -f $(TARGET_B)
    

    注意:在创建共享库时,通常不需要 .cpp 文件,因为模板类在头文件中实例化。

  4. 编译共享库

    使用 make 命令编译两个共享库:

    make -f Makefile_for_libA  # 假设你将第一个Makefile命名为Makefile_for_libA
    make -f Makefile_for_libB  # 假设你将第二个Makefile命名为Makefile_for_libB
    
  5. 使用共享库

    在你的应用程序中,你可以链接并使用这两个共享库。但是,你需要确保模板实例化在链接时不会发生冲突。这通常意味着你需要在每个共享库和最终的应用程序中正确地管理模板的实例化。

    // main.cpp
    #include <iostream>
    #include "MyClass.h"
    
    int main() {
        MyClass<int> objA(42);
        std::cout << "Value from libA: " << objA.getValue() << std::endl;
    
        // 注意:这里我们假设libB中的MyClass实例化和使用是隔离的
        // 实际情况中,你可能需要更复杂的机制来避免符号冲突
        // 比如使用命名空间或者不同的模板参数
    
        return 0;
    }
    

    编译和链接你的应用程序:

    g++ main.cpp -o myApp -L. -lA -lB -Wl,-rpath,.
    
  6. 处理潜在的符号冲突

    如果你发现链接时出现符号冲突,你可能需要使用一些高级技术,如:

    • 命名空间:将模板类放在不同的命名空间中。
    • 模板参数修改:为两个库中的模板类使用不同的模板参数。
    • 编译器特性:利用编译器特性(如GCC的 visibility 属性)来控制符号的导出。

请注意,将相同的模板代码编译到两个不同的共享库中通常是不推荐的,因为这增加了二进制大小和潜在的维护复杂性。如果可能的话,考虑将模板类放在一个共享的、单独的库中,并由其他库和应用程序链接这个共享库。


http://www.kler.cn/a/391513.html

相关文章:

  • 如何在 CentOS 中生成 CSR
  • 查看APK的公钥,MD5信息
  • 深入浅出 OpenResty
  • Unity的四种数据持久化方式
  • 【数据结构学习笔记】19:跳表(Skip List)
  • DeepSeek-V3技术报告
  • elementUI input 禁止内容两端存在空格,或者是自动去除两端空格
  • springboot小型养猪场信息管理系统-计算机毕业设计源码48584
  • 【青牛科技】 GC6153——TMI8152 的不二之选,可应用于摇头机等产品中
  • 编译ffmpeg动态库时设置RPATH为$ORIGIN
  • Elasticsearch日志收集成功但是展示不出来????
  • webpack指南
  • Vue 简单入手
  • C++20 中最优雅的那个小特性 - Ranges
  • uni-app表单⑪
  • 【3D Slicer】的小白入门使用指南二
  • rust智能指针
  • ubuntu下openssl签名证书制作流程及验证demo
  • XML Schema 字符串数据类型
  • 干式电抗器的故障诊断和排除方法是什么?
  • 【大数据学习 | HBASE】hbase的写数据流程与hbase插入数据
  • Python教程笔记(1)
  • macOS sw_vers 查看当前系统版本
  • 【题解】—— LeetCode一周小结45
  • 光控资本:“自主可控”将进入新估值阶段
  • 【旷视科技-注册/登录安全分析报告】