`
wx1569567608
  • 浏览: 71228 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

   为了能够重用已有的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)

转载于:https://my.oschina.net/u/158055/blog/694478

分享到:
评论

相关推荐

    go-toolset-7-golang-bin-1.8.3-4.el7.x86_64.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    golang-linux-arm64-sdk

    本文将详细探讨“golang-linux-arm64 SDK”,揭示其核心特性和使用方法,帮助开发者更好地理解和利用这个强大的工具。 一、golang-linux-arm64 SDK简介 golang-linux-arm64 SDK是Go语言针对Linux操作系统和ARM64...

    Java语言写的围棋小游戏 半成品A Go game written in golang(Semi-finished).zip

    半成品A Go game written in golang(Semi-finished).zip Java语言写的围棋小游戏。半成品A Go game written in golang(Semi-finished).zip Java语言写的围棋小游戏。半成品A Go game written in golang(Semi-...

    golang实现aes-256-cbc

    在Golang中实现AES-256-CBC(Advanced Encryption Standard with a 256-bit key in Cipher Block Chaining mode)是一种常见的加密方法,用于确保数据的安全性。然而,Golang的标准库`crypto/cipher`在处理密钥时...

    golang-bin-1.17.2-2.module_el8.6.0+963+7827afaa.x86_64.rpm

    官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装

    golang-stats-api-handler, Golang cpu,内存,gc等信息api处理程序.zip

    golang-stats-api-handler, Golang cpu,内存,gc等信息api处理程序 golang-stats-api-handlerGolang cpu,内存,gc等信息api处理程序。 安装go get github.com/fukata/golang-stats-api-handler示

    golang-misc-1.16.1-3.module_el8.5.0+762+a2d12c29.noarch.rpm

    官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装

    Go-用于自动获取证书LetsEncryptSSL证书的Golang库

    标题中的“Go-用于自动获取证书LetsEncryptSSL证书的Golang库”指的是使用Go语言(Golang)编写的工具或库,它可以帮助开发者自动化获取Let's Encrypt提供的SSL证书。Let's Encrypt是一个免费、自动化且开放的证书...

    create-basic-configdrive

    创建基本配置驱动器用于创建coreos configdrive的Golang...basic-configdrive -hcreate-basic-configdrive -H myhostname -S ~/.ssh/mykey.pub -t TOKEN使用virtualbox测试configdrive 安装virtualbox go get github....

    开源项目-alaska-golang-ref-sheet.zip

    开源项目-alaska-golang-ref-sheet.zip,alaska/golang-ref-sheet: A golang quick reference sheet. Your one stop concurrency shop!

    开源项目-dkondratovych-golang-ua-meetup.zip

    开源项目-dkondratovych-golang-ua-meetup.zip,Presentation about Context in Go 1.7. Review, examples, thoughts.

    Go-golang-set-Go的线程安全的和非线程安全的高性能集

    `golang-set`库提供了一种实现,包括线程安全和非线程安全的高性能集,非常适合在Go的并发环境中使用。 首先,我们要理解什么是线程安全和非线程安全。线程安全指的是在多线程环境下,一个函数或方法在同一时刻可以...

    最新intellij ieda golang 插件2013-11-27日编译

    最新intellij ieda golang 插件2013-11-27日编译

    Api-golang-gin-realworld-example-app.zip

    Api-golang-gin-realworld-example-app.zip,使用golang gingolang/gin代码库构建的示例性真实世界应用程序,包含遵循真实世界规范和api的真实世界示例(crud、auth、高级模式等)。,一个api可以被认为是多个软件设备...

    Golang_Puzzlers-春节主题资源

    项目中的“readme.txt”文件通常包含该项目的基本信息和使用说明。它会对项目的结构、安装部署、运行方式等进行简要说明。对于想要深入学习Golang的用户来说,这个文件是入门的敲门砖。它可能会详细解释这个“Golang...

    golang.org-master

    然而,有时我们可能无法直接访问golang.org网站获取这些宝贵的资料,因此这个名为“golang.org-master”的压缩包就像是一份大礼包,为Go程序员提供了离线学习和研究Go语言的机会。 首先,让我们深入了解golang.org...

    golang-hex-dumper

    golang-hex-dumper 一个简单的十六进制转储库例程,用于需要深入研究二进制文件的诊断。 以十六进制显示字节。 随附gohexdump目录中的示例命令行工具。 go get github.com/glycerine/golang-hex-dumper/... ...

    docker golang 基础包1.20-alpine

    docker golang 基础包1.20-alpine

Global site tag (gtag.js) - Google Analytics