解決GO編譯時避免引入外部動態(tài)庫的問題
簡介
最近碰到一個問題,有一個流量采集的組件中使用到了github.com/google/gopacket 這個庫,這個庫使用一切正常,但是唯獨有一個缺點,編譯后的二進制文件依賴于libpcap.so的動態(tài)庫。這為安裝包兼容多個平臺造成了一定的困擾,于是便想著如何把libpcap這個外部依賴已靜態(tài)庫的方式在go程序編譯的同時link進可執(zhí)行程序。
gopacket是如何構(gòu)建的?
此處先截取一小片源碼(github.com/google/gopacket/pcap/pcap_unix.go),此處可以看到在cgo中指定了部分的編譯參數(shù),其中的 "-lpcap" 便是指定link到的庫的名稱??梢哉f是相當(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 抓包的簡單示例 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ù)的長度 Promisc = false // 是否開啟混雜模式 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ī)則 if err = handle.SetBPFFilter(BPF); err != nil { log.Fatal(err) } // 開始獲取流量 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查看依賴庫的使用情況
[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]#
很容易的查看到對libpcap.so.1 這個動態(tài)庫的依賴
準備靜態(tài)庫
找到你的libpcap.so 對應(yīng)的libpcap.a 文件,無論是通過安裝libpcap-devel(libpcap-dev)的庫還是直接從頭構(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” 這個參數(shù)既可以用于鏈接動態(tài)庫也可以用于鏈接靜態(tài)庫,動態(tài)庫優(yōu)先, 那么我我們讓go 編譯器在編譯時執(zhí)行搜索庫的路徑并把靜態(tài)庫放置于路徑下即可。
[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)建時cgo的參數(shù),-L 指定了查找動靜態(tài)庫的位置,-I 用于指定源碼頭文件的指定路徑,-ldflags '-w -s'
用于去除debug 和符號表的信息,不加也沒事。
現(xiàn)在我們可以看到對libpcap.so的動態(tài)庫依賴消失了,因為libpcap已靜態(tài)庫的方式鏈接進了go編譯好的程序。
到此這篇關(guān)于GO編譯時避免引入外部動態(tài)庫的解決方法的文章就介紹到這了,更多相關(guān)go編譯動態(tài)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Gin golang web開發(fā)模型綁定實現(xiàn)過程解析
這篇文章主要介紹了Gin golang web開發(fā)模型綁定實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10golang控制結(jié)構(gòu)select機制及使用示例詳解
這篇文章主要介紹了golang控制結(jié)構(gòu)select機制及使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10golang如何通過viper讀取config.yaml文件
這篇文章主要介紹了golang通過viper讀取config.yaml文件,圍繞golang讀取config.yaml文件的相關(guān)資料展開詳細內(nèi)容,需要的小伙伴可以參考一下2022-03-03