问题

问题

瘦子

我将 PHP 构建为 apache 模块 (libphp56.so),并将其链接到 MacPorts 的 libcurl。但是,如果加载了 libphp56.so,httpd 在启动(通过 launchd)时会失败,并打印库版本不匹配错误。

脂肪

我运行 PHP 的配置脚本,--with-curl=/opt/local将其与 /opt/local/lib/libcurl.4.dylib (由 MacPorts 提供)链接。 libcurl 的副本是版本 9.0.0,但 dyld 声称正在加载版本 7.0.0,这恰好是 /usr/lib/libcurl.4.dylib 的版本。目前,我假设后者正在加载。

apachectl调用launchctl运行 httpd。如果直接运行,httpd会加载libphp56.so并且运行不会出错。

以下是来自命令行的一些相关信息(为了可读性添加了空格):

$ sudo -s
#apachectl 配置测试
httpd:/private/etc/apache2/httpd.conf 第 174 行存在语法错误:
无法将 libexec/apache2/libphp56.so 加载到服务器中:
dlopen(/库/WebServer/libexec/apache2/libphp56.so,10):
库未加载:/opt/local/lib/libcurl.4.dylib

引用自:/Library/WebServer/libexec/apache2/libphp56.so
原因:库版本不兼容:libphp56.so需要9.0.0或更高版本,但libcurl.4.dylib提供7.0.0版本

# /usr/sbin/httpd
# ps -ax -O gid | grep /usr/sbin/httpd
 6878 0 ?? SS 0:00.22 /usr/sbin/httpd
 6901 70 ?? S 0:00.00 /usr/sbin/httpd
 6907 0 s008 S+ 0:00.00 grep --color=auto /usr/sbin/httpd
# 杀死-术语 6878

# otool -L /opt/local/lib/libcurl.4.dylib | grep libcurl 函数
/opt/local/lib/libcurl.4.dylib:
    /opt/local/lib/libcurl.4.dylib(兼容版本9.0.0,当前版本9.0.0)

# otool -L /usr/lib/libcurl.4.dylib | grep libcurl 函数
/usr/lib/libcurl.4.dylib:
    /usr/lib/libcurl.4.dylib(兼容版本7.0.0,当前版本8.0.0)

# otool -L /Library/WebServer/libexec/apache2/libphp56.so | grep libcurl 函数
    /opt/local/lib/libcurl.4.dylib(兼容版本9.0.0,当前版本9.0.0)

# 回显“x${DYLD_LIBRARY_PATH}x”
xx
# grep -r 'DYLD_.*_PATH' /etc
# launchctl getenv DYLD_LIBRARY_PATH

httpd 的 launchd.plist 相当基本:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Disabled</key>
    <false/>
    <key>EnvironmentVariables</key>
    <dict>
      <key>XPC_SERVICES_UNAVAILABLE</key>
      <string>1</string>
    </dict>
    <key>KeepAlive</key>
    <dict>
      <key>SuccessfulExit</key>
      <false/>
    </dict>
    <key>Label</key>
    <string>org.apache.httpd</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/sbin/httpd</string>
      <string>-D</string>
      <string>FOREGROUND</string>
    </array>
  </dict>
</plist>

设置迪尔德报告环境变量DYLD_PRINT_TO_FILEDYLD_PRINT_ENVDYLD_PRINT_LIBRARIES显示 launchd 设置 DYLD_LIBRARY_PATH 并加载 /usr/lib/libcurl.4.dylib。

# DYLD_PRINT_TO_FILE=~/httpd.log DYLD_PRINT_ENV=1 DYLD_PRINT_LIBRARIES=1 apachectl configtest
# grep -P 'curl|DYLD_' ~/httpd.log
DYLD_PRINT_TO_FILE=/Users/Capra/httpd.log
DYLD_PRINT_LIBRARIES=1
DYLD_PRINT_ENV=1
DYLD_PRINT_LIBRARIES=1
DYLD_PRINT_TO_FILE=/Users/Capra/httpd.log
DYLD_LIBRARY_PATH=/usr/lib
DYLD_PRINT_ENV=1
dyld:已加载:/usr/lib/libcurl.4.dylib
# 回显 > ~/http.log
# DYLD_PRINT_TO_FILE=~/httpd.log DYLD_PRINT_ENV=1 DYLD_PRINT_LIBRARIES=1 /usr/sbin/httpd -D FOREGROUND
^C
# grep -P 'curl|DYLD_' ~/httpd.log
DYLD_PRINT_TO_FILE=/Users/Capra/httpd.log
DYLD_PRINT_LIBRARIES=1
DYLD_PRINT_ENV=1
dyld:已加载:/opt/local/lib/libcurl.4.dylib
dyld:已卸载:/opt/local/lib/libcurl.4.dylib
dyld:已加载:/opt/local/lib/libcurl.4.dylib

请注意,libcurl 并不是唯一遇到此问题的库。在进行故障排除时,我在构建过程中遗漏了 PHP 的curl 扩展,并收到了有关 libxml 的类似消息。

问题

DYLD_LIBRARY_PATH通过 launchd 运行时如何取消httpd 的设置?安全后果是什么?

尝试的解决方案

  • launchctl unsetenv DYLD_LIBRARY_PATH
  • DYLD_LIBRARY_PATH在 org.apache.httpd.plist 中设置。
  • 让 org.apache.httpd.plist 为 httpd 运行一个包装器来设置DYLD_LIBRARY_PATH

非解决方案

虽然我可以链接到系统 libcurl,但我正在寻找一种让 PHP 使用更新的组件运行的方法;链接 /usr/lib/libcurl.4.dylib 只是最后的手段。完全避免 launchd、不在构建中包含受影响的 PHP 扩展/库以及替换系统 libcurl 也被认为是非解决方案。我几乎会考虑有一个可以移动的包装纸。

系统信息

  • 操作系统:Mac OS X 10.10.5 优胜美地。
  • 网络服务器:Apache 2.4.16
  • PHP 5.6.31

相关内容