R 语言中的 libpng 版本冲突
事情起因是在 R 语言中调用 png
包的 readPNG
读取 png 图片的时候,碰到了错误:libpng error: Incompatible libpng version in application and library。
> library(png)
> p1 = readPNG("/bioinfo/polyA/circos.png")
Error in readPNG("/bioinfo/polyA/circos.png") :
libpng error: Incompatible libpng version in application and library
In addition: Warning messages:
1: In readPNG("/bioinfo/polyA/circos.png") :
libpng warning: Application was compiled with png.h from libpng-1.6.37
2: In readPNG("/bioinfo/polyA/circos.png") :
libpng warning: Application is running with png.c from libpng-1.2.49
>
这个问题,其实在 《RamiGO 安装及库依赖解决备忘》曾经遇到过,当时的解决方法,在现在看起来其实是并不完善的。所以,在问题解决前,我们先来看看这个问题到底是怎么导致的。
首先,我的 R 是通过源码编译安装的,而且在安装的过程中 configure
时候指定了自己安装的 libpng-1.6.37。
./configure --prefix=bioinfo/software/r/r-4.4.2 --enable-R-shlib --with-libtiff --with-libpng --with-jpeglib --with-pcre1 \
LDFLAGS="-L/bioinfo/software/mylibs/zlib-1.2.6/lib \
-L/bioinfo/software/mylibs/bzip2-1.0.6/lib \
-L/bioinfo/software/mylibs/pcre-8.40/lib \
-L/bioinfo/software/mylibs/tiff-4.0.9/lib \
-L/bioinfo/software/mylibs/jpeg-9c/lib \
-L/bioinfo/software/mylibs/libpng-1.6.37/lib \
-L/bioinfo/software/mylibs/xz-5.2.3/lib \
-L/bioinfo/software/mylibs/curl-7.64.1/lib -fopenmp" \
CPPFLAGS="-I/bioinfo/software/mylibs/zlib-1.2.6/include \
-I/bioinfo/software/mylibs/bzip2-1.0.6/include \
-I/bioinfo/software/mylibs/pcre-8.40/include \
-I/bioinfo/software/mylibs/tiff-4.0.9/include \
-I/bioinfo/software/mylibs/jpeg-9c/include \
-I/bioinfo/software/mylibs/libpng-1.6.37/include \
-I/bioinfo/software/mylibs/xz-5.2.3/include \
-I/bioinfo/software/mylibs/curl-7.64.1/include"
第二,我使用的 png
是在 R 里面直接 install.package('png')
安装的。
$ ldd /bioinfo/software/r/r-4.4.2/lib64/R/library/png/libs/png.so
linux-vdso.so.1 => (0x00007fff29dd9000)
libpng12.so.0 => /usr/lib64/libpng12.so.0 (0x00007f1a614bc000)
libz.so.1 => /bioinfo/software/r-3.3.2/lib/libz.so.1 (0x00007f1a612a4000)
libm.so.6 => /lib64/libm.so.6 (0x00007f1a61020000)
libR.so => /bioinfo/software/r/r-3.6.1/lib64/R/lib/libR.so (0x00007f1a6098e000)
libgomp.so.1 => bioinfo/software/gcc-7.3.0/lib64/libgomp.so.1 (0x00007f1a60760000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1a60543000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1a601af000)
libRblas.so => /bioinfo/software/r/r-3.6.1/lib64/R/lib/libRblas.so (0x00007f1a5ff83000)
libgfortran.so.3 => /usr/lib64/libgfortran.so.3 (0x00007f1a5fc91000)
libreadline.so.6 => /lib64/libreadline.so.6 (0x00007f1a5fa4e000)
libpcre.so.1 => /bioinfo/software/r-3.3.2/lib/libpcre.so.1 (0x00007f1a5f81b000)
liblzma.so.5 => /bioinfo/software/r-3.3.2/lib/liblzma.so.5 (0x00007f1a5f5f6000)
librt.so.1 => /lib64/librt.so.1 (0x00007f1a5f3ee000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1a5f1e9000)
libiconv.so.2 => /usr/local/lib/libiconv.so.2 (0x00007f1a5ef04000)
/lib64/ld-linux-x86-64.so.2 (0x0000003636a00000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f1a5ece2000)
从 ldd
的结果可以很明显看到,install.package('png')
使用了系统默认的 libpng
,也就是对应的 libpng-1.2.49
。因此最后在调用 png
的时候就和编译使用的 libpng-1.6.37
发生了冲突。
第三,所以最终的解决方法就是,先设置 libpng-1.6.37
的 PATH
和 LD_LIBRARY_PATH
。
export PATH=/bioinfo/software/mylib/libpng-1.6.37/bin:$PATH
export LD_LIBRARY_PATH=/bioinfo/software/mylib/libpng-1.6.37/lib:$LD_LIBRARY_PATH
卸载原来的 png
包,再重新安装。
remove.packages('png')
options("repos"=c(CRAN="https://mirrors.tuna.tsinghua.edu.cn/CRAN/"))
install.packages('png')
总的来说,最开始碰到这个问题的时候,虽然知道问题在哪,也设置过 LD_LIBRARY_PATH
后去重装 png
,但是一直都没成功,后面尝试了几个方法。
一是,怎么在 install.packages()
中指定 libpng-1.6.37 的 LDFLAGS
和 CPPFLAGS
,因为没搞懂 --configure-args
具体是怎么用的,这条路没走通。另外,在 HOME/.R/Makevars
设置了 LDFLAGS
和 CPPFLAGS
进行了尝试,也依然不起作用。
二是,想通过 patchelf
去直接修改 png.so
的动态库链接,虽然修改成功,但直接把 png
搞崩溃。
直至把 libpng-1.6.37 的 bin 也一起增加到 PATH
,才重装 png
后,这个问题才最终解决。个人猜测在安装 png
时检测 libpng 的过程中应该跟 libpng-config
的可执行文件有关系,因为系统默认的 /usr/bin/libpng-config
为 1.2.49 版本,而 libpng-1.6.37 的 bin/libpng-config
默认软连接至 bin/libpng16-config
,对应 1.6.37。
事后,去 png
的源码仓库一看,果然在 src/Makevars
中发现了链接库和依赖中调用了 libpng-config
:
PKG_LIBS=$(PNG_LIBS) `libpng-config --static --ldflags`
PKG_CFLAGS=$(PNG_CFLAGS) `libpng-config --cflags`

而系统的 libpng-config
和 libpng-1.6.37 的 bin/libpng-config
的链接库和依赖:
$ /usr/bin/libpng-config --static --ldflags
-L/usr/lib64 -lpng12 -lz -lm
$ /bioinfo/software/mylib/libpng-1.6.37/bin/libpng-config --static --ldflags
-L/bioinfo/software/mylib/libpng-1.6.37/lib -lpng16 -lm -lz -lm
正好印证了在安装 png
时,的确需要从默认 PATH
中调用 libpng-config
,从而获取对应的链接库和依赖。