5

目前我正在尝试在一些 Linux 测试服务器上安装 PHP 5.3.0。由于我们急切地等待 ext/intl,我们想看看它提供的功能。我configure使用以下参数成功运行

./configure
    --with-apxs2=/usr/local/apache2/bin/apxs
    --prefix=/usr/local/php
    --with-zlib-dir=/usr/local/zlib
    --with-imap=/.../imap-2006k
    --with-imap-ssl
    --with-openssl=shared
    --with-iconv=shared
    --with-zlib=shared
    --with-curl=shared
    --with-curlwrappers
    --enable-exif
    --with-ldap=shared,/usr/local/openldap
    --with-ldap-sasl
    --enable-mbstring=shared
    --with-mcrypt
    --enable-soap=shared
    --enable-sockets
    --enable-zip=shared
    --enable-pdo=shared
    --with-pdo-sqlite=shared
    --with-sqlite=shared
    --with-mysql=shared,/usr/local/mysql
    --with-pdo-mysql=shared,/usr/local/mysql
    --with-mysqli=shared,/usr/local/mysql/bin/mysql_config
    --with-mhash=shared,/usr/local/mhash
    --with-libxml-dir=/usr/local/libxml2
    --with-xsl=shared,/usr/local/libxslt
    --enable-xmlreader=shared
    --enable-xmlwriter=shared
    --with-gmp=shared
    --with-icu-dir=/usr/local/icu
    --enable-intl

ICU 4.2 位于/usr/local/icuPHP 5.2.9 编译完美(没有 int 和 icu 选项)。但是当我编译 PHP 5.3.0 源代码时,我会收到很多类似的错误消息

