1
learningman 2022-06-12 23:49:59 +08:00 via Android
那你总得给个理由吧
|
2
thewiredguy OP |
3
thewiredguy OP 比方说我用 go 调用 C++,我不想用 pkg-config ,我甚至想要把 C++ 的 .so 嵌入到我最后生成的 executable binary 里,有没有一种方式?别说用 Docker 容器什么的。
|
4
SMGdcAt4kPPQ 2022-06-13 00:25:56 +08:00
P/Invoke 请求一战
|
5
Buges 2022-06-13 00:36:25 +08:00 via Android
so 是动态库啊,一般是不能嵌入的, 虽然有一些魔改的 trick 能从内存中加载动态库,但那绝对不是正常做法。
正常来说你想要静态链接那就去构建静态链接库。 |
6
lysS 2022-06-13 00:42:21 +08:00
动态库是单独的文件,你需要的是静态库,本质就是 cgo 绑定 C 。
。。但是这些和垃圾回收有什么关系呢? |
7
SMGdcAt4kPPQ 2022-06-13 00:49:29 +08:00
@ComputerIdiot .NET 可以嵌入 Native Library 生成单文件,运行时释放 https://docs.microsoft.com/en-us/dotnet/core/deploying/single-file/overview#including-native-libraries
|
8
Suddoo 2022-06-13 01:49:53 +08:00
可以关注一下 巴拿马项目 https://github.com/openjdk/panama-foreign
|
9
akaHenry 2022-06-13 02:47:57 +08:00 10
你的感觉没错.
go 的 cgo, 本来就是个半残. 不建议使用. (早期 uber 等大量依赖 cgo 的, 应该都苦不堪言) 用到 cgo 的场景, 其实应该换语言了. 用 rust/c/c++ 配合 FFI 更合适. (微服务场景, 都是 RPC 抹平 业务单元差异) 不要被单一语言锁死. 适合谁, 谁上. 多学一门语言, 拓宽解决问题的思路. 最坏的就是 all-in-one 思想, 东施效颦, 各种捉急. |
11
Kasumi20 2022-06-13 10:21:28 +08:00
都不如 Rust
|
12
cccjh 2022-06-13 10:22:52 +08:00
公司同样的业务,封装底下自研的时序库的动态链接库,
早期 java 调用 jni ,后面改 jna , 我后面又用 go 去弄 cgo , 最后我又改成了 python 的 ctypes ,python 最终使用的上层用协程加 ctypes 接口处用多进程 这些全是我一个人弄的,其中整个体验下来,cgo 的体验是最差的,当你想用协程去调 cgo 时,结果可想而知。 |
13
akaHenry 2022-06-13 10:24:36 +08:00 1
@nmap
1. 如果是 Server 端, 可以通过 微服务 RPC(如 gRPC) / Restful API / Websoket 方式来调用. 避免侵入性. 把 C++ 改造成一个独立的服务. 暴露 RPC/Rest API 给 Go 调用. 即可以绕过 cgo. 2. 如果是 client 端, 如果用 Go 写 Client, 这本身已经是邪路. 那只能 cgo. 当然, 如果是 Desktop 桌面版的 app. 也可以同上, 把 桌面版 app 改造成 client/server 模型, 中间变成 proxy, 依然可以走 RPC/Rest API 方式调用. |
15
akaHenry 2022-06-13 10:34:55 +08:00 2
@cxytz01
github.com/hhstore/blog/issues/242 github.com/hhstore/blog/issues/355 可以参考我这 2 篇博客, 关于 FFI 的内容. https://en.wikipedia.org/wiki/Foreign_function_interface FFI 是通用的跨语言调用规范. 主流语言基本都兼容 C ABI. 所以, 都可以通过 C ABI 方式来跨语言通信. |
17
thewiredguy OP @lysS JNI 是 Java Native Interface ,不是垃圾回收
|
18
janxin 2022-06-13 11:01:02 +08:00
@orzglory 于是现在 uber 换 zig 做 cgo 后端了 233333
CGO 确实体验式最差的,并且尼玛死活没计划改... 不过你说的这个问题倒不是什么比较大的问题,想内嵌不过是 dynamic library loader 的问题...有很多第三方库可以用的 https://github.com/rainycape/dl |
19
akaHenry 2022-06-13 11:01:16 +08:00
@hhaobao
https://cloud.tencent.com/developer/article/1650525 https://dave.cheney.net/2016/01/18/cgo-is-not-go https://relistan.com/cgo-when-and-when-not-to-use-it 看这些讨论吧. 除了极端场景, 只有 c/c++ 的库, 需要 binding 给 go 使用. 才用 cgo. 而这个代价, 可能非常高. 即使要用, 请隔离在小服务内. 然后 RPC 暴露给其他服务. 不要污染整个大项目. 这是坨💩. 谁用谁知道. |
20
thewiredguy OP C++ 基本上没用过,只能先用 CGO ,回头再用 C++ 写服务了。
|
21
DefoliationM 2022-06-13 11:20:25 +08:00
@thewiredguy embed 打包到二进制里
|
22
lysS 2022-06-13 11:41:51 +08:00
@thewiredguy 喔,看叉屁了
|
23
hhaobao 2022-06-13 11:42:09 +08:00
@orzglory 谢谢, 这些我都知道的. 但我感觉还是说不通 cgo 是半残啊, 你有没有跟 jni 或者 python 调 c 的这些语言对比资料. 我学习一下其它语言在调 c 这块比 go 好在哪
|
24
icexin 2022-06-13 11:43:45 +08:00 10
跨语言调用 c 模块有其自身的复杂度在,不可能简单,也注定不是平凡的事情,任何语言都要面对。
主要有以下几个问题: 1. 包管理的差异,c 没有官方的包管理,所以库的管理完全看系统,或者团队的约定工具,如 cmake 等。go 其实可以跟 c 一起源码发布成一个 go 的包,见 https://github.com/mattn/go-sqlite3 2. 交叉编译,新的语言基本上都有很方便的交叉编译方案,甚至不需要(脚本语言)。而 c 的交叉编译工具链其实很复杂,搞过嵌入式或者搞过路由器的都知道我在说啥。 3. 数据类型的差异。这部分主要是内存布局的差异带来的。比如一个 c 的 struct 不一定对应着高级语言里面的一个 class 。go 在这一点上其实做的很好了,go 的一个 struct 基本上对应一个 c 的 struct 。指针的概念也跟几乎一致,除了算数运算。所以 cgo 几乎可以不加修改的直接引用 c 的头文件,以及传递 go struct 作为参数给 c 函数。 4. 内存管理的差异。c 是手动管理的内存,所有内存都要自己显式分配和释放。新的语言基本上都有自己的内存管理方案,即 GC 。这就带来了语言之间内存传递的问题,c 分配的内存不会被 go tracing ,go 的内存也不能被 c 手动释放,其他语言类似。 5. 并发模型的差异。这部分基本上是语言自带协程的独特问题。因为 go 里面的协程有自己的栈,而 c 基本上可以认为是操作系统的线程栈。这两者之间的差异会带来诸如 TLS 和栈切换的问题。 所以综合看来,除了第 5 点是 go 特有的,其他语言几乎都有类似的问题。go 引入 cgo 主要是为了解决复用已有的大量 c 库的遗产,不是和 c 无缝调用,混合编程,目前也就 c++做到了和 c 无缝衔接,但为了这个能力 c++也付出了很多代价,到现在还在打补丁。 软件工程没有银弹,作为工程师最主要的工作就是熟悉各个模块的脾性,对症下药,挑选最合适项目的方案,而不是强行套方案,最终不符合预期的时候骂骂咧咧。 |
25
zhuangzhuang1988 2022-06-13 11:44:24 +08:00
@ComputerIdiot 都不如.net 系, 就是关注度太低了
|
26
lysS 2022-06-13 11:56:01 +08:00
有头文件的时候 cgo 还行吧,中间可以自动生成 go 的类型、函数。而且 FFI 本来就属于是程序间的 api ,两个语言“揉得太碎”,肯定性能和代码可扩展性会受损
|
27
Nugine0 2022-06-13 12:18:33 +08:00 2
@icexin Rust/C++/Zig 都可以无缝调用 C 语言,都有无栈协程,手动(半自动?)管理内存,允许声明与 C 一致的内存布局。相比 C++,Rust/Zig 的包管理和交叉编译更方便。你说的这些问题在系统级编程语言中都有完善的解决方案。
|
28
Buges 2022-06-13 12:28:10 +08:00 via Android
@icexin cgo 我见到最多的诟病是开销问题,调个系统 API 还好,如果是 hotpath 那开销非常明显。
jni/cpython 之类的开销如何我倒是不清楚。 还有交叉编译可以用 zig 作为 CC 使用,能让 go/rust 在交叉编译含 c 代码的库时开箱即用。 |
29
Srar 2022-06-13 13:42:50 +08:00 via iPhone
|
30
32uKHwVJ179qCmPj 2022-06-13 14:00:20 +08:00
@icexin 24# 说的非常对,还有问题的建议细品层主的回复并应用到其他语言上进行对比
|
31
swulling 2022-06-13 14:04:43 +08:00
有条件还是建议隔离出 C/C++服务,单独提供 RPC 供调用,如果是本地调用可以用 Unix domain socket 。这样后续维护起来也简单。
|
32
THESDZ 2022-06-13 14:46:38 +08:00
建议 rpc ,担心性能可以考虑 grpc
https://github.com/hashicorp/go-plugin |
33
fgodt 2022-06-13 15:40:39 +08:00
但凡用 cgo 写过实际大项目的 都应该不会再选 cgo 了
|
34
akaHenry 2022-06-13 22:12:14 +08:00
@hhaobao
我贴给你的 FFI 相关博客, 就是 rust 和 dart 通过 C ABI 跨语言通信啊? 怀疑你有没有认真看? 至于 Python 调用 C. 这完全不用讨论. Python 社区, 大量的包, 都是 C 实现, 然后 binding 给 Python 使用. 这是 Python 性能优化的基本手段. > 关于 FFI / C ABI 跨语言通信. 是双向的. ( C ABI 是桥) 上面很多讨论, 都假定是 Go 通过 cgo 来调用 C 代码. (注意, 还有反过来的场景) rust/c/c++ 的 FFI 都是双向通信能力优秀. 说 CGo 是半残, 就是尽量不要用. 没有什么方案设计, 是非它不行的, 缺它不可. 没有什么方案设计, 是非它不行的, 缺它不可. 没有什么方案设计, 是非它不行的, 缺它不可. 非喜欢抬杠的, 你喜欢, 你就多用, 每个项目都用. |
35
akaHenry 2022-06-13 22:15:58 +08:00
https://github.com/trustwallet/wallet-core
这个 c++ 项目, 实现了跨语言 binding 到多个平台 iOS, Android(通过 jni). core lib 层跨平台场景, 选项只有 rust/c/c++. 不要走邪路. |
36
akaHenry 2022-06-13 22:31:54 +08:00
我上面贴的 2 篇博客, 都不看的?
github.com/hhstore/blog/issues/242 github.com/hhstore/blog/issues/355 > rust + ffi + flutter 实践案例: - https://github.com/AppFlowy-IO/AppFlowy - 这个项目, UI 层使用 flutter, core lib 层使用 rust. - 是非常现代的设计方案. > FFI 库( rust + dart): https://github.com/fzyzcjy/flutter_rust_bridge https://github.com/rust-lang/rust-bindgen https://github.com/google/autocxx https://github.com/rust-qt/ritual https://github.com/eqrion/cbindgen https://github.com/getditto/safer_ffi https://github.com/shekohex/flutterust https://github.com/sunshine-protocol/dart-bindgen https://github.com/brickpop/flutter-rust-ffi https://github.com/TimNN/cargo-lipo https://github.com/bbqsrc/cargo-ndk https://github.com/dart-lang/ffigen 跨平台场景, 要注意其他语言的 FFI 基础设施建设(易用性 /成熟度). Go 完全没有可比性. 现在贴内容, 都要投喂到这种程度, 才看吗? 如果看了我上面 2 篇博客. 还要坚持用 cgo 的. 那.... 你开心就好. |
37
akaHenry 2022-06-13 22:35:22 +08:00
至于 Python 的 FFI + C ABI 非常成熟. (毕竟 Python 性能优化靠 C)
社区实践了几百年了. Python 社区基础库, 基本都是 C 实现. 我是懒得贴了. 没有讨论必要. |
38
Cbdy 2022-06-13 22:50:57 +08:00 via Android
jni 确实还行
|
39
hhaobao 2022-06-14 01:01:36 +08:00
@orzglory 我觉得你误会了吧, 我只是认真请教, 关于 cgo 我用很久了, 既然你说 cgo 半残是指尽量不要用的意思, 那我就明白了, 我只是以为你能给出一些其它资料能更深入分析的.
看来 V2EX 上还是不能随便请教问题, 只要请教就被当杠精. |
40
hhaobao 2022-06-14 01:06:54 +08:00
@orzglory 另外, 我觉得在描述一样技术时, 把它说成"半残", 这么严重的词, 然后你意思仅是尽量不要用, 我还以为你能补齐它的另一半. 有点意思, 你们都是大牛, 我们都是扛精.
|
41
akaHenry 2022-06-14 02:53:04 +08:00
|
42
akaHenry 2022-06-14 03:04:31 +08:00 1
> 挑选最合适项目的方案,而不是强行套方案,最终不符合预期的时候骂骂咧咧。
上面某楼, 讲这种没卵用的废话. 1. 你没有使用过一个方案. 怎么知道好不好, 合适不合适? 不实践, 就知道是不是强行套方案? 你开天眼了? 云玩家? 2. 使用过, 很臭. 不能说? 不能排雷? 让更多人避坑? 3. 说它臭, 就是骂骂咧咧? 没有银弹, 就你懂? 4. 合着, 实践过, 被坑过. 再推荐给别人踩坑, 是什么形态? 这种看似"理中客", 最好笑. 你用, 我推荐. 我用, 我不用. 我本来懒得喷. 看还有人看不懂上下文. 明确一下吧. 而且, 我列了大量资料, 不去看. 不去对比各种语言的方案进展. 喜欢用 cgo, 你就多用啊. 我又不是写给你的. |
43
masterclock 2022-06-14 08:27:37 +08:00
其他不说,cgo 把东西写在注释里,注释成了会影响程序本身的东西,那还是注释吗?为什么不设计一些专门的结构来处理?就为了让语言 “干净”?
|
44
cheng6563 2022-06-14 09:19:16 +08:00
@masterclock 为了编译速度,一个符号都不想加,你敢信。之前设计泛型时一度考虑继续用括号()表示泛型
|
45
32uKHwVJ179qCmPj 2022-06-14 10:20:24 +08:00
抛开业务场景谈方案好坏就是耍流氓
|
46
xsen 2022-06-14 18:17:54 +08:00
@cccjh #12 cgo 体验还算好,你是实践做法有些问题
不要业务代码直接调用 cgo ,做个 cgo-binding pkg 隔离 |
47
zinwalin 2022-06-14 21:49:59 +08:00
JNI 太繁琐了。
|