C程序中让两个不同版本的库共存

发布时间:2020-10-03 15:43:20 作者:重归混沌
来源:网络 阅读:505

原文连接:http://blog.gotocoding.com/archives/875


今天有同学提出,如何在一个C程序中让两个不同版本的库共存。


首先想到的方案是,把其中一个版本的库函数全部重命名,比如把每一个函数名都加一个_v2的后缀。

人工替换到没什么,但是如果函数个数超过10个,就有点不拿人当人使了。


而使有工具去替换就会遇到一些棘手的问题,如何识别哪些是函数,哪些是系统函数(系统函数不需要添加后缀)等。


随后想到的另一个解决方案是C++的方案,为其中一个版本库中的所有文件添加命名空间。然后使用g++将这部分代码编译成.o文件,之后再使用gcc将这些.o文件与整个程序中的其他代码进行链接。


不过需要注意的是,g++编译后所有导出接口名都会变化得不那么直观。



第三种方案完全解决了以上两种方案的痛点。


考虑一个C语言的编译链接过程。


首先会将每个c文件编译成.o文件。


在编译过程中,导出函数并不会被实际分配地址,而是将函数名以F符号的方式存在.o文件的符号表中。


在本c文件调用的函数如果不存在于本文件,也会生成一个UND的符号存在.o文件的符号表中。


在链接过程中,链接器接收输入的.o文件,为每个.o文件中的符号分存地址,并生成可执行文件。


有了这几点事实,问题就变得的简单多了。


首先将其中一个版本的库中所有代码编译为.o文件。然后收集所有.o文件中的F符号。


由于整个库代码有内部依赖关系,收集到的F符号必然是所有.o文件中UND符号的超集。


换句话说,所有的F符号名就是我们要重命名的所有函数名。


这里我们需要借助objdump和objcopy工具。objdump -t 用于列表.o文件的符号表,objcopy用于重命名符号。


我随手写了一段用于过虑F符号的lua脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
--rename.lua
local list = {}
local reg = "([^%s]+)%s+([^%s]+)%s+([^%s]+)"..
        "%s+([^%s]+)%s+([^%s]+)%s+([^%s]+)"
for l in io.stdin:lines() do
        local a,b,c,d,e,f = string.match(l, reg)
        if a and c == "F" then
                list[#list + 1] = " --redefine-sym "
                list[#list + 1] = string.format("%s=%s_v2", f, f)
        end
end
print("#/bin/sh")
print("objcopy " .. table.concat(list) .. " $1")

我们可以使用如下命令来收集所有.o文件的F符号, 并产生修改符号所用的脚本

1
find . -name '*.o' | xargs objdump -t | ./lua rename > rename.sh

现在我们只需要再执行一条命令就可以把所有函数名增加一个_v2的后缀.

1
find . -name '*.o' | xargs -n 1 sh ./rename.sh

至此,我们这个版本的库代码的所有函数名已经全部增加了_v2后缀。

这些被处理过的.o文件与我们将所有.c代码中函数名重命名之后编译出的.o文件完全一等价。


8月2号补充:

在实际使用中发现, 局部函数(static 函数)符号有可能会被gcc做修饰,将被修饰的符号重命名会给我们带来一些麻烦,而我们原本也不需要去处理局部函数。


因此对rename.lua做如下修改,过虑掉非全局符号:

1
2
3
4
5
6
7
8
9
10
11
12
13
--rename.lua
local list = {}
local reg = "([^%s]+)%s+([^%s]+)%s+([^%s]+)"..
        "%s+([^%s]+)%s+([^%s]+)%s+([^%s]+)"
for l in io.stdin:lines() do
        local a,b,c,d,e,f = string.match(l, reg)
        if a and c == "F" and b == "g" then
                list[#list + 1] = " --redefine-sym "
                list[#list + 1] = string.format("%s=%s_v2", f, f)
        end
end
print("#/bin/sh")
print("objcopy " .. table.concat(list) .. " $1")


推荐阅读:
  1. SQLPS不同版本的差异
  2. jQuery中API、事件和多库共存是什么意思

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c lua compile

上一篇:解决使用Vue.js显示数据的时,页面闪现原始代码的问题

下一篇:云计算将迎来这六大主流趋势

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》