静态 link libpng 进入共享库

Static link libpng into a shared library

我已将问题减少到最小程度 test.c:

#include "png.h"

int function() {
    printf("%ld", (long)png_create_read_struct);
}

编译

gcc -shared -fPIC test.c -o test.so -lm -l:libpng16.a

报错

/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/6/../../../x86_64-linux-gnu/libpng16.a(pngread.o): relocation R_X86_64_PC32 against symbol `png_sRGB_table' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value

现在我发现的这个错误的每一个答案都归结为 "do what it says and recompile with -fPIC",但正如你所看到的,我已经在这样做了。那么给出了什么?

(以上输出来自 Ubuntu 17.10 with libpng16。Ubuntu 16.04 with libpng12 导致类似错误。)

Now every answer I've found to this error boils down to "do what it says and recompile with -fPIC", but as you can see I'm already doing that. So what gives?

正如我评论的那样,不,事实上你还没有已经这样做了。 linker 希望从 libpng16.a 中输入的对象 link 是 PIC,但事实并非如此。 这就是它想让你用-fPIC重新编译的东西。

虽然可以将 PIC 对象存储在常规存档中,例如 libpng16.a,但这是非常规的。这些文件通常被称为 "static libraries" 并非没有原因。它们通常旨在支持构建静态二进制文件,而不是共享二进制文件,并且 PIC 对象不满足该目的。您不应期望标准包提供的任何此类存档包含 PIC 对象。

无论如何,由于您正在构建共享库,因此自然而适当的做法是 link 到 libpng 的共享版本。您尝试 link 静态库时遇到了一些麻烦,但不清楚原因。无论您想要完成什么,这都是错误的方法,即使它是值得完成的事情。

使用 -fPIC 编译 libpng

user@user_pc:~/Documents$ mkdir libpng
user@user_pc:~/Documents$ cd libpng
user@user_pc:~/Documents/libpng$ wget https://download.sourceforge.net/libpng/libpng-1.6.37.tar.gz
user@user_pc:~/Documents/libpng$ tar xvfz libpng-1.6.37.tar.gz
user@user_pc:~/Documents/libpng$ cd libpng-1.6.37
user@user_pc:~/Documents/libpng/libpng-1.6.37$./configure --prefix=/home/user/Documents/libpng --with-pic=yes
user@user_pc:~/Documents/libpng/libpng-1.6.37$ sudo make

您的二进制文件在 ~/Documents/libpng/libpng-1.6.37/lib 中,最有趣的是 libpng.a,它现在是用 -fPIC 编译的。

它还解决了在 Linux 上将 blender 作为 Python 模块编译时的问题:

/usr/bin/ld.gold: error: /usr/lib/x86_64-linux-gnu/libpng.a(pngerror.o): requires dynamic R_X86_64_PC32 reloc against 'stderr' which may overflow at runtime; recompile with -fPIC
collect2: error: ld returned 1 exit status