为了能够重用已有的C语言库,我们在使用Golang开发项目或系统的时候难免会遇到Go和C语言混合编程,这时很多人都会选择使用cgo。 话说cgo这个东西可算得上是让人又爱又恨,好处在于它可以让你快速重用已有的C语言库,无需再用Golang重造一遍轮子,而坏处就在于它会在一定程度 上削弱你的系统性能。关于cgo的种种劣迹,Dave Cheney大神在他的博客上有一篇专门的文章《cgo is not Go》,感兴趣的同学可以看一看。但话说回来,有时候为了快速开发满足项目需求,使用cgo也实在是不得已而为之。

 
       在Golang中使用cgo调用C库的时候,如果需要引用很多不同的第三方库,那么使用#cgo CFLAGS:和#cgo LDFLAGS:的方式会引入很多行代码。首先这会导致代码很丑陋,最重要的是如果引用的不是标准库,头文件路径和库文件路径写死的话就会很麻烦。一旦第 三方库的安装路径变化了,Golang的代码也要跟着变化,所以使用pkg-config无疑是一种更为优雅的方法,不管库的安装路径有何变化,我们都不 需要修改Go代码,接下来本博主就用一个简单的例子来说明如何在cgo命令中使用pkg-config。
 
       首先假定我们在路径/home/ubuntu/third-parties/hello下安装了一个名称为hello的第三方C语言库,其目录结构如下所示,在hello_world.h中只定义了一个接口函数hello,该函数接收一个char *字符串作为变量并调用printf将其打印到标准输出。
 
# tree /home/ubuntu/third-parties/hello/
/home/ubuntu/third-parties/hello/
├── include
│   └── hello_world.h
└── lib
    ├── libhello.so
    └── pkgconfig
        └── hello.pc
 
       为了保证pkg-config能够找到这个C语言库,我们要为这个库生成一个描述文件,也就是lib/pkgconfig目录下的hello.pc,其内容如下,有不了解该配置文件内容的看客们可以去搜索一下pkg-config的相关文档。
 
# cat hello.pc 
prefix=/home/ubuntu/third-parties/hello
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${exec_prefix}/include
Name: hello
Description: The hello library just for testing pkgconfig
Version: 0.1
Libs: -lhello -L${libdir}
Cflags: -I${includedir}
 
       完成pkg-config描述文件的创建后,还需要将该描述文件的路径信息添加到PKG_CONFIG_PATH环境变量中,只有这样 pkg-config才能正确获取这个C语言库的相关信息。此外,我们还需要将该C语言库的库文件路径添加到LD_LIBRARY_PATH环境变量中, 具体命令如下:
 
# export PKG_CONFIG_PATH=/home/ubuntu/third-parties/hello/lib/pkgconfig
# pkg-config --list-all | grep libhello
libhello    libhello - The hello library just for testing pkgconfig
# export LD_LIBRARY_PATH=/home/ubuntu/third-parties/hello/lib
 
       在完成以上一系列准备工作之后,我们就可以开始编写Golang代码了,以下是Golang调用C语言接口的代码示例,我们只需要#cgo pkg-config: libhello和#include < hello_world.h >两行语句即可实现对hello函数的调用。如果C语言库的安装路径发生了变化,只需修改hello.pc这个描述文件即可,Golang代码无需重新修改和编译。
 
package main
// #cgo pkg-config: libhello
// #include < stdlib.h >
// #include < hello_world.h >
import "C"
import (
"unsafe"
)
func main() {
msg := "Hello, world!"
cmsg := C.CString(msg)
C.hello(cmsg)
C.free(unsafe.Pointer(cmsg))
}
 
       最后,编译该程序代码,查看可执行程序是否正确链接了C语言库,执行程序验证能否正确调用库函数功能。
 
# go build hello_world.go 
# ldd hello_world
linux-vdso.so.1 =>  (0x00007ffff63d3000)
libhello.so => /home/ubuntu/third-parties/hello/lib/libhello.so (0x00007fc31c0e1000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc31bec3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc31bafe000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc31c2e3000)
# ./hello_world 
Hello, world!
 
       在以上步骤中需要关注的有两个地方:1)创建C语言库的pkg-config配置文件并将配置文件的路径添加到环境变量 PKG_CONFIG_PATH中;2)C语言库文件的路径添加到环境变量LD_LIBRARY_PATH中,如果没有这一步,Go语言程序可以编译成 功,但是可执行文件无法正确连接到C语言库,会出现如下情况:
 
