解決GO編譯時(shí)避免引入外部動(dòng)態(tài)庫(kù)的問(wèn)題
簡(jiǎn)介
最近碰到一個(gè)問(wèn)題,有一個(gè)流量采集的組件中使用到了github.com/google/gopacket 這個(gè)庫(kù),這個(gè)庫(kù)使用一切正常,但是唯獨(dú)有一個(gè)缺點(diǎn),編譯后的二進(jìn)制文件依賴(lài)于libpcap.so的動(dòng)態(tài)庫(kù)。這為安裝包兼容多個(gè)平臺(tái)造成了一定的困擾,于是便想著如何把libpcap這個(gè)外部依賴(lài)已靜態(tài)庫(kù)的方式在go程序編譯的同時(shí)link進(jìn)可執(zhí)行程序。
gopacket是如何構(gòu)建的?
此處先截取一小片源碼(github.com/google/gopacket/pcap/pcap_unix.go),此處可以看到在cgo中指定了部分的編譯參數(shù),其中的 "-lpcap" 便是指定link到的庫(kù)的名稱(chēng)。可以說(shuō)是相當(dāng)?shù)拇直┝恕?/p>
#cgo solaris LDFLAGS: -L /opt/local/lib -lpcap #cgo linux LDFLAGS: -lpcap #cgo dragonfly LDFLAGS: -lpcap #cgo freebsd LDFLAGS: -lpcap #cgo openbsd LDFLAGS: -lpcap #cgo netbsd LDFLAGS: -lpcap #cgo darwin LDFLAGS: -lpcap
演示demo
// 使用gopacket 抓包的簡(jiǎn)單示例
package main
import (
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
logger "github.com/sirupsen/logrus"
"log"
)
const (
device = "ens32"
SnapLen = int32(65535) // libpcap 接收數(shù)據(jù)的長(zhǎng)度
Promisc = false // 是否開(kāi)啟混雜模式
BPF = "icmp"
)
func main() {
handle, err := pcap.OpenLive(device, SnapLen, Promisc, pcap.BlockForever)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
// 編譯并設(shè)置bpf過(guò)濾規(guī)則
if err = handle.SetBPFFilter(BPF); err != nil {
log.Fatal(err)
}
// 開(kāi)始獲取流量
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
packetSource.NoCopy = true
packetChan := packetSource.Packets()
for packet := range packetChan {
if packet.TransportLayer() == nil {
// icmp流量
icmpStreamHandle(packet)
} else if packet.TransportLayer().LayerType() == layers.LayerTypeTCP {
// tcp流量
tcpStreamHandle(packet)
} else if packet.TransportLayer().LayerType() == layers.LayerTypeUDP {
// udp流量
udpStreamHandle(packet)
}
}
}
func icmpStreamHandle(packet gopacket.Packet) {
logger.Info("get icmp packet")
}
func tcpStreamHandle(packet gopacket.Packet) {
}
func udpStreamHandle(packet gopacket.Packet) {
}編譯并ldd查看依賴(lài)庫(kù)的使用情況
[root@localhost ddk]# go build main.go && ldd main linux-vdso.so.1 => (0x00007ffe965f3000) libpcap.so.1 => /lib64/libpcap.so.1 (0x00007f6be101f000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6be0e03000) libc.so.6 => /lib64/libc.so.6 (0x00007f6be0a35000) /lib64/ld-linux-x86-64.so.2 (0x00007f6be1260000) [root@localhost ddk]#
很容易的查看到對(duì)libpcap.so.1 這個(gè)動(dòng)態(tài)庫(kù)的依賴(lài)
準(zhǔn)備靜態(tài)庫(kù)
找到你的libpcap.so 對(duì)應(yīng)的libpcap.a 文件,無(wú)論是通過(guò)安裝libpcap-devel(libpcap-dev)的庫(kù)還是直接從頭構(gòu)建。此處已重頭構(gòu)建為例:
yum install -y gcc flex byacc cd /usr/local/source wget http://www.tcpdump.org/release/libpcap-1.9.1.tar.gz tar zxvf libpcap-1.9.1.tar.gz cd libpcap-1.9.1 && ./configure && make
指定編譯參數(shù)
“-lpcap” 這個(gè)參數(shù)既可以用于鏈接動(dòng)態(tài)庫(kù)也可以用于鏈接靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)優(yōu)先, 那么我我們讓go 編譯器在編譯時(shí)執(zhí)行搜索庫(kù)的路徑并把靜態(tài)庫(kù)放置于路徑下即可。
[root@localhost ddk]# CGO_LDFLAGS="-g -O2 -L/usr/local/source/libpcap-1.9.1 -I/usr/local/source/libpcap-1.9.1" go build -ldflags '-w -s' -o main main.go [root@localhost ddk]# ldd main linux-vdso.so.1 => (0x00007fff6cde4000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1e767fa000) libc.so.6 => /lib64/libc.so.6 (0x00007f1e7642c000) /lib64/ld-linux-x86-64.so.2 (0x00007f1e76a16000) [root@localhost ddk]#
稍微解釋下這條編譯的命令CGO_LDFLAGS="-g -O2 -L/usr/local/source/libpcap-1.9.1 -I/usr/local/source/libpcap-1.9.1" go build -ldflags '-w -s' -o main main.go。CGO_LDFLAGS 環(huán)境變量用于指定構(gòu)建時(shí)cgo的參數(shù),-L 指定了查找動(dòng)靜態(tài)庫(kù)的位置,-I 用于指定源碼頭文件的指定路徑,-ldflags '-w -s' 用于去除debug 和符號(hào)表的信息,不加也沒(méi)事。
現(xiàn)在我們可以看到對(duì)libpcap.so的動(dòng)態(tài)庫(kù)依賴(lài)消失了,因?yàn)閘ibpcap已靜態(tài)庫(kù)的方式鏈接進(jìn)了go編譯好的程序。
到此這篇關(guān)于GO編譯時(shí)避免引入外部動(dòng)態(tài)庫(kù)的解決方法的文章就介紹到這了,更多相關(guān)go編譯動(dòng)態(tài)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang實(shí)現(xiàn)超時(shí)退出的三種方式
這篇文章主要介紹了Golang三種方式實(shí)現(xiàn)超時(shí)退出,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Go并發(fā)的方法之goroutine模型與調(diào)度策略
在go中,協(xié)程co-routine被改為goroutine,一個(gè)goroutine只占幾kb,因此可以有大量的goroutine存在,另一方面goroutine 的調(diào)度器非常靈活,本文給大家介紹下Go并發(fā)的方法之goroutine模型與調(diào)度策略,感興趣的朋友一起看看吧2021-11-11
Go語(yǔ)言RPC Authorization進(jìn)行簡(jiǎn)單ip安全驗(yàn)證的方法
這篇文章主要介紹了Go語(yǔ)言RPC Authorization進(jìn)行簡(jiǎn)單ip安全驗(yàn)證的方法,實(shí)例分析了Go語(yǔ)言進(jìn)行ip驗(yàn)證的技巧,需要的朋友可以參考下2015-03-03
Go語(yǔ)言跨平臺(tái)時(shí)字符串中的換行符如何統(tǒng)一?
本文介紹了Go語(yǔ)言中統(tǒng)一換行符的方法,包括使用`strings.ReplaceAll`函數(shù)將Windows風(fēng)格的換行符`\r\n`替換為Unix風(fēng)格的換行符`\n`,或?qū)\n`替換為`\r\n`,統(tǒng)一換行符可以避免不同平臺(tái)間顯示不一致、傳輸時(shí)出現(xiàn)多余的換行符或丟失換行符,以及解析錯(cuò)誤等問(wèn)題2024-11-11
GoFrame代碼優(yōu)化gconv類(lèi)型轉(zhuǎn)換避免重復(fù)定義map
這篇文章主要為大家介紹了GoFrame代碼優(yōu)化gconv類(lèi)型轉(zhuǎn)換避免重復(fù)定義map示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Go獲取兩個(gè)時(shí)間點(diǎn)時(shí)間差的具體實(shí)現(xiàn)
本文主要介紹了Go獲取兩個(gè)時(shí)間點(diǎn)時(shí)間差的具體實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
詳解golang執(zhí)行Linux shell命令完整場(chǎng)景下的使用方法
本文主要介紹了golang執(zhí)行Linux shell命令完整場(chǎng)景下的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Mango?Cache緩存管理庫(kù)TinyLFU源碼解析
這篇文章主要為大家介紹了Mango?Cache緩存管理庫(kù)TinyLFU源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

