golang 动态库 (buildmode)
目录
- 1. golang 动态库
- 2. Golang 生成 C 动态库 `.so` 和静态库 `.a`
- 2.1. 源代码
- 2.2. 编译
- 2.3. C
- 2.4. 执行
- 2.5. 如何生成静态库
- 2.6. Go 调用 C 库
- 2.6.1. 源代码
- 3. golang 语言使用动态库、调用动态链接库
- 3.1. Go 插件系统
- 3.2. 动态加载的优劣
- 3.3. Go 的插件系统: Plugin
- 3.4. 插件开发原则
- 3.4.1. 插件独立
- 3.4.2. 使用接口类型作为边界
- 3.4.3. Unix 模块化原则
- 3.4.4. 版本控制
- 3.5. 插件开发示例
- 3.5.1. 编写插件
- 3.5.2. 使用插件
1. golang 动态库
2. Golang 生成 C 动态库 .so
和静态库 .a
2.1. 源代码
Go 生成 C 动态库 .so
和静态库 .a
package mainimport "C"
import "fmt"//export hello
func hello(){fmt.Println("hello world")
}
//export add
func add(a,b int) int {return a+b
}func main(){
}
注意: 生成 C 可调用的 so 时, Go 源代码需要以下几个注意。
- 必须导入 “C” 包
- 必须在可外部调用的函数前加上 【//export 函数名】的注释
- 必须是 main 包, 切含有 main 函数, main 函数可以什么都不干
2.2. 编译
先要安装 go 的标准库
go install -buildmode=shared -linkshared std
编译共享库
go build -buildmode=c-shared -o so 库文件名 自己的项目
然后当前目录就会出现 xxx.h
和 xxx.so
文件
2.3. C
#include<stdio.h>
#include"libtest.h" //生成的头文件void main(){hello();printf("\n2+3=%d\n",add(2,3));
}
编译:
gcc goso.c -L ./ -ltest -o goso
2.4. 执行
由于是共享库, 那么运行时就需要加载需要的库。在 linux 中默认库的路径为/usr/lib 或者/usr/lib64 。如果想将自己所在的文件夹也添加到库搜索目录中去。那么有两种方式:
- 修改配置文件, 将自己的目录添加到库搜索目录列表中去。/etc/ld.so.conf 然后执行 ldconfig
- 修改环境变量, 临时改变库搜索路径。 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH: 自己的目录
2.5. 如何生成静态库
只需要将 buildmode 改为 c-archive 即可。然后编译时将静态库参与编译即可。
2.6. Go 调用 C 库
2.6.1. 源代码
注意:
需要使用到 cgo 工具
- 直接在 import "C"之前添加一个注释。 然后使用 C 语法添加库的头文件。
- 针对共享库由于是操作系统管理程序运行加载的共享库, 所以可以不用管, 只需要将 so 库放入对应的目录即可。针对静态库, 那么就要在代码中多添加一行, 告诉编译器编译时需要连接的库。// #cgo LDFLAGS: -L ./ -lfoo
package main//#cgo LDFLAGS: -L ./ -lfoo 使用静态库时需要添加
//#include"xxx.h"
import "C"
xxxx
func main(){C.xxx(xxx)
}
3. golang 语言使用动态库、调用动态链接库
3.1. Go 插件系统
通过使用插件在运行时扩展程序的功能, 而无需重新编译程序, 这是一个很常见的功能需求, 特别是在模块化设计的程序里面, 比如 Nginx 的模块系统。 在 C/C++中通过使用动态库的方式可以实现动态加载, 但是 Go 直到 1.8 官方才开始支持, 下面将介绍 Go 如何基于动态链接库来实现动态加载。
3.2. 动态加载的优劣
优点:
- 动态加载, 也称热加载, 每次升级时不用重新编译整个工程, 重新部署服务, 而是添加插件时进行动态更新。这对于很多比较重型的服务来说非常重要。
缺点:
- 带来一定的安全风险, 如果一些非法模块被注入如何防范
- 给系统带来一定的不稳定的因素, 如果模块有问题, 没有经过良好的测试, 容易导致服务崩溃
- 为版本管理带来了难题, 特别是在微服务的今天, 同一个服务, 加载了不同的插件, 应该怎么管理版本, 插件版本应该如何管理
因此请慎重考虑, 是使用动态插件还是在源码里面进行插件化。
3.3. Go 的插件系统: Plugin
从 1.8 版开始, 官方提供了这种插件化的手段: plugin. 此功能使程序员可以使用动态链接库构建松散耦合的模块化程序, 可以在运行时动态加载和绑定。
Go 插件是使用 -buildmode = plugin
标记编译的一个包, 用于生成一个共享对象 (.so) 库文件。 Go 包中的导出的函数和变量被公开为 ELF 符号, 可以使用 plugin 包在运行时查找并绑定 ELF 符号。Go 编译器能够使用 build flag -buildmode = c-shared 创建 C 风格的动态共享库。
1.8 版本插件功能只能在 Linux 上使用。 1.10 也可以在 Mac 上运行。
下面将介绍使用 Go 插件系统创建模块化软件的一些开发原则, 并提供一个功能齐全的示例。
3.4. 插件开发原则
使用 Go 插件创建模块化程序需要遵循与常规 Go 软件包一样严格的软件实践。然而, 插件引入了新的设计问题, 因为它们的解耦性质被放大了。因此我们在设计可插拔系统时, 有一些原则需要关注:
3.4.1. 插件独立
应该将插件视为与其他组件分离的独立组件。这允许插件独立于他们的消费者, 并拥有自己的开发和部署生命周期。注意插件的可用性很重要, 因为它有肯能为整个系统带来不稳定的因素, 因此系统必须为插件集成提供一个简单的封装层, 插件开发人员将系统视为黑盒, 不作为所提供的合约以外的假设, 从而保证插件自身的可用性。
3.4.2. 使用接口类型作为边界
Go 插件可以导出任何类型的包函数和变量。您可以设计插件来将其功能解耦为一组松散的函数。缺点是您必须单独查找和绑定每个函数符号。
然而, 更为简单的方法是使用接口类型。创建导出功能的接口提供了统一简洁的交互, 并具有清晰的功能划分。解析到接口的符号将提供对该功能的整个方法集的访问, 而不仅仅是一个方法。
3.4.3. Unix 模块化原则
插件代码应该设计成只关注一个功能点。
3.4.4. 版本控制
插件是不透明而独立的实体, 应该进行版本控制, 以向用户提示其支持的功能。这里的一个建议是在命名共享对象文件时使用语义版本控制。例如, 上面的文件编译插件可以命名为 eng.so.1.0.0。
3.5. 插件开发示例
我以我遇到的一个实际需求为例, 在开发物联网接入组件的时候, 需要动态支持物解析, 下面就开发一个物解析的插件系统。
下面是项目结构, parser.go 是接口规约, main.go 是主程序, plugins 存放多个插件包
├── main.go
├── parser.go
└── plugins├── car│ └── car.go└── phone└── phone.go
3.5.1. 编写插件
- 编写主程序接口规约: main.go
package main// Parser use to parse things
type Parser interface {
byte) (meta map[string]string, data map[string]float64, err error)
}
- 根据接口规约编写插件: car.go
package maintype car stringfunc (c *car) Parse([]byte) (meta map[string]string, data map[string]float64, err error) {
map[string]string{"key1": "a"}
map[string]float64{"key1": 1}return meta, data, nil
}var Car car
- 根据接口规约编写插件: phone.go
package maintype phone stringfunc (p *phone) Parse([]byte) (meta map[string]string, data map[string]float64, err error) {
map[string]string{"key1": "b"}
map[string]float64{"key1": 2}return meta, data, nil
}var Phone phone
- 编译插件插件写完后将在 plugins 目录下编译插件:
$ cd plugins
$ go build -buildmode=plugin -o car.so car/car.go
$ go build -buildmode=plugin -o phone.so phone/phone.go
最终在 plugins 目录下会生成好我们编译好的插件:
$ ls *.so
car.so phone.so
3.5.2. 使用插件
插件的使用很简单, 大概步骤如下:
- 用 plugin.Open() 打开插件文件
- 用 plguin.Lookup(“Export-Variable-Name”) 查找导出的符号"Car"或者"Phone"。 请注意, 符号名称与插件模块中定义的变量名称相匹配
- 使用该变量
主程序使用插件: main.go
package mainimport (
"fmt"
"plugin"
)// Parser use to parse things
type Parser interface {
byte) (meta map[string]string, data map[string]float64, err error)
}func pa() {
"./plugins/car.so")
if err != nil {
panic(err)}"Car")
if err != nil {
panic(err)}p, ok := car.(Parser)
if ok {
byte("a"))
if err != nil {
panic(err)}
"meta: %v, data: %v \n", meta, data)}
}func pb() {
"./plugins/phone.so")
if err != nil {
panic(err)}"Phone")
if err != nil {
panic(err)}p, ok := phone.(Parser)
if ok {
byte("a"))
"meta: %v, data: %v \n", meta, data)}
}func main() {pa()pb()
}
测试是否正常运行:
$ go run main.go
meta: map[key1:a], data: map[key1:1]
meta: map[key1:b], data: map[key1:2]
相关文章:
golang 动态库 (buildmode)
目录 1. golang 动态库2. Golang 生成 C 动态库 .so 和静态库 .a2.1. 源代码2.2. 编译2.3. C2.4. 执行2.5. 如何生成静态库2.6. Go 调用 C 库2.6.1. 源代码 3. golang 语言使用动态库、调用动态链接库3.1. Go 插件系统3.2. 动态加载的优劣3.3. Go 的插件系统: Plugin3.4. 插件开…...

