在GO中调用C源代码#基础篇1
开坑说明
最近在编写客户端程序或与其他部门做功能集成时多次碰到了跨语言的sdk集成,虽说方案很多诸如rpc啊,管道啊,文件io啊,unix socket啊之类的不要太多,但最完美的基础方式还是让程序与sdk结合到一起(个人观点,不喜勿喷),顺便研究了下在go调用标准c接口的种种方法与坑,内容不少,有空便慢慢更新了。
内嵌形式
先让我们来看一个最简单的cgo实例
package main
//#include <stdio.h>
import "C"
func main() {
C.puts(C.CString("Hello World"))
}
输出
Hello World
通过"C包"调用了c中常见的puts函数同时传入通过C.Cstring把go 中string转化为的c string(相当于char *)。其实“C”这个并不是一个包,而是通过import "C"语句启用了go编译器cgo相关的功能让gcc也参与到了编译中。这种方式通过紧贴在import "C"语句上面的注释中编写c代码并在后续代码中使用C对象调用。当然也可以通过这种方式调用自定义的c函数。
package main
import "C"
/*#include <stdio.h>
void say_hello_with_name(char * name){
printf("hello %s\n", name);
}
*/
import "C"
func main() {
C.say_hello_with_name(C.CString("oscar"))
}
输出
hello oscar
外置的C代码
内置的C代码固然很方便,但用到cgo大多数的使用场景是我有一个需要复用的c代码库,像是c++的stl库亦或者是linux c中的什么已经封装好的第三方依赖。这些时候便需要外置一些c的文件.h .c .cpp之类与.go文件混编。先看一个最简单的例子(调用linux的系统账户认证)。
// auth.h
int auth(char *user, char *passwd);
// auth.c
#include <shadow.h>
#include <stdio.h>
#include <unistd.h>
int auth(char *user, char *passwd){
char *obtpwd;
struct spwd *spasswd;
spasswd = getspnam(user);
obtpwd = crypt(passwd, spasswd->sp_pwdp);
if(strcmp(spasswd->sp_pwdp, obtpwd) == 0)
return 0;
else return 1;
}
// main.go
package main
/*
#cgo LDFLAGS: -lcrypt
#include "auth.h"
*/
import "C"
import "fmt"
func main() {
var username, password string
fmt.Println("Please enter your username and password: ")
_, _ = fmt.Scanln(&username, &password)
rst := C.auth(C.CString(username), C.CString(password))
fmt.Println(rst)
}
保证上述三个文件在同一个go工程目录下运行 go build -o main 构建工程。#cgo LDFLAGS: -lcrypt 这个一行是cgo给gcc的编译参数,相关的编译参数与连接参数有空了在后面的文章里说明,-lcrypt 表示编译时需要去连接libcrypt这个库。
注意,这种c go 混编的方式个人是不建议的,cgo对外置c代码片构建支持非常差,我无法在cgo中通过编译参数指定c代码片的搜索路径(头文件倒是没啥问题),这也就意味着当项目被调用的c代码片都得在项目根目录下,这可太糟糕了。个人觉得如果有大量的外部依赖c语言的库请分开编译,c库使用gcc编译成静态或动态库在让go在编译时连接为好,写个makefile分开分步编译也不是什么麻烦事,还是上面的例子,让我们把编译的过程稍加修改。
1. 构建libauth.a静态库
gcc -c -o auth.o -lcrypt auth.c
ar rcs libauth.a auth.o
得到libauth.a
2. 对main.go稍加修改
package main
/*
#cgo CFLAGS: -I./
#cgo LDFLAGS: -L. -lauth -lcrypt
#include "auth.h"
*/
import "C"
import "fmt"
func main() {
var username, password string
fmt.Println("Please enter your username and password: ")
_, _ = fmt.Scanln(&username, &password)
rst := C.auth(C.CString(username), C.CString(password))
fmt.Println(rst)
}
此处修改主要是新增了libauth.a静态库的链接参数
3. 编译
go build -o main main.go
可以把上述的步骤整下写个简单的makefile
.PHONY : all
all: main
libauth.a: auth.c
gcc -c -o auth.o -lcrypt auth.c
ar rcs libauth.a auth.o
main: main.go libauth.a
go build -o main main.go
clean:
rm -f auth.o libauth.a main
这样也让我们得出产物的过程变得相对简单快捷
在GO中调用C源代码#基础篇1的更多相关文章
- 关于 C++ 中的强制转换 - 基础篇
引言 假设有基类 A,包含了虚函数 func1,以及有派生类 B,继承于类 A,派生类 B 中实现了函数 func1.此时可以用 A 类型的指针指向 B 类型的对象,并用 A 类型的指针调用 B 类型 ...
- 效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】) 转
效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中[附源代码下载]) 本文目录: (一)背景 (二)数据库数据导入到Excel的方法比较 ...
- Java多线程系列--“基础篇”03之 Thread中start()和run()的区别
概要 Thread类包含start()和run()方法,它们的区别是什么?本章将对此作出解答.本章内容包括:start() 和 run()的区别说明start() 和 run()的区别示例start( ...
- 在Android中调用C#写的WebService(附源代码)
由于项目中要使用Android调用C#写的WebService,于是便有了这篇文章.在学习的过程中,发现在C#中直接调用WebService方便得多,直接添加一个引用,便可以直接使用将WebServi ...
- 【COCOS2DX-LUA 脚本开发之一】在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途!
[COCOS2DX-LUA 脚本开发之一]在Cocos2dX游戏中使用Lua脚本进行游戏开发(基础篇)并介绍脚本在游戏中详细用途! 分类: [Cocos2dx Lua 脚本开发 ] 2012-04-1 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- 《量化投资:以MATLAB为工具》连载(2)基础篇-N分钟学会MATLAB(中)
http://www.matlabsky.com/thread-43937-1-1.html <量化投资:以MATLAB为工具>连载(3)基础篇-N分钟学会MATLAB(下) ...
- 【算法与数据结构】在n个数中取第k大的数(基础篇)
(转载请注明出处:http://blog.csdn.net/buptgshengod) 题目介绍 在n个数中取第k大的数(基础篇),之所以叫基础篇是因为还有很多更高级的算法,这些 ...
- 在Eclipse中使用JUnit4进行单元測试(0基础篇)
本文绝大部分内容引自这篇文章: http://www.devx.com/Java/Article/31983/0/page/1 我们在编写大型程序的时候,须要写成千上万个方法或函数,这些函数的功能可能 ...
随机推荐
- JS字符串格式化
//字符串格式化String.prototype.format = function () { var values = arguments; return this.replace(/\{(\d+) ...
- spring-boot 注解解析
package com.hllq.quan.controller; import com.hllq.quan.mapper.WeiboUserMapper; import com.hllq.quan. ...
- 什么是 spring?
Spring 是个 java 企业级应用的开源开发框架.Spring 主要用来开发 Java 应用, 但是有些扩展是针对构建 J2EE 平台的 web 应用.Spring 框架目标是简化 Java 企 ...
- Effective Java —— 用静态工厂方法代替构造器
本文参考 本篇文章参考自<Effective Java>第三版第一条"Consider static factory methods instead of constructor ...
- Spark学习摘记 —— Pair RDD转化操作API归纳
本文参考 参考<Spark快速大数据分析>动物书中的第四章"键值对操作",由于pair RDD的一些特殊操作,没有和前面两篇的API归纳放在一起做示例 前面的几个api ...
- 全方位讲解 Nebula Graph 索引原理和使用
本文首发于 Nebula Graph Community 公众号 index not found?找不到索引?为什么我要创建 Nebula Graph 索引?什么时候要用到 Nebula Graph ...
- Numpy使用Matplotlib实现可视化绘图
Numpy使用Matplotlib实现可视化绘图 可以直接将Numpy的数组传给Matplotlib实现可视化绘图: 曲线图 饼图 柱状图 直方图 1. 绘制正弦曲线 2. 绘制饼图 3. 柱状图 4 ...
- css3中user-select的用法详解
css3中user-select的用法详解 user-select属性是css3新增的属性,用于设置用户是否能够选中文本.可用于除替换元素外的所有元素,以下是user-select的主要用法和注意事项 ...
- ES6-11学习笔记--数值的扩展
二进制 0B 八进制 0O Number.isFinite() , Number.isNaN() Number.parseInt() , Number.parseFloat() Number ...
- Java/C++实现访问者模式---购物车
在我们课堂上的"购物车"的例子中,增加一个新的访问者:打包员,负责对购物车中货物装包. 类图: Java代码: public interface Product { void ac ...