ext/intl/grapheme/.libs/grapheme_util.o(.text+0xbab):/.../php-5.3.0/ext/intl/grapheme/grapheme_util.c:208: undefined reference to `ubrk_close_4_2'

我很确定这与找不到共享库有关。环境

export LD_LIBRARY_PATH=/usr/local/icu/lib

没有帮助。

谁能指出我的一些解决方案?我相当一无所知-而且我在这些事情上也不是真正的专家...

编辑:

我刚刚重新检查并确保各种 icu 库和各自的软链接都位于/usr/local/icu/lib

lrwxrwxrwx  1 root root       20 Jul  1 09:56 libicudata.so -> libicudata.so.42.0.1
lrwxrwxrwx  1 root root       20 Jul  1 09:56 libicudata.so.42 -> libicudata.so.42.0.1
-rw-r--r--  1 root root 16015140 Jul  1 09:56 libicudata.so.42.0.1
lrwxrwxrwx  1 root root       20 Jul  1 09:56 libicui18n.so -> libicui18n.so.42.0.1
lrwxrwxrwx  1 root root       20 Jul  1 09:56 libicui18n.so.42 -> libicui18n.so.42.0.1
-rwxr-xr-x  1 root root  2454770 Jul  1 09:56 libicui18n.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuio.so -> libicuio.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuio.so.42 -> libicuio.so.42.0.1
-rwxr-xr-x  1 root root    65299 Jul  1 09:56 libicuio.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicule.so -> libicule.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicule.so.42 -> libicule.so.42.0.1
-rwxr-xr-x  1 root root   356125 Jul  1 09:56 libicule.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libiculx.so -> libiculx.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libiculx.so.42 -> libiculx.so.42.0.1
-rwxr-xr-x  1 root root    75110 Jul  1 09:56 libiculx.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicutu.so -> libicutu.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicutu.so.42 -> libicutu.so.42.0.1
-rwxr-xr-x  1 root root   159330 Jul  1 09:56 libicutu.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuuc.so -> libicuuc.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuuc.so.42 -> libicuuc.so.42.0.1
-rwxr-xr-x  1 root root  1660769 Jul  1 09:56 libicuuc.so.42.0.1

make check运行大量测试 - 所有测试都成功:

[All tests passed successfully...]
Elapsed Time: 00:00:25.000
make[2]: Leaving directory `/.../icu-4.2/source/test/cintltst'
---------------
ALL TESTS SUMMARY:
All tests OK:  testdata intltest iotest cintltst
make[1]: Leaving directory `/.../icu-4.2/source/test'
make[1]: Entering directory `/.../icu-4.2/source'
verifying that icu-config --selfcheck can operate
verifying that make -f Makefile.inc selfcheck can operate
PASS: config selfcheck OK
make[1]: Leaving directory `/.../icu-4.2/source'

编辑:VolkerK 问题的答案

我从源代码安装了 ICU 4.2,正如我在构建过程上方所写的那样,单元测试和安装都很好。

/usr/local/icu/bin/icu-config --version
4.2.0.1

/usr/local/icu/bin/icu-config --prefix
/usr/local/icu

/usr/local/icu/bin/icu-config --cppflags-searchpath
-I/usr/local/icu/include

/usr/local/icu/bin/icu-config --ldflags --ldflags-icuio
-lpthread -lm   -L/usr/local/icu/lib -licui18n -licuuc -licudata  -lpthread -lm   -licuio

objdump -C /usr/local/icu/lib/libicuuc.so.42.0.1
// doesn't work because of unrecognized argument -C

编辑关于 VolkerK 的评论:

不,没有涉及编译器的切换——我一个接一个地直接运行了两个构建过程。objdump /usr/local/icu/lib/libicuuc.so.42.0.1也不起作用,但我设法跑了

objdump -t /usr/local/icu/lib/libicuuc.so.42.0.1 | grep ubrk_close
00000000000d2484 g     F .text  000000000000002d              ubrk_close_4_2

不知道这些信息是否有帮助。

编辑 VolkerK 的edit1 和 edit2

我认为有问题 - 系统上确实有另一个 icu 版本;至少在部分(例如,没有其他 icu-config;只有一个 in /usr/local/icu/bin)。

gcc -lpthread -lm -L/usr/local/icu/lib -licui18n -licuuc -licudata -lpthread -lm -licuio -print-file-name=libicuuc.so返回

/usr/lib64/gcc-lib/x86_64-suse-linux/3.3.5/../../../../lib64/libicuuc.so

gcc -lpthread -lm -L/usr/local/icu/lib -licui18n -licuuc -licudata -lpthread -lm -licuio -print-file-name=libicuuc.so.42返回

libicuuc.so.42

所以问题似乎是,如何让新的 lib-path 进入构建过程?顺便说一句,我从你的回答中学到了很多——谢谢大家。

我还尝试编译您的简单测试程序 - 它也因相同的未定义引用错误而失败,很可能是由于 PHP 无法编译的相同原因。

如何摆脱对 lib-path 中旧 icu-library 的引用,或者如何优先考虑新的 icu-library-path?

4

3 回答 3

6

问题似乎是二进制文件链接到错误的(共享)库文件。
首先是对我认为问题所在的冗长而无聊的解释。请记住,我不是 Linux 专家。我真的希望您了解我的思路,以便您可以决定它是否可行和/或我错在哪里。
第一个(粗)解决方案很容易可逆。运行另一个 ./configure 并且所有更改都是历史记录。我觉得还挺省的。

为什么你首先有 icu 4-2 特定的依赖项?我们来看一个php的intl扩展的源文件(ext/intl/grapheme/grapheme_string.c)

#include <unicode/ubrk.h>
...
PHP_FUNCTION(grapheme_substr)
{
   ...
   ubrk_close(bi);
   ...

到目前为止,还没有特定于版本的代码。无论您使用 icu 3.4 还是 icu 4.2,grapheme_string.c 看起来都一样。ubrk_close_4_2 来自哪里?
当您运行“./configure ... --with-icu-dir=/usr/local/icu”命令时,将执行文件 ext/intl/config.m4。在这个过程中调用icu-config 来获取构建php 所需的包含路径和库文件。您提供了 icu 安装的路径,归结为

ICU_CONFIG="$PHP_ICU_DIR/bin/icu-config"
ICU_INCS=`$ICU_CONFIG --cppflags-searchpath`
ICU_LIBS=`$ICU_CONFIG --ldflags --ldflags-icuio`

被执行。您自己尝试过 icu-config,因此您知道它输出什么以及 ICU_INCS 和 ICU_LIBS 包含什么。当文件被编译/链接时,ICU_INCS 和 ICU_LIBS 被传递给 gcc。gcc(显然)在其默认目录中没有找到 unicode/ubrk.h,因此它在 ICU_INCS 提供的其他包含目录中搜索该文件,并在其中找到了 icu 4.2 包含文件。unicode/ubrk.h 包含 unicode/utypes.h,然后包含 unicode/urename.h - 再次包含 icu 4.2 头文件。在这种情况下,unicode/urename.h 包括#define ubrk_close ubrk_close_4_2。
当预处理器完成时,ubrk_close(bi) 已被 ubrk_close_4_2(bi) 取代。

PHP_FUNCTION(grapheme_substr)
{
   ...
   ubrk_close_4_2(bi);
   ...

现在您有了一个特定于版本的依赖项,即某个库必须解决的对 ubrk_close_4_2 的引用。
所以包含部分确实有效。它确实找到了您的 icu 4.2 版本并使用了它的头文件。到现在为止还挺好。
现在是链接器部分。在您的情况下 ICU_LIBS 包含

-lpthread -lm -L/usr/local/icu/lib -licui18n -licuuc -licudata -lpthread -lm -licuio

-licuuc 告诉 gcc “给我找一个名为 'icuuc' 的库并使用它”。然后 gcc 在 LIB 路径中搜索具有与“icuuc”匹配的特定命名方案的文件。
在这种情况下,libicuuc.so。请注意,它不查找特定于版本的文件名,只查找 libicuuc.so。一旦找到这样的文件,它就不会再寻找另一个文件。首先 gcc 在其默认路径中搜索。然后它搜索额外的库路径——按照它们提供给 gcc 的顺序。IE

gcc -L/usr/lib -L/usr/local/lib -licuuc

如果有这样的文件而不是 /usr/local/lib/libicuuc.so (不再),将找到 /usr/lib/libicuuc.so。这意味着默认路径或库路径指令的顺序可能是您遇到问题的原因。
当您的程序与共享对象链接时,“特殊”加载程序将添加到代码中,并且共享对象的名称存储在您的程序中(在链接时)。
每次执行程序时,(运行时)加载程序首先搜索共享对象(按其名称),加载代码并替换一些存根跳转地址。
共享对象可以“告诉”链接器(即在链接时)加载程序在运行时应该查找的共享对象的名称(SONAME 属性)。查看您在问题文本中提供的目录列表

lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuuc.so -> libicuuc.so.42.0.1
lrwxrwxrwx  1 root root       18 Jul  1 09:56 libicuuc.so.42 -> libicuuc.so.42.0.1
-rwxr-xr-x  1 root root  1660769 Jul  1 09:56 libicuuc.so.42.0.1

libicuuc.so,这是 gcc 在提供 -licuuc 时要查找的文件。链接器遵循符号链接并使用 libicuuc.so.42.0.1。该文件“告诉”链接器(运行时)加载程序应该查找 libicuuc.so.42,请参见http://userguide.icu-project.org/packaging#TOC-ICU-Versions
加载程序将遵循符号链接并加载 libicuuc.so.42.0.1,或者如果有另一个错误修复 libicuuc.so.42.0.2,libicuuc.so.42.0.3,无论 libicuuc.so.42 指向什么。libicuuc.so.42 将/应该始终指向导出 icu 4.2 符号的实际共享对象。代码可能已更改/修复,但导出的符号保持不变。你现在的问题是 gcc 没有找到 libicuuc.so->libicuuc.so.42.0.1 但是(比方说) libicuuc.so->libicuuc.so.34.xy 这个 libicuuc.so.34.xy 没有导出 icu 4.2 符号,它不提供 ubrk_close_4_2 而是提供 ubrk_close_3_4。因此,没有 ubrk_close_4_2 -> 未解决的参考错误。

第一个“解决方案”(粗略):让 ./configure 发挥它的魔力,然后......只需编辑 Makefile。
在文本编辑器中打开 Makefile(在源代码顶级目录中),搜索 INTL_SHARED_LIBADD= 并替换

-licui18n -licuuc -licudata -licuio

在那一行中

/usr/local/icu/lib/libicui18n.so.42 /usr/local/icu/lib/libicuuc.so.42 /usr/local/icu/lib/libicudata.so.42 /usr/local/icu/lib /libicuio.so.42

(保留任何 -lm -pthread ... 原样)。再次编译。
这“告诉” gcc/链接器不要搜索 .so 文件,而是使用特定的文件。结果应该与您的库路径正常工作相同(因为 SONAME)。
但是每次运行 ./configure 时,都必须再次应用“修复”。

第二种解决方案:删除其他 libicuXY.so 符号链接(这就是想到“备份”一词的地方),只保留 libicuXY.so->libicuXY.so.42.0.1 链接。如果没有其他 libicuuc.so->>libicuuc.so.34.xy 链接,gcc/链接器将无法找到它们并且不会链接到旧版本。
再次因为已经链接到旧版本的 SONAME 属性二进制文件仍然可以运行,因为“他们的”加载程序将搜索(仍然存在的)libicuXY.so.34 文件。
这将影响所有后续的链接器运行,即如果您构建另一个使用旧包含文件的项目,您将遇到同样的问题。头文件和共享对象(在链接时)必须匹配。

于 2009-07-11T17:34:57.343 回答
0

你打电话时

export LD_LIBRARY_PATH=/usr/local/icu/lib

那么您将覆盖当前设置的路径。所以它可能会找到 ICU,但它不会找到它需要的任何其他库。试试这个:

export LD_LIBRARY_PATH=/usr/local/icu/lib:${LD_LIBRARY_PATH}

如果这没有帮助,我可以想到两件事来尝试:

  1. 图书馆在正确的地方吗?也许您的安装移到了其他地方,例如/usr/local/lib/icu
  2. ICU有用吗?尝试 ICU 的“make check”目标。尝试编译/运行 ICU 中包含的测试套件,或者尝试编译并运行一个简单的 ICU 示例。这个演示文稿(PPT)有几个简单的例子。

编辑

我想我想通了。看起来 php-intl 仅适用于 libicu 3.6 或 3.8。我已经在谷歌上搜索过发布 php-intl 的 Linux 发行版,它们都依赖于 libicu 3.8,即使它们也发布了 libicu 4.0 或更高版本。intl 成为 php 本身的一部分之前的最后一个变更日志表明相同。

我建议安装 libicu 3.8 并重试。

于 2009-07-06T07:40:23.367 回答
0

很有可能ld不知道在哪里可以找到这些库。您将不得不更新 LD_LIBRARY_PATH(每次),或者让 ldconfig 了解您的新库。

您可以:

  • 将其安装在 /usr/local/lib 或 /usr/lib
  • 将其位置添加到 /etc/ld.so.conf 并重新运行 /sbin/ldconfig

现在,即使 ldconfig 由任何安装的库运行,ldconfig 也不知道它的位置,因为 /usr/local/icu/lib 不在它的范围内。如果库安装到 /usr/local/lib/icu,ldconfig 会知道在哪里可以找到它,而您不必手动指定 LD 路径。

我建议在修改 ld.so.conf 之前将库重新安装到 /usr/local/lib 并运行 ldconfig,但是如果您只想让它工作,那么修改该文件并不是什么大忌。

于 2009-07-08T00:36:48.083 回答