使用 make 编译:链接到库

使用 make 编译:链接到库

我正在使用 make 为应用程序编译 PHP。问题是当我执行 ldd php 时,我有这样的东西:

libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007f5b4e661000)

但 libk5crypto.so.3 是一个指向 libk5crypto.so.3.1 的符号

我希望我的 php 直接指向 libk5crypto.so.3.1。

是否可以 ?

编辑:我有一个带有我自己编译的 php 服务器的 Web 应用程序。我不想将其安装在 /etc 中,我只想将其安装在我的应用程序中。

在我的应用程序中,我有一个名为 server 的文件夹,其中存储 php、fop、mapserver 等...

在我的 php 文件夹中,我有一个 lib 文件夹,其中放置了所有依赖项(ldd bin/php)

当我安装应用程序时,我修改文件 /etc/ld.so.conf 以添加来自我的 php 服务器的 lib 目录,然后执行 ldconfig。

有时这些库已经存在于 /usr/lib/x86_64-linux-gnu 中,并且 PHP 会采用该库而不是其文件夹中的库。这几乎不是问题,但有时我在 /usr/lib... 中有一个库,它具有相同的主要版本,但具有较低的次要版本。 PHP 尝试从 /usr/lib 获取它并抛出一个错误,因为 php 是使用最新的依赖项进行编译的。

出于这个原因,我想直接指向 libk5crypto.so.3.1。

当我更新我的应用程序时,我删除了我的 php,然后放置了一个包含所有新库的较新的 php。

另一件事是,我尝试告诉 PHP 查看给定目录中的库,但我的问题是我不知道编译时它会在哪里。

JigglyNaga 的编辑:我编译 PHP,然后编译 imap 和其他扩展。问题出在 php 和扩展上。所以 imap 的编译更短,所以我给你全部。

root@ubuntu16:~/compilPHP/php-7.2.2/ext/imap# make
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=compile cc  -I. -I/root/compilPHP/php-7.2.2/ext/imap -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client  -DHAVE_CONFIG_H  -g -O2   -c /root/compilPHP/php-7.2.2/ext/imap/php_imap.c -o php_imap.lo
mkdir .libs
cc -I. -I/root/compilPHP/php-7.2.2/ext/imap -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client -DHAVE_CONFIG_H -g -O2 -c /root/compilPHP/php-7.2.2/ext/imap/php_imap.c  -fPIC -DPIC -o .libs/php_imap.o
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=link cc -DPHP_ATOM_INC -I/root/compilPHP/php-7.2.2/ext/imap/include -I/root/compilPHP/php-7.2.2/ext/imap/main -I/root/compilPHP/php-7.2.2/ext/imap -I/php/include/php -I/php/include/php/main -I/php/include/php/TSRM -I/php/include/php/Zend -I/php/include/php/ext -I/php/include/php/ext/date/lib -I/usr/include/c-client  -DHAVE_CONFIG_H  -g -O2   -o imap.la -export-dynamic -avoid-version -prefer-pic -module -rpath /root/compilPHP/php-7.2.2/ext/imap/modules  php_imap.lo -Wl,-rpath,/usr/lib/x86_64-linux-gnu/mit-krb5 -L/usr/lib/x86_64-linux-gnu/mit-krb5 -lc-client -lcrypt -lpam -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lssl -lcrypto
cc -shared  .libs/php_imap.o  -L/usr/lib/x86_64-linux-gnu/mit-krb5 -lc-client -lcrypt -lpam -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lssl -lcrypto  -Wl,-rpath -Wl,/usr/lib/x86_64-linux-gnu/mit-krb5 -Wl,-soname -Wl,imap.so -o .libs/imap.so
creating imap.la
(cd .libs && rm -f imap.la && ln -s ../imap.la imap.la)
/bin/bash /root/compilPHP/php-7.2.2/ext/imap/libtool --mode=install cp ./imap.la /root/compilPHP/php-7.2.2/ext/imap/modules
cp ./.libs/imap.so /root/compilPHP/php-7.2.2/ext/imap/modules/imap.so
cp ./.libs/imap.lai /root/compilPHP/php-7.2.2/ext/imap/modules/imap.la
PATH="$PATH:/sbin" ldconfig -n /root/compilPHP/php-7.2.2/ext/imap/modules

最终编辑:它有效,我在制作之前更改了 rpath。 export LDFLAGS='-Wl,-rpath,\$${ORIGIN}/../lib' 非常感谢您的所有回答。

答案1

我不确定这是否可能,但不应该;这是一个非常糟糕的主意。

Library SONAME(libfoo.so.X 的东西)是在库中定义的。您可能认为完整路径位于您的 php 二进制文件中,但事实并非如此;只有 SONAME 是。这就是输出中ldd显示的原因libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3:名称libk5crypto.so.3在这个系统上,解析为该/usr/lib/x86_64-linux-gnu目录下的文件。

