zfl9 / dns2tcp

将 dns 查询从 udp 转为 tcp 的实用工具
GNU Affero General Public License v3.0
138 stars 54 forks source link

能否增加一个静态编译的选项? #1

Closed pexcn closed 5 years ago

pexcn commented 5 years ago

比如:make STATIC=1, 我试了一下这样改是可以静态链接的

diff --git a/Makefile b/Makefile
index a66b4cb..37153c4 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 CC = gcc
-CFLAGS = -std=c99 -Wall -Wextra -O3
+CFLAGS = -std=c99 -Wall -Wextra -O3 -pipe
 INCLUDES =
-LDFLAGS =
-LIBS = -luv
+LDFLAGS = -Wl,--build-id=none -static
+LIBS = -luv -lpthread
 SRCS = netutils.c dns2tcp.c
 OBJS = $(SRCS:.c=.o)
 MAIN = dns2tcp
root@ROC:~/dns2tcp# make
gcc -std=c99 -Wall -Wextra -O3 -pipe  -c netutils.c -o netutils.o
gcc -std=c99 -Wall -Wextra -O3 -pipe  -c dns2tcp.c -o dns2tcp.o
gcc -std=c99 -Wall -Wextra -O3 -pipe  -s -o dns2tcp netutils.o dns2tcp.o -Wl,--build-id=none -static -luv -lpthread
/usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libuv.a(libuv_la-core.o): In function `uv__getpwuid_r':
(.text+0x16e0): warning: Using 'getpwuid_r' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
root@ROC:~/dns2tcp# file dns2tcp
dns2tcp: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, stripped
root@ROC:~/dns2tcp# nm dns2tcp
nm: dns2tcp: no symbols
root@ROC:~/dns2tcp# ldd dns2tcp
        not a dynamic executable
root@ROC:~/dns2tcp# ./dns2tcp -h
usage: dns2tcp <-L LISTEN_ADDR> <-R REMOTE_ADDR> [-vVh]
 -L <ip#port>           udp listen address, it is required
 -R <ip#port>           tcp remote address, it is required
 -v                     print verbose log, default: <disabled>
 -V                     print version number of dns2tcp and exit
 -h                     print help information of dns2tcp and exit
bug report: https://github.com/zfl9/dns2tcp. email: zfl9.com@gmail.com
zfl9 commented 5 years ago

readme 中的这种编译方式其实和静态编译差不多,不推荐“全静态连接”,glibc某些函数如果静态链接,运行时会有问题。上面其实可以看到一些 gcc 的警告信息,说的就是这种情况。

如果你希望将 libuv 依赖库静态链接到 dns2tcp 可执行文件中,可按照如下步骤进行编译:


# 进入某个目录
cd /opt

获取 libuv 源码包

libuv_version="1.31.0" wget https://github.com/libuv/libuv/archive/v$libuv_version.tar.gz -Olibuv-$libuv_version.tar.gz tar xvf libuv-$libuv_version.tar.gz

进入源码目录,编译

cd libuv-$libuv_version ./autogen.sh ./configure --prefix=/opt/libuv --enable-shared=no --enable-static=yes CC="gcc -O3" make && sudo make install cd ..

获取 dns2tcp 源码

git clone https://github.com/zfl9/dns2tcp

进入源码目录,编译

cd dns2tcp make CFLAGS="-pthread" INCLUDES="-I/opt/libuv/include" LDFLAGS="-L/opt/libuv/lib" && sudo make install

pexcn commented 5 years ago

嗯嗯,其实我是想把它移植到 openwrt 里面,静态编译就可以少安装一个 libuv 的包了

zfl9 commented 5 years ago

按照这个方式编译其实就不需要 libuv 相关的东西了。

zfl9 commented 5 years ago

注意字眼:将 libuv 依赖库静态链接到 dns2tcp 可执行文件中

pexcn commented 5 years ago

这是仅静态链接 libuv ,嗯嗯大概懂了~

zfl9 commented 5 years ago

通常我个人喜欢的做法是,第三方依赖,静态链接进去,glibc 还是不要静态链接了。

zfl9 commented 5 years ago

这是仅静态链接 libuv ,嗯嗯大概懂了~

但这就够了(99%的情况下都没问题的)。直接拷贝 binary 文件到目标主机上运行即可。

pexcn commented 5 years ago

如果静态链接了 glibc,假如用 openwrt-18.06 的 sdk 编译运行正常,然后到了 openwrt-19.07 的环境下运行就会可能出错?

zfl9 commented 5 years ago

具体不是太了解,比如 getaddrinfo() 这个解析域名的 api,如果静态链接进去了,编译时只是一个警告,但是运行的时候,会出现段错误。类似的例子应该挺多的。

pexcn commented 5 years ago

嗯,好的

zfl9 commented 5 years ago

这是使用readme的方式静态编译的 dns2tcp:

$ file dns2tcp
dns2tcp: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=53737165ba201d8624f3d38b3b3bdceab76e15d6, for GNU/Linux 3.2.0, stripped
$ ldd dns2tcp
    linux-vdso.so.1 (0x00007ffdacc66000)
    libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f40c3c14000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007f40c3a51000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f40c3c70000)

可以看到就只有 pthread、libc 两个动态链接库,所以没有问题的。我将它拷贝到其它linux x86上照常运行。当然 openwrt 也是同样的道理,我自己也是将这些运行在树莓派上的,也是交叉编译过去的。

pexcn commented 5 years ago

嗯,清楚了,只是 openwrt 的 Makefile 我还不知道应该怎么写... 😄