【问题标题】:Trouble installing PHP 5.3.0 with intl-support使用 intl-support 安装 PHP 5.3.0 时遇到问题
【发布时间】:2010-11-07 21:11:49
【问题描述】:

目前我正在尝试在一些 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/icu,PHP 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 的 questions

我从源代码安装了 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 and edit2:

我认为有问题 - 系统上确实有另一个 icu 版本;至少部分(例如,没有其他 icu-config;只有/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 的优先级?

【问题讨论】:

  • 运行ldconfig /usr/local/icu/lib 有帮助吗?
  • icu-config 的输出似乎是正确的。可惜 objdump -C 不起作用。 Afaik libicuuc.so 应该导出 ubrk_close ......也许你可以尝试不带参数?只是“objdump /usr/local/icu/lib/libicuuc.so.42.0.1”,它应该显示这个共享对象已经导出了哪些符号/函数。让我们坚持这个例子:只复制&粘贴 ubrk_close/ubrk_close_4_2 的条目。顺便说一句:您还没有在构建 ICU 和 PHP 之间切换编译器(或例如 gcc 的主要版本)?
  • 在 VolkerK 发表评论后编辑问题。
  • 您也可以在构建时尝试跟踪 open() 调用。这样你就可以看到打开了哪些文件。也许它会揭示构建过程期望 libicu 位于哪个位置。
  • @Sander Marechal:我该怎么做(“跟踪 open() 调用”)?尽管我设法构建了我尝试过的几乎所有软件(PHP 5.3 除外;-)

标签: php linux installation intl


【解决方案1】:

问题似乎是二进制文件链接到错误的(共享)库文件。
首先是对我认为问题所在的冗长而无聊的解释。请记住,我不是 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 的顺序。即

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.x.y。这个 libicuuc.so.34.x.y 不导出 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.x.y 链接,gcc/链接器将找不到它们并且不会链接到旧版本。
再次因为已经链接到旧版本的 SONAME 属性二进制文件仍然可以运行,因为“他们的”加载程序将搜索(仍然存在的)libicuXY.so.34 文件。
这将影响所有后续的链接器运行,即如果您构建另一个使用旧包含文件的项目,您将遇到同样的问题。头文件和共享对象(在链接时)必须匹配。

【讨论】:

  • 很好的解释和大量的工作 - 虽然我可以在星期一之前测试你提出的解决方案,但我接受了你的回答,因为它为傻瓜(比如我自己)提供了一个非常好的洞察力来了解这个主题(至对我来说有点神秘)。
  • 我知道这有多令人沮丧 ;-) 如果它不起作用,请告诉我。虚拟机中的 imho gentoo 是修补 linux 和新源包的好东西(尽管还没有 php 5.3 ebuild)
  • OK - 在我将所有 libicuXY.so 符号链接重命名为 /usr/lib64 中的 libicuXY.so.old 以便使用 ICU 4.2 库之后,现在编译整个内容。但现在似乎还有另一个问题:“make test”显示 9999/9999 测试要么失败,要么被跳过。但这也发生在没有 icu 被编译成 PHP 的情况下。下一个要解决的问题 ;-) 再次感谢您的努力!
  • 全部失败?哎哟!尽管如此,它仍然可能是共享对象的问题。测试日志会告诉你 ;-)
  • OK - 发现问题。我不知道 make test 使用了我当前安装的 PHP 版本 (/usr/local/php/lib/php-cli.ini) 的 php-cli.ini。这会导致在每个测试中生成一个警告,即 register_long_arrays 已被弃用,从而导致所有测试的测试失败。
【解决方案2】:

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,但是如果您只想让它工作,那么修改该文件并不是什么大忌讳。

【讨论】:

  • 对不起 - 不。那没有成功。编辑 ld.so.conf 或将 icu 安装到“标准”库路径都没有显示一些结果。是否存在与构建过程运行的 64 位环境相关的问题?
【解决方案3】:

当你打电话时

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 示例。 This presentation (PPT) 有几个简单的例子。

编辑

我想我明白了。看起来 php-intl 仅适用于 libicu 3.6 或 3.8。我已经在谷歌上搜索过发布 php-intl 的 Linux 发行版,它们都依赖于 libicu 3.8,即使它们也发布了 libicu 4.0 或更高版本。 last changelog before intl became part of php itself 表示相同。

我建议安装 libicu 3.8 并重试。

【讨论】:

  • 我也想过,但是:错误消息与不在 LD_LIBRARY_PATH 中的 icu-lib-dir 相同,将 icu-lib-dir 作为 LD_LIBRARY_PATH 中的唯一目录和 icu -lib-dir 附加到 LD_LIBRARY_PATH。编译似乎没有找到库。
猜你喜欢
  • 2020-03-10
  • 2012-04-17
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-20
  • 2012-01-22
  • 2021-01-16
相关资源
最近更新 更多