libk5crypto.so.3不保证始终可以在该位置找到该文件。路径中的部分x86_64-linux-gnu完全暴露了您正在运行 Debian 或其衍生版本之一;其他仅支持 biarch 而不是完整 multiarch 的发行版(如 Red Hat)/usr/lib64则使用它。这取决于运行时动态链接器,您可以通过使用其配置(通常是)来调试它,ldd以找出找到您的位置。libk5crypto.so.3/etc/ld.so.conf

具有SONAME非常特殊的语义。如果您对完整的技术细节感兴趣,我可以衷心推荐 Ulrich Drepper 的精彩著作文档就此主题而言;但如果没有的话,您应该明白.so.3文件名的部分编码了兼容的API 的一部分。这个想法是,当您libk5crypto由于某种原因更新时,系统会安装新的库,例如libk5crypto.so.3.2,移动符号链接,最后删除旧库。这意味着,只要图书馆还存在兼容 ABI,任何针对它编译的程序都不需要仅仅因为更新库而重新编译。

然而,如果您将库的全名编码到二进制文件中,那么这种优势就完全消失了,因此您必须在库的每次升级时重新编译。你几乎肯定不希望这样。

说了这么多,这个问题似乎是一个XY问题。您到底想要实现什么目标?

答案2

将其添加为另一个答案,因为另一个答案仍然可以独立存在,但您的问题(在您澄清之后)是不同的。如果这是关于随应用程序以及系统附带的库,那么情况就没有可比性。您几乎已经完成了修复它所需的操作,但还没有完全完成:-)

您的问题有多种解决方案:LD_LIBRARY_PATH、、rpath传送更改的库以及多次编译。每个都有其优点和问题,所以让我解释一下:

  • LD_LIBRARY_PATH

    如果您沿着这条路线走下去,那么您可以在运行程序之前设置一个环境变量。它可能要求您在二进制文件周围使用包装器脚本(即,您运行一个首先设置然后运行的/path/to/my/phpshell 脚本,而不是直接运行)。LD_LIBRARY_PATH/path/to/my/php

    这种方法的缺点是它有点脆弱:

    • LD_LIBRARY_PATH被添加到库搜索路径之前,但不会替换它。这意味着,如果有问题的库是在系统范围内安装的,但由于某种原因无法加载您提供的库,则动态链接器将依赖于系统提供的库。
    • 调用 shell 脚本的要求意味着您需要额外的 fork/exec 调用,这可能会导致出现问题。通过在 shell 脚本中使用命令可以在一定程度上缓解这种情况exec(以便脚本被 php 二进制文件替换,并且您的 php 程序是父程序的正确子程序),但它仍然很混乱

    另一方面,它允许您在存储库的位置上具有一定的灵活性(即,如果系统提供的库在某些情况下足够好,那么从目录中删除它就可以了LD_LIBRARY_PATH

  • rpath

    这里的想法是告诉编译器(通过gcc -Wl,-rpath,'/path/to/library')确切地在哪里寻找库。这会在编译时硬编码到程序中,然后动态链接器将绝对忽略您提供的库之外的版本rpath,包括系统提供的版本。这避免了上面的混乱LD_LIBRARY_PATH,但缺点是这使得事情不太灵活;如果您需要在文件系统中移动内容,则需要重新编译所有内容。

    这也意味着,如果您的用户希望看到以不同方式安装的东西,他们就太不走运了。他们可能不喜欢那样。

这两种方法都记录在ld.so手册页中。

  • 运送更改的库

    在这里,我们的想法是,您不是尝试链接到libk5crypto.so.3,而是链接到libmycorp-k5crypto.so.3。在这种情况下,动态链接器获取系统提供的机会为零libk5crypto.so.3。这里的优点是安装后相当简单和优雅;缺点是人们可能会开始怀疑您是否进行了更改libk5crypto(并要求您提供补丁),并且您还必须深入研究libk5crypto.so构建系统以使其真正生成一个libmycorp-k5crypto.so库。从长远来看,它也可能看起来很糟糕,所以在走这条路之前要小心。

  • 多次编译

    您无需交付系统范围内提供的库,而是只需在每个受支持的发行版上编译您的应用程序,并为每个发行版提供一个包,而不是提供您的库。像packagecloud.io使这更容易做到。由于系统上只有一个具有给定名称的库,因此只有一个库可供选择,并且不可能选择错误的库。缺点是您需要测试的东西范围更大,因此您在发布时需要做更多的工作(并且您最好有一个好的测试套件)。

    优点是,此方法可确保您交付的数量少于其他方式(因此您需要支持的数量更少),并且您可以告诉使用libk5crypto.so您不再支持的旧版本的发行版的用户,他们应该先更新一下。

相关内容