google / gopacket

Provides packet processing capabilities for Go
BSD 3-Clause "New" or "Revised" License
6.34k stars 1.13k forks source link

How to package libraries 'libpcap' into go programs? error while loading shared libraries: libpcap.so.0.8. #734

Open azureskyL opened 4 years ago

azureskyL commented 4 years ago

my go program import gopacket, I use go build -o main main.go to build program, system is Ubuntu 18.04.3 LTS with go version go1.13.1 linux/amd64. when I run the linux executeable program main in CentOS Release 6.10 (Final) Kernel Linux 2.6.32-754.el6.x86_64, which does install go enveriment, it report an error:

[root@localhost Desktop]# ./main ./main: error while loading shared libraries: libpcap.so.0.8: cannot open shared object file: No such file or directory

because CentOS doesn't containlibpcap, my goal is to run go program on the CentOS which dosen't hava libpcap or go enveriment. Is there any way to package libraries 'libpcap' into go programs? How ?

jandos commented 4 years ago

Try this CGO_LDFLAGS+="-Wl,-static -L/usr/lib/x86_64-linux-gnu/libpcap.a -lpcap -Wl,-Bdynamic" go build This will statically link libpcap into your go binary. Make sure you provide correct location of libpcap.a file.

azureskyL commented 4 years ago

@jandos Sorry for the late reply, I tried it, but new problems appeared.

$ locate libpcap.a
/home/zxcasd/libpcap-1.4.0/libpcap.a
/usr/lib/x86_64-linux-gnu/libpcap.a
/usr/local/lib/libpcap.a

$ CGO_LDFLAGS+="-Wl,-static -L/usr/lib/x86_64-linux-gnu/libpcap.a -lpcap -Wl,-Bdynamic" go build main.go 
# github.com/google/gopacket/pcap
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpcap.a(pcap.o): In function `pcap_set_immediate_mode':
(.text+0x850): multiple definition of `pcap_set_immediate_mode'
/tmp/go-build482533506/b111/_x002.o:/home/zxcasd/go/src/github.com/google/gopacket/pcap/pcap_unix.go:52: first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpcap.a(pcap.o): In function `pcap_set_tstamp_precision':
(.text+0x8e0): multiple definition of `pcap_set_tstamp_precision'
/tmp/go-build482533506/b111/_x002.o:/home/zxcasd/go/src/github.com/google/gopacket/pcap/pcap_unix.go:78: first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpcap.a(pcap.o): In function `pcap_get_tstamp_precision':
(.text+0x980): multiple definition of `pcap_get_tstamp_precision'
/tmp/go-build482533506/b111/_x002.o:/home/zxcasd/go/src/github.com/google/gopacket/pcap/pcap_unix.go:85: first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpcap.a(savefile.o): In function `pcap_fopen_offline_with_tstamp_precision':
(.text+0x2e0): multiple definition of `pcap_fopen_offline_with_tstamp_precision'
/tmp/go-build482533506/b111/_x002.o:/home/zxcasd/go/src/github.com/google/gopacket/pcap/pcap_unix.go:74: first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/libpcap.a(savefile.o): In function `pcap_open_offline_with_tstamp_precision':
(.text+0x4f0): multiple definition of `pcap_open_offline_with_tstamp_precision'
/tmp/go-build482533506/b111/_x002.o:/home/zxcasd/go/src/github.com/google/gopacket/pcap/pcap_unix.go:69: first defined here
collect2: error: ld returned 1 exit status

I also tried these commands, but the result is the same.

$ CGO_LDFLAGS+="-Wl,-static -L/home/zxcasd/libpcap-1.4.0/libpcap.a -lpcap -Wl,-Bdynamic" go build main.go  
$ CGO_LDFLAGS+="-Wl,-static -L/usr/local/lib/libpcap.a -lpcap -Wl,-Bdynamic" go build main.go
charles-d-burton commented 4 years ago

You should build a statically compiled binary if you want portability. Try this:

export PCAPV=1.9.1
wget http://www.tcpdump.org/release/libpcap-$PCAPV.tar.gz && \
    tar xvf libpcap-$PCAPV.tar.gz && \
    cd libpcap-$PCAPV && \
    ./configure --with-pcap=linux && \
    make

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --ldflags "-L ./libpcap-$PCAPV -linkmode external -extldflags \"-static\"" -a -o main .
azureskyL commented 4 years ago

You should build a statically compiled binary if you want portability. Try this:

export PCAPV=1.9.1
wget http://www.tcpdump.org/release/libpcap-$PCAPV.tar.gz && \
    tar xvf libpcap-$PCAPV.tar.gz && \
    cd libpcap-$PCAPV && \
    ./configure --with-pcap=linux && \
    make

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --ldflags "-L ./libpcap-$PCAPV -linkmode external -extldflags \"-static\"" -a -o main .

new problems arise, and I didn't find any solution. where should put the folder libpcap-1.9.1 ?

$ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build --ldflags "-L ./libpcap-$PCAPV -linkmode external -extldflags \"-static\"" -a -o main main1.5.go 
# github.com/google/gopacket/pcap
../go/src/github.com/google/gopacket/pcap/pcap.go:30:22: undefined: pcapErrorNotActivated
../go/src/github.com/google/gopacket/pcap/pcap.go:52:17: undefined: pcapTPtr
../go/src/github.com/google/gopacket/pcap/pcap.go:64:10: undefined: pcapPkthdr
alicektx commented 4 years ago

...in my case, after building libpcap, CGO_LDFLAGS+="-L/path/to/libpcap" go build -ldflags="-s -w" main.go

