解決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)文章
Go語(yǔ)言Grpc?Stream的實(shí)現(xiàn)
本文主要介紹了Go語(yǔ)言Grpc?Stream的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Go語(yǔ)言O(shè)RM框架構(gòu)造查詢(xún)條件示例詳解
這篇文章主要為大家介紹了Go語(yǔ)言O(shè)RM框架構(gòu)造查詢(xún)條件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Gin golang web開(kāi)發(fā)模型綁定實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Gin golang web開(kāi)發(fā)模型綁定實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10我為什么喜歡Go語(yǔ)言(簡(jiǎn)潔的Go語(yǔ)言)
從2000年至今,也寫(xiě)了11年代碼了,期間用過(guò)VB、Delphi、C#、C++、Ruby、Python,一直在尋找一門(mén)符合自己心意和理念的語(yǔ)言。我很在意寫(xiě)代碼時(shí)的手感和執(zhí)行的效率,所以在Go出現(xiàn)之前一直沒(méi)有找到2014-10-10golang控制結(jié)構(gòu)select機(jī)制及使用示例詳解
這篇文章主要介紹了golang控制結(jié)構(gòu)select機(jī)制及使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10golang如何通過(guò)viper讀取config.yaml文件
這篇文章主要介紹了golang通過(guò)viper讀取config.yaml文件,圍繞golang讀取config.yaml文件的相關(guān)資料展開(kāi)詳細(xì)內(nèi)容,需要的小伙伴可以參考一下2022-03-03