工作拆分so总结

拆分SO中遇到的问题:

1、APP_STL := c++_static,得改为 c++_shared

每个 so 都独立包含一份 C++ 运行时:

c++_static 会将 LLVM libc++ 的静态库(libc++_static.a)完整地链接到每一个生成的 .so 文件中。假设你有 libA.solibB.so,它们各自都包含了一份相同的 C++ 运行时代码。

重复的全局状态:

C++ 运行时中有一些关键全局状态,例如:

异常处理表(unwinding tables)

堆内存分配器(new/delete)

类型信息(RTTI)

具体崩溃场景:

1.跨 so 抛异常:在 libA.so 中抛出一个异常,希望在 libB.so 中捕获。由于两个 so 使用不同的异常处理表,捕获会失败,通常导致 std::terminate 或直接崩溃。

2.跨 so 分配/释放内存:在 libA.so 中用 new 分配内存,在 libB.so 中用 delete 释放。因为每个 so 有自己的堆管理,可能导致堆损坏或内存泄漏。

比如说在常用特殊功能中,我在子so中new分配内容,把它给特殊功能的so用智能指针保管

子 SO 中的 new 调用的是子 SO 自己那份 operator new,它从子 SO 的堆(可能是通过 malloc 封装的独立)分配内存。

主 SO 中的 std::shared_ptr 析构时调用 delete,调用的是主 SO 自己那份 operator delete,它会去主 SO 的堆释放内存。

这两个堆是不同的,甚至可能使用了不同的内存分配器实现。在一个堆分配、另一个堆释放是绝对禁止的,后果包括:堆元数据损坏

双重释放或释放未分配地址

立即崩溃(如 SIGSEGV 或 malloc: *** error for object ...)

3.动态类型检查失败:dynamic_cast 或 typeid 跨 so 使用时,RTTI 比较会失败(即使同一个类在不同 so 中被视为不同类型)。

4.增大包体积:每个 so 都多了一份运行时库代码,总大小显著增加。

2、代码拆分,之前所有的代码都在一起虽然分了不同的cpp文件,但是都是同一个类,同一个头文件;

拆分代码按照类别 定义不同的类,都继承与CSpBase类(包含了 公用方法等);

若是不拆分的做法

switch (HotSpType)

{

case enum_OilReset:

m_pHotSpFunction = make_shared<CNissanHotSp_01_OilReset>();

break;

case enum_BMS:

m_pHotSpFunction = make_shared<CNissanHotSp_02_BMS>();

break;

} 随后初始化指针,随后若是 点击功能后再根据功能ID划分,子类重写

这样的话就每个子类都要重写函数,直接定义在基类,子类在构造函数中调用 RegisterFunction 来注册自己;

template<typename ClassType>

void RegisterFunction(const string& funcName,

const ErrorCode_t(ClassType::* memFunc)(string&) const,

ClassType* pThis) {

m_mapFuncAddr[funcName] = [pThis, memFunc](string& arg) -> ErrorCode_t {

return (pThis->*memFunc)(arg);

};

}

还可以更进一步

class Base {

protected:

map<string, function<ErrorCode_t(string&)>> m_mapFuncAddr;

public:

void RegisterFunction(const string& name, function<ErrorCode_t(string&)> func) {

m_mapFuncAddr[name] = move(func);

}

};

class Derived : public Base {

public:

Derived() {

RegisterFunction("process", [this](string& arg) {

return this->Process(arg); // Process 可以是任意签名,只要返回值能转为 ErrorCode_t

});

}

ErrorCode_t Process(string& arg) const { /*...*/ }

};

使用 function 去除模板化

3、按照功能来导出so、各so都导出接口

EXPORT_SYMBOL void Lib_ReadVersion(void* pSysEnter, const char* strEcuName, const char** ppVecID, int nIDCount);

extern "C" {

void Lib_ReadVersion(void* pSysEnter, const char* strEcuName, const char** ppVecID, int nIDCount) {

// 转换参数

string ecuName = strEcuName ? strEcuName : "";

vector<string> vecIDs;

for (int i = 0; i < nIDCount; ++i) {

vecIDs.push_back(ppVecID[i]);

}

TopDon_AD900_Nissan::CInformation information;

information.SetSysEnterPointer((TopDon_AD900_Nissan::CEnterSys*)pSysEnter);

information.ReadVersion(ecuName, vecIDs);

}

}

给外边So调用;

4、通用的接口、单列类、以及so资源管理类、如何跨so调用问题;

因为默认的情况下只会将本地的主so拷贝的工作目录。所以主so就不能链接其他的子so;但是不能每个so都包含通用接口的文件、资源管理文件、

更何况它还是单列的,全局唯一;

想法一、将这些公用的都变成一个so 名为 Comm.so,其他的子so都链接它,在主程序运行的时候将单列类的地址传递给子so,以及资源管理对象的地址也传递过去。

想法二、主so只包含mian函数,再重新定义一个主流程so,比如Nissan.so并暴露出主流程接口,mian函数当中将Comm.so拷贝到工作目录并打开,

这样所有的so都可以链接Comm.so,及所有内容都唯一了。

相关推荐
88号技师1 小时前
2026年2月新锐一区SCI-完整家庭互动优化算法Undivided Family Interaction Algorithm-附Matlab免费代码
开发语言·算法·数学建模·matlab·优化算法
手揽回忆怎么睡1 小时前
java打包无效的发行版:xx,临时修复当前窗口指定 JDK21
java·开发语言
zh1570231 小时前
c++ 零知识证明库 c++如何使用bellman或libsnark
jvm·数据库·python
2401_898717661 小时前
mysql如何利用cron定时备份_mysql自动化配置说明
jvm·数据库·python
李日灐1 小时前
【优选算法5】位运算经典算法面试题
后端·算法·面试·位运算
zhoutongsheng1 小时前
SQL利用子查询实现复杂条件排序_嵌套逻辑实现业务规则
jvm·数据库·python
汉克老师1 小时前
GESP5级C++考试语法知识(十四、分治算法(一))
算法·归并排序·排序·分治算法·gesp5级·gesp五级
一直有一个ac的梦想1 小时前
cmu15445 2025fall lec15 query optimiaztion Pt1
java·服务器·数据库
郝学胜-神的一滴1 小时前
干货版《算法导论》03:动态数组 × 链表的极致平衡艺术
java·数据结构·c++·python·算法·链表