C_and_CPP 板


LINE

※ 引述《lovejomi (JOMI)》之铭言: : 询问一个撰写c++ shared library (.so) 给 client使用的问题 : 看到一份code, .so 的header 提供的api prototype是长这样 : std::unique_ptr<Foo> CreateFoo(); : 这很明显的是 : allocate的动作在lib里面 : deallocate的人一定在caller那端也就是client code : a. 这是不是一个很不正确的design? : 基於一个观念 : 不该把new跟delete的动作, 在不同library间执行 : 之前观念是因为heap是独立的, 所以会出问题 下面再讲 new/delete 和 heap 独立的问题.. 通常不会在 API 设计上绑死 object 是怎麽 allocate, 这样会限缩以後 改变 memory management 的弹性.例如有些 runtime engine 会用自已的 memory pool, 不管中间有什麽 leak, 反正在 release runtime engine 後都就整个 pool 合收 但这样不代表就不能用 unique_ptr. unique_ptr 只是提供 "自动" 呼叫 deletor 的方式, 但 deletor 还是会由你的 library 提供 foo *fp = createFoo(); releaseFoo(fp); vs. using foo_ptr = unique_ptr<foo, void(*)(foo*)>; foo_ptr createFoo() { return foo_ptr(createFooInternal(), releaseFoo); } foo_ptr fp = createFoo(); 然後没人用 fp 时帮你呼叫 releaseFoo(fp); 那不是大同小异吗? : b. 但这观念是不是只有windows上才有呢? 不确定 : 以下连结也只提到dll : https://stackoverflow.com/questions/443147/c-mix-new-delete-between-libs 跟 e. 一起回答 会有这个问题是因为 Windows DLL 和 Linux Shared Object 的 binding 时机不同 要 call 什麽 function, 在编 DLL 就决定了, 但对 shared object, 是在 runtime 才决定 (可以改这个行为, 但我们以下都以预设的行为讨论) 想一下有段 code executable: main.c libfoo.so: foo.c ______________________________________ _________________________________ 1 #include <stdio.h> │ 1 #include <stdio.h> 2 │ 2 3 int g = 1000; │ 3 int g = 2000; 4 │ 4 5 void foo() { │ 5 void foo () { 6 printf ("main: foo %d\n", g); │ 6 printf ("foo: foo %d\n", g); 7 } │ 7 } 8 │ 8 9 void g_plus_plus(); │ 9 void g_plus_plus() { 10 void bar(); │ 10 g++; 11 │ 11 } 12 int main () { │ 12 13 foo(); │ 13 void bar() { 14 g_plus_plus(); │ 14 foo(); 15 bar(); │ 15 } 16 } │ a.out 和 libfoo.so 都有提供 g 变数, 和 foo function, 那这段 code 会印出什麽结果? 在 Linux, 会印出 main: foo 1000 main: foo 1001 但在 Windows 会印出 main: foo 1000 foo: foo 2001 因编译 DLL 时就决定 DLL 要使用 foo.c 里的 definition 但 SO 在 runtime 决定要哪一个本版 Linux (或 FreeBSD 等) 基本上是走 System V Application Binary Interface http://www.sco.com/developers/gabi/latest/ch5.dynamic.html 看 Shared Object Dependencies 那一节 细节有点复杂, 不过可以想成, runtime 时才决定 symbol 是哪本版本, 整个程式, 主程式本身和连带的 SO 都会使用同一个版本, 若 executable 本身和 SO 都有提供, 以 executable 为主. 这样的规范其实会让 static link archive library 和 dynamic link so 时 的结果一样 (当然 function / data 要切分到不同的 object file 避免 redefinition 的问题) 打太久差点忘了为什麽要写这段 orz 所以在 Windows, 有分 single/multi-thread * debug/release 四种 vc runtime .exe 和 .dll 用不同的 config 编会连到不同的版本, 两边会搭不起来 但 Linux 不会有这个问题 shared object 可以用 static, visilibity attribute, 或 linker 的 -Bsymbolic 等来达到类似 DLL 的行为, 但 DLL 应该是没办法做到 SO 这样的行为 (至少我不知道做法) : 针对这件事 我并没有明确的google到有什麽guideline提到该怎麽设计 : 如果是以我经验来说 : 多半是 : Foo* Create() 搭配 void Release(Foo*) : 但这感觉比较偏向C, 而这样好像也限制client端得到这个Foo*後无法用smart pointer去 : hold. : 所以以我的想法会觉得 : 回传 : weak_ptr<Foo> or shared_ptr<Foo> Create(); 给client : 然後Create函数里面实作的时候使用一个global之类的container, : 把这sp记录起来确保 .so是最後一个去delete他的人 : 但这边衍伸一个疑问 : c. a.exe + b.so 使用load time dynamic link的话, : a.exe还是b.so的global变数会先开始解构? : 如果是使用 run time dynamic link的话 基本上 destructor 是 constructor 倒过来的顺序 Linux 会用 .init/.init_array/.fini/.fini_array 做 global 的 constructor destructor load constructor, unload 时 destructor, a.exe 先, b.so 後, 同理 dlclose b.so 时做 destructor, exit a.exe 才 destrucor : d. 如果client用dlopen 然後dlsym拿到一个sp後 : 手动呼叫dlclose....这时候继续使用这个sp 是不是会有undefined的行为产生? : 就算没有人解构可是.so已经被close了? 好像没直接关系? 如果 so 里 new int(123) 传回去, 应该是不会怎样啦, 你是想问如果 object 的 code 在 so里吧? 我想是会炸掉, 不过为什麽好好的要 dlopen 东西 allocate 东西又再 dlclose 掉? : e. 不能在不同的library间 new delete这件事 是否是platform/compiler dependent? : 假设linux上如果我测试发现没有出问题 是否表示在这compiler/platform下 上面回了, 基本上是 platform ABI 决定的行为 compiler (整个 toolchain 和lib) 要配合 platform ABI : 100%不会发生问题 你这条件太强了 XD : 还是说"有可能" 不定时的出现问题 而不能马上当下发现立刻修正? : 因为目前使用那个shared library(return unique ptr)并没发生问题 : 会不会之後在某特定情况下突然出现问题呢? : 会有 lib 间 heap是独立的这件事 是gcc / vc实作决定的吗 还是更底层 OS实作? 我觉得独立 heap 是稻草人 orz : f. 以我的观念来看 如果是.a 的static lib, 是不是就完全没有design上特别的考量 : 不需要特别去因为写static library而有特别需要注意的地方? : g. 如果一个exe使用多个.so 而这些.so都用不同版本的gcc build出来的 : 这样如果他们expose的api 含有 stl的type : 是不是就是一个非常不好的design? 不同 gcc 可能会搭不且的 stl library 和 glibc, 混用会有问题 虽然 shared object 有 versioning 的基制, 但实际上还是会有遇一些问题 gcc 的 stl 应该也没有不同版本的实作完全相同, SO 和执行档如果会 pass object 给对方, 例如上面 unique_ptr 的 case, 有可能两边的 declaration 有差异而 runtime 才发现问题 : 如果我真的要使用这些不同版本的.so 是不是只能祈祷不会出事情而无法作解决? : 而这问题是不是只要这些.so用dynamic link libstdc++就没事了? : h. 有没有什麽网页有特别针对shared library的interface design 有提供guideline? : 想要稍微go through一下比较能掌握一些必要观念 最重要的这部份我好像没办法给建议 @@ 最去经验是 dynamic link 其实没有想像中的 protable, 蛮常遇到问题, 但如果你要 static link 又有到 dlopen 等 function, 那 link 时的 glibc 和执行的 glibc 要同一个版本, 不然会有问题. 这样 static link 其实没意义 在 Linux 要保证没问题最好还是要在执行环境重编 : 以上几个问题有点复杂 请教各位 : 非常感谢 --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.42.124.212
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1535034391.A.EEA.html
1F:推 ilikekotomi: 感谢分享 一直不知道dll和so有这种差别 08/24 00:24
2F:推 james732: 推 08/24 01:10
3F:→ cole945: 想了一下我a.讲的有点误导. create出来叫人家自已delete 08/24 09:05
4F:→ cole945: 的framework也少. 用的人通常自已决定要不要用uniq_ptr去 08/24 09:06
5F:→ cole945: 接. 但直接return uniq_ptr强迫人家用的自已经验没遇过 08/24 09:07
6F:→ cole945: > 第二推少了一个字 "不少" 08/24 09:07
7F:推 Bencrie: g 这样不会重复定义喔?@@a 08/24 09:40
8F:推 Bencrie: 试了一下 link so 还真的不会撞到 XD 08/24 09:47
9F:推 AstralBrain: 是个undefined behavior, no diagnostic required 08/24 10:04
10F:推 lovejomi: 看来要花时间吸收一下,谢谢 08/25 00:27
11F:→ lovejomi: 不过uniqueptr真的不能使用default deleter吗 08/25 00:28
12F:推 lovejomi: 我遇到 a.exe 使用vector<.so type> 然後.so 里面也使 08/25 00:32
13F:→ lovejomi: 用这种vector<type>..两者用不同版本编,link的时候出现 08/25 00:32
14F:→ lovejomi: warning possible ODR violation....是不是表示a.exe最 08/25 00:32
15F:→ lovejomi: 终可能是link到.so的vector实作,也可能是自己的vector 08/25 00:33
16F:→ lovejomi: 实作?决定权在linker? 08/25 00:33
17F:→ Killercat: namespace一样的话 对 08/28 22:34
18F:→ Killercat: 事实上严格讲起来是symbol symbol就是namespace+arg 08/28 22:37
19F:→ Killercat: 所以「symbol」一样的话 linker会直接吐error给你 08/28 22:37
20F:→ Killercat: 程式设计师的自我修养有相当详细的解释 08/28 22:38
21F:→ Killercat: 有点语意不清 其实symbol的话决定权并非linker, linker 08/28 22:38
22F:→ Killercat: 唯一能做的不是选择而是直接靠背出来 08/28 22:38
23F:→ cole945: 你说的.o link的情况,上面在说的是dynamic linking的情况 08/28 22:51
24F:→ cole945: 换个方法讲,这篇在讲的是loader处理module间symbol的问题 08/28 23:06
25F:→ cole945: 而你在说的是linker link单一module时的问题 08/28 23:06
26F:→ cole945: 如果说linker不用管选择symbol也太单纯化了,至少处理weak 08/28 23:07
27F:→ cole945: symbol就有影响了. 虽然我没认真读过程式设计师的自我修 08/28 23:10
28F:→ cole945: 不过我的工作是弄整个toolchain,不至於这个搞不清XD 08/28 23:12







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:iOS站内搜寻

TOP