Ie. a simplified version of what jandos said... (as i didn't needed to pull other C libs afterwards). With disabled cgo, i got various complaints (from libc?)... but i didn't researched into it further.

NietzscheX commented 4 years ago

i meet the same issue,it's hard encoded. https://github.com/google/gopacket/blob/master/pcap/pcap_unix.go

/*

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

include

include

include

so you just need do it like this:

yum install libpcap-devel -y

NietzscheX commented 4 years ago
[root@hk libai]# cat a.go 
package main

import (
    "fmt"
    _ "github.com/google/gopacket"
    _ "github.com/google/gopacket/pcap"
)

func main() {
    fmt.Println("It works!")
}

[root@hk libai]#go run a.go 

# github.com/google/gopacket/pcap
../go/pkg/mod/github.com/google/gopacket@v1.1.17/pcap/pcap_unix.go:34:18: fatal error: pcap.h: No such file or directory
 #include <pcap.h>
                  ^
compilation terminated.

[root@hk libai]# yum install libpcap-devel -y
Loaded plugins: fastestmirror
Determining fastest mirrors
 ....
Transaction test succeeded
Running transaction
  Installing : 14:libpcap-devel-1.5.3-11.el7.x86_64                                                                                                               1/1 
  Verifying  : 14:libpcap-devel-1.5.3-11.el7.x86_64                                                                                                               1/1 

Installed:
  libpcap-devel.x86_64 14:1.5.3-11.el7                                                                                                                                

Complete!

[root@hk libai]# go run a.go 
It works!
synfinatic commented 4 years ago

@NietzscheX you just built a dynamically linked binary.

The OP needs to do something like this:

LDFLAGS='-l/usr/lib/libpcap.a' CGO_ENABLED=1 \
    go build -ldflags '-linkmode external -extldflags -static' -o static-binary cmd/*.go

basically this tells go, to use CGO and statically link everything and points at the libpcap archive. Note that with modern gcc, this isn't a perfect solution. You'll end up with the following warnings because you can't link in NSS:

/usr/bin/ld: /tmp/go-link-421168096/000009.o: in function `mygetgrouplist':
/build/golang-1.14-d9PooB/golang-1.14-1.14.3/src/os/user/getgrouplist_unix.go:16: warning: Using 'getgrouplist' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-421168096/000008.o: in function `mygetgrgid_r':
/build/golang-1.14-d9PooB/golang-1.14-1.14.3/src/os/user/cgo_lookup_unix.go:38: warning: Using 'getgrgid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-421168096/000008.o: in function `mygetgrnam_r':
/build/golang-1.14-d9PooB/golang-1.14-1.14.3/src/os/user/cgo_lookup_unix.go:43: warning: Using 'getgrnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-421168096/000008.o: in function `mygetpwnam_r':
/build/golang-1.14-d9PooB/golang-1.14-1.14.3/src/os/user/cgo_lookup_unix.go:33: warning: Using 'getpwnam_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-421168096/000008.o: in function `mygetpwuid_r':
/build/golang-1.14-d9PooB/golang-1.14-1.14.3/src/os/user/cgo_lookup_unix.go:28: warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /tmp/go-link-421168096/000006.o: in function `_cgo_26061493d47f_C2func_getaddrinfo':
/tmp/go-build/cgo-gcc-prolog:58: warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libpcap.a(nametoaddr.o): in function `pcap_nametoaddr':
(.text+0x9): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libpcap.a(nametoaddr.o): in function `pcap_nametonetaddr':
(.text+0x101): warning: Using 'getnetbyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/libpcap.a(nametoaddr.o): in function `pcap_nametoproto':
(.text+0x583): warning: Using 'getprotobyname_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

So there are certain system calls which aren't linkable and will cause crashes. So don't call those above listed functions. Obviously, if anyone has a better way of doing it I'm all ears...

yogihardi commented 3 years ago
export PCAPV=1.9.1
wget http://www.tcpdump.org/release/libpcap-$PCAPV.tar.gz && \
    tar xvf libpcap-$PCAPV.tar.gz && \
    cd libpcap-$PCAPV && \
    ./configure --with-pcap=linux && \
    make

i figured out from @charles-d-burton script, add the following env variables:

export LD_LIBRARY_PATH="-L<pcap path>/libpcap-$PCAPV"
export CGO_LDFLAGS="-L<pcap path>/libpcap-$PCAPV"
export CGO_CPPFLAGS="-I<pcap path>/libpcap-$PCAPV"

go build .  
yxing-xyz commented 1 year ago

Musl-cross:

install musl-cross

export PATH=/home/x/.local/opt/x86_64-linux-musl-cross/bin/:$PATH

libnl

git clone https://github.com/thom311/libnl && cd libnl ./configure --host=x86_64-pc-linux-gnu CC=x86_64-linux-musl-gcc --prefix=/home/x/.local/opt/x86_64-linux-musl-cross/x86_64-linux-musl make && make install

libpcap

git clone git@github.com:the-tcpdump-group/libpcap.git&& cd libpcap ./configure --host=x86_64-pc-linux-gnu CC=x86_64-linux-musl-gcc --prefix=/home/x/.local/opt/x86_64-linux-musl-cross/x86_64-linux-musl --with-pcap=linux make && make install

go build

CGO_ENABLED=1 CC=x86_64-linux-musl-gcc GOOS=linux GOARCH=amd64 go build –ldflags “-linkmode external -extldflags ‘-static -lnl-genl-3 -lnl-3’” -o app main.go