【mysql】2006 - Server has gone away
执行了一组插入语句 提示:2006 - Server has gone away; 2006-服务器已经消失; 消失去哪里了,被黑洞吞没了吗?!!! 网络问题 网络不稳定?断网了?检查网络连…...
动态规划43(Leetcode91解码方法)
代码: class Solution {public int numDecodings(String s) {int n s.length();if(s.charAt(0)0)return 0;if(n1)return 1;int[] dp new int[n1];dp[0]1;dp[1]1;for(int i2;i<n;i){if(s.charAt(i-2)1){dp[i]dp[i-2];}else if(s.charAt(i-2)2&&s.charA…...

STM32电源名词解析
先来简单了解一下各种电源端口的命名 VCC:Ccircuit 表示电路的意思, 即接入电路的电压 VDD:Ddevice 表示器件的意思, 即器件内部的工作电压。 VSS:Sseries 表示公共连接的意思,通常指电路公共接地端电压。 GND:在电…...
openAI宫斗感想 chatGPT带给客户巨大利益的就是王者。王者终究会归来。技术人员不要总是想掌握所有核心技术并用到极致。
1.我很喜欢乔布斯用的iCEO,每个人的工作都是临时的,打掉铁饭碗才会有效率。有铁饭碗就容易使人怠慢、傲慢、嚣张、低效率的消耗自己和别人的生命。日本人为什么对每个人每个客户都毕恭毕敬,感觉因为他的饭碗都掌握在周围的人手里。 日本文化…...

驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接
参考:https://www.cnblogs.com/sam-snow-v/p/15917898.html eclipse链接SQL Server出现问题 笔者使用Open JDK 17,SQL Server 2016,项目中使用JPA操作数据库。测试环境没问题,生产环境出现如题所示“驱动程序无法通过使用安全套接…...
性能调优第一步:服务器硬件如何选型
硬件选型是调优的第一步,无论你是自行购买服务器进行托管,还是租用服务器,或者购买云主机,都要面临的一个问题,那就是选择服务器的硬件配置,因为没有一台服务器能满足所有需求,解决所有的问题。…...

Codewhisperer 使用评价
最近亚⻢逊推出了一款基于机器学习的 AI 编程助手 Amazon CodeWhisperer,可以实时提供代码建议。在编写代码时,它会自动根据现有的代码和注释给出建议。Amazon CodeWhisperer 与GitHub Copilot类似,主要的功能有: 代码补全注释和文档补全代码…...

结合scss实现黑白主题切换
是看了袁老师的视频后,自己做了一下练习。原视频地址: b站地址https://www.bilibili.com/video/BV15z4y1N7jB/?spm_id_from333.1007.top_right_bar_window_history.content.click&vd_sourcec6cf63302f28d94ebc02cbedcecc57ea首先创建一个全局的scs…...
go-zero对数据库的操作
一、go-zerro中结合gorm来操作mysql数据库 1、这里我这就直接结合gorm-gen的方式来实现数据库操作,关于gorm-gen可以参考官网 2、创建一个数据库,并且创建一个表 -- ------------------------ -- 用户表 -- ------------------------ DROP TABLE IF EXISTS user; C…...

Mac git查看分支以及切换分支
查看本地分支 git branch 查看远程仓库分支 git branch -r 查看本地与远程仓库分支 git branch -a 切换分支 git checkout origin/dev/js...
Qt调起Mac“系统设置”面板
mac系统设置相关字段: Accessibility 面板相关 项目 URL Scheme Main x-apple.systempreferences:com.apple.preference.universalaccess Display x-apple.systempreferences:com.apple.preference.universalaccess?Seeing_Display Zoom x-apple.systempreference…...
小程序如何刷新当前页面
小程序可以通过调用wx.pageScrollTo()方法来实现刷新当前页面,该方法可以滚动页面并使页面滚动到顶部,从而达到刷新页面的效果。具体的操作步骤如下: 在需要刷新的页面中添加一个按钮或其他触发事件的元素。 绑定相应的点击事件,…...

OSI参考模型
目录 一. OSI参考模型的各层功能二. 网络排错三. 网络安全四. 实体、协议、服务和服务访问点SAP五. TCP IP体系结构 一. OSI参考模型的各层功能 \quad \quad \quad \quad 我们首先来看应用层实现的功能 每个字段的各种取值所代表的意思 \quad \quad 比如要保存的文件内容是ab…...

(c语言进阶)内存函数
一.memcpy(void* dest,void* src,int num) ,操作单位为字节,完成复制且粘贴字符串 1.应用 #include <stdio.h> #include<string.h> int main() {int arr1[] { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] { 0 };memcpy(arr2, arr1, 20);//从…...

【2023春李宏毅机器学习】快速了解机器学习基本原理
文章目录 机器学习约等于机器自动找一个函数 机器学习分类 regression:输出为连续值classification:输出为一个类别structured learning:又叫生成式学习generative learning 生成有结构的物件(如:影像、句子…...
人工智能:科技的魔术师
引言: 人工智能(Artificial Intelligence,简称AI)作为一项前沿技术,正以惊人的速度改变着我们的生活。它像魔术师一样,能够解决我们的问题、提供建议,甚至预测未来。从智能手机到智能家居&…...

三菱FX3U小项目—运料小车自动化
目录 一、项目描述 二、IO口分配 三、项目流程图 四、项目程序 五、总结 一、项目描述 设备如下图所示,其中启动按钮SB1用来开启运料小车,停止按钮SB2用来手动停止运料小车(其工作方式任务模式要求)。当小车在原点SQ1位置,按下启动按钮S…...

智慧城市大脑数据中台解决方案:PPT全套37页,附下载
关键词:智慧城市大脑解决方案,数据中台解决方案,智慧城市建设,数据中台建设,智慧城市大脑建设,数据中台建设架构 一、智慧城市大脑数据中台建设背景 智慧城市大脑数据中台是一个面向城市级数据管理、开发和…...

vs code git问题:文件明明已加入忽略文件中,还是出现
vs code git问题:文件明明已加入忽略文件中,还是出现 原因: 因为之前这些文件都已经提交过,线上GIT已经存在,已存在就不能忽略, 解决办法: 先要删除这些文件提交上去,然后把这些文…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...