1

The Skinny

I built PHP as an apache module (libphp56.so) and linked it against MacPorts' libcurl. However, httpd fails when launching (via launchd) if libphp56.so is loaded, printing a library version mismatch error.

The Fat

I ran PHP's configure script with --with-curl=/opt/local to link it with /opt/local/lib/libcurl.4.dylib (provided by MacPorts). That copy of libcurl is version 9.0.0, but dyld claims that version 7.0.0 is being loaded, which happens to be the version of /usr/lib/libcurl.4.dylib. For now, I'm assuming the latter is being loaded.

apachectl calls launchctl to run httpd. If run directly, httpd loads libphp56.so and runs without error.

Here's some relevant info from the command line (whitespace added for readability):

$ sudo -s
# apachectl configtest
httpd: Syntax error on line 174 of /private/etc/apache2/httpd.conf: 
Cannot load libexec/apache2/libphp56.so into server: 
dlopen(/Library/WebServer/libexec/apache2/libphp56.so, 10): 
Library not loaded: /opt/local/lib/libcurl.4.dylib

Referenced from: /Library/WebServer/libexec/apache2/libphp56.so
Reason: Incompatible library version: libphp56.so requires version 9.0.0 or later, but libcurl.4.dylib provides version 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
# kill -TERM 6878

# otool -L /opt/local/lib/libcurl.4.dylib | grep libcurl
/opt/local/lib/libcurl.4.dylib:
    /opt/local/lib/libcurl.4.dylib (compatibility version 9.0.0, current version 9.0.0)

# otool -L /usr/lib/libcurl.4.dylib | grep libcurl 
/usr/lib/libcurl.4.dylib:
    /usr/lib/libcurl.4.dylib (compatibility version 7.0.0, current version 8.0.0)

# otool -L /Library/WebServer/libexec/apache2/libphp56.so | grep libcurl
    /opt/local/lib/libcurl.4.dylib (compatibility version 9.0.0, current version 9.0.0)

# echo "x${DYLD_LIBRARY_PATH}x"
xx
# grep -r 'DYLD_.*_PATH' /etc
# launchctl getenv DYLD_LIBRARY_PATH

The launchd.plist for httpd is fairly basic:

<?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>

Setting the dyld reporting environment variables DYLD_PRINT_TO_FILE, DYLD_PRINT_ENV and DYLD_PRINT_LIBRARIES reveals launchd sets DYLD_LIBRARY_PATH and /usr/lib/libcurl.4.dylib is loaded.

# 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: loaded: /usr/lib/libcurl.4.dylib
# echo > ~/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: loaded: /opt/local/lib/libcurl.4.dylib
dyld: unloaded: /opt/local/lib/libcurl.4.dylib
dyld: loaded: /opt/local/lib/libcurl.4.dylib

Note that libcurl isn't the only library to suffer this issue. While troubleshooting, I left out PHP's curl extension as part of the build and got a similar message regarding libxml.

The Question(s)

How can I unset DYLD_LIBRARY_PATH for httpd when run via launchd? What are the security ramifications?

Attempted Solutions

  • launchctl unsetenv DYLD_LIBRARY_PATH
  • setting DYLD_LIBRARY_PATH in org.apache.httpd.plist.
  • have org.apache.httpd.plist run a wrapper for httpd that sets DYLD_LIBRARY_PATH

Non-Solutions

While I could link against the system libcurl, I'm looking for a way to have PHP run with updated components; linking /usr/lib/libcurl.4.dylib is only a last resort. Avoiding launchd entirely, not including the affected PHP extensions/libraries in the build and replacing the system libcurl are also considered non-solutions. I'd almost consider having a wrapper that would move.

System Info

  • OS: Mac OS X 10.10.5 Yosemite.
  • Web server: Apache 2.4.16
  • PHP 5.6.31
  • Did you try env in your launcher? Something like env -iDYLD_LIBRARY_PATH= /usr/sbin/httpd -D FOREGROUND? Did you try to set DYLD_LIBRARY_PATH to /opt/local/lib:/usr/lib in your launcher (in the EnvironmentVariables section)? – xhienne Aug 14 '17 at 19:53
  • @xhienne: un/setting DYLD_LIBRARY_PATH to anything in the launchd.plist and wrapper by any method fails. Also, I don't want to prepend "/opt/local/lib" to the path as there are system libraries I must use over the MacPorts ones (httpd loads /usr/lib/libiconv.2.dylib, so PHP must use the same). – outis Aug 14 '17 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.