在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 我们在编写大型程序的时候,须要写成千上万个方法或函数,这些函数的功能可能 ...
随机推荐
- ThreadLocal 是什么?有什么用?
ThreadLocal 是一个本地线程副本变量工具类.主要用于将私有线程和该线程存放的副本对象做一个映射,各个线程之间的变量互不干扰,在高并发场景下,可以实现无状态的调用,特别适用于各个线程依赖不通的 ...
- 服务端处理 Watcher 实现 ?
1.服务端接收 Watcher 并存储 接收到客户端请求,处理请求判断是否需要注册 Watcher,需要的话将数据节点 的节点路径和 ServerCnxn(ServerCnxn 代表一个客户端和服务端 ...
- 学习FastDfs(二)
分布式文件系统(DFS) 指文件系统管理的物理存储资源不一定直接连接在本地节点上 而是通过计算机网络与节点相连 分布式文件系统的设计基于客户机/服务器模式 一个典型的网络可能包括多个多个用户访问的服务 ...
- centos下安装配置maven
下载maven安装包 wget http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache-maven ...
- 攻防世界 Ditf misc
Ditf 附件下载下来就是一张图片,我们拉到hxd中发现应该有隐藏的压缩包 我们拉入到kali里面分析 意外发现图片高度被修改过我们先用binwalk分析图片看看 我们先尝试分离一下分离出一个压缩包但 ...
- 如何在Ubuntu 18.04 LTS上安装和配置MongoDB
MongoDB是一款非关系型数据库,提供高性能,高可用性和自动扩展企业数据库. MongoDB是一个非关系型数据库,因此您不能使用SQL(结构化查询语言)插入和检索数据,也不会将数据存储在MySQL或 ...
- ffmpeg将视频生成gif
1.安装ffmpeg 2.cmd中输入 ffmpeg -i 0.mp4 -f gif 0.gif 即可将视频转为gif
- java中hashCode和equals什么关系,hashCode到底怎么用的
Object类的hashCode的用法:(新手一定要忽略本节,否则会很惨) 马 克-to-win:hashCode方法主要是Sun编写的一些数据结构比如Hashtable的hash算法中用到.因为ha ...
- Spring理解1 ioc
Spring Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架). 需要了解 ioc容器 IOC底层原理 IOC接口 BeanFactory Bean的作用域 IOC操 ...
- 基于Nginx实现反向代理
一.nginx的简介 Nginx 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务 其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服 ...