# ldd hello_world
linux-vdso.so.1 =>  (0x00007fffa49e2000)
libhello.so => not found
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007feb0fe93000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007feb0face000)
        /lib64/ld-linux-x86-64.so.2 (0x00007feb100b1000)

Golang使用pkg-config自动获取头文件和链接库的方法的更多相关文章

  1. Makefile中自动生成头文件依赖

    为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新 ...

  2. Makefile自动生成头文件依赖

    前言 Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程. Makefile模板 首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖 ...

  3. IOS中获取各种文件的路径介绍及方法

    IOS中获取各种文件的目录路径的方法 技术交流新QQ群:414971585 iphone沙箱模型的有四个文件夹,分别是什么,永久数据存储一般放在什么位置,得到模拟器的路径的简单方式是什么. docum ...

  4. .h头文件、 .lib库文件、 .dll动态链接库文件之间的关系

    转自.h头文件. .lib库文件. .dll动态链接库文件之间的关系 h头文件作用:声明函数接口 dll动态链接库作用:含有函数的可执行代码 lib库有两种: (1)静态链接库(Static Liba ...

  5. C语言常用的库文件(头文件、函数库)

    C语言常用的库文件(头文件.函数库) C系统提供了丰富的系统文件,称为库文件.C的库文件分为两类,一类是扩展名为".h"的文件,称为头文件,在前面的包含命令中我们已多次使用过.在& ...

  6. iOS程序破解——class-dump获取头文件

    原文在此:http://www.cnblogs.com/mddblog/p/4942894.html 一.简述 class-dump顾名思义,是用来dump目标对象class信息的工具.它根据oc的r ...

  7. pycharm自动生成头文件注释

    1.在file->settings->file and code templates->python script即可自定制pycharm创建文件自动生成的头文件注释信息 2.创建p ...

  8. linux c 获取头文件函数getenv

    #include <stdio.h>#include <stdlib.h> int main(){ printf("%s\n", getenv(" ...

  9. 关于启明星系统移除apppath配置,让系统自动获取路径来设置cookie的解决方法

    启明星系统底层使用统一接口,特别是用户,用户登录后,都会建立一个 userinfo 的cookie.请看下面2个网址: http://120.24.86.232/book http://120.24. ...

随机推荐

  1. HDU1735 字数统计

    版权声明:长风原创 https://blog.csdn.net/u012846486/article/details/28011667 字数统计 Time Limit: 1000/2000 MS (J ...

  2. 一:线性dp

    概念: 动态规划是运筹学的一个分支,是求解决策过程最优化的数学方法. 动态规划是通过拆分问题,定义问题状态和状态之间的关系使得问题能够以递推(或者说分治)的方法去解决. 解决策略: 1)最优化原理:如 ...

  3. linux下配置python环境 django创建helloworld项目

    linux下配置python环境 1.linux下安装python3 a. 准备编译环境(环境如果不对的话,可能遇到各种问题,比如wget无法下载https链接的文件) yum groupinstal ...

  4. Kotlin Android学习入门

    1.基本语法 https://github.com/mcxiaoke/kotlin-notes/blob/master/kotlin-tutorial-basic.md 2.推荐两篇Kotlin An ...

  5. C#多线程编程之:异步事件调用

    当一个事件被触发时,订阅该事件的方法将在触发该事件的线程中执行.也就是说,订阅该事件的方法在触发事件的线程中同步执行.由此,存在一个问 题:如果订阅事件的方法执行时间很长,触发事件的线程被阻塞,长时间 ...

  6. 黄聪:wordpress如何防止发布文章时候自动清除<P>、<br>换行标签

    1.安装[TinyMCE Advanced]插件 2.进入[后台]--[设置]--[TinyMCE Advanced]把这个选项勾上保存即可.

  7. Bootstrap-Other:Less 教程

    ylbtech-Bootstrap-Other:Less 教程 1.返回顶部 1. 2. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部 1. http://www.runoob. ...

  8. postman-2get发送请求

    文档地址:https://www.v2ex.com/p/7v9TEc53 第一个API请求 最热主题 相当于首页右侧的 10 大每天的内容. https://www.v2ex.com/api/topi ...

  9. 20165233 2017-2018-2 《Java程序设计》第七周学习总结

    20165233 2017-2018-2 <Java程序设计>第七周学习总结 教材学习内容总结 ch11 下载XAMPP 基本操作:连接数据库 基础:查询操作,更新.添加与删除操作 重点: ...

  10. Cloudera Manger CDH 安装文档

    简介: Cloudera Manager 是 Cloudera 公司推出的 Hadoop 集群管理工具,通过该管理工具可以方便的部署.配置.监控集群. Cloudera 公司自己发布的 Hadoop ...