0

I'm doing a compilation of PHP for an application with make. The problem is when I do a ldd php I have something like this:

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

But libk5crypto.so.3 is a symlic that point to libk5crypto.so.3.1

I would like my php to point directly to libk5crypto.so.3.1.

Is-it possible ?

EDIT: I have a web application with a php server that I compile myself. I don't want to install it in /etc, I just want it to be inside my application.

Inside my application I have a folder named server where I store php, fop, mapserver etc...

Inside my php folder, I have a lib folder and inside I put all dependencies (ldd bin/php)

When I install my application, I modify the file /etc/ld.so.conf to add the lib dir from my php server, then I do a ldconfig.

Sometimes the libs already exists in /usr/lib/x86_64-linux-gnu and PHP take this libs instead the one on his folder. It's nearly not a problem, but sometimes I have a lib inside /usr/lib... that have the same major version but has a lower minor version. PHP tries to get it from /usr/lib and thrown me an error because php was copile with the newest dependencies.

Is for that reason that I want to point to libk5crypto.so.3.1 directly.

When I update my application, I delete my php and I put a newer one with all the new libs.

Another things, I try to tell PHP to look the libs in a given directory, but my problem I don't know where it will be at compile time.

EDIT for JigglyNaga : I compile PHP, Then I compile imap and others extensions. The problem is with php and the extension. So the compilation is shorter for imap so I give you all.

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

FINAL EDIT: It worked, I change the rpath before making the make. export LDFLAGS='-Wl,-rpath,\$${ORIGIN}/../lib' Thanks a lot for all your answers.

  • make runs a series of separate commands to create the php executable. Can you edit your question to include (the end of) the output from make, to show what exact command was used here? – JigglyNaga Feb 12 '18 at 14:19
  • That make output shows that this is a typical build process that handles the fine details automatically. But those details are the exact parts you're trying to change. You can't achieve this with an option to make, you'd have to dig right down to the part where it calls the linker. Please can you expand on "I try to tell PHP to look the libs in a given directory"? This sounds more like the right approach for your problem. – JigglyNaga Feb 12 '18 at 16:30
  • I put all needed libs in php/lib. The libs will be always in the lib dir of my PHP, but my PHP is inside a application that I don't know where the application will be. The script that install the application and my PHP will then add the lib dir from my PHP in /etc/ld.so.conf. That works fine but if a lib is present in /usr/lib and in my php lib dir, php will take the one from /usr/lib. And sometimes it doesn't work because the one on /usr/lib has a lower minor version that the one PHP was compile with. – Sébastien Legrand Feb 13 '18 at 7:22
1

Adding this as another answer because the other one can still stand on its own, but your problem (after you clarified) is different. If this is about libraries that are shipped with your application and also by the system, then the situation is not comparable. You're almost at what you need to do to fix it, but not quite :-)

There are several solutions to your problem: LD_LIBRARY_PATH, rpath, shipping changed libraries, and compiling multiple times. Each has their advantages and issues, so let me explain:

  • LD_LIBRARY_PATH

    If you go down this route, then you set an environment variable before you run your program. It probably requires that you use a wrapper script around your binary (i.e., rather than directly running /path/to/my/php, you run a shell script which first sets LD_LIBRARY_PATH and then runs /path/to/my/php).

    The downside of this method is that it's a bit fragile:

    • LD_LIBRARY_PATH is prepended to the library search path, but it does not replace it. That means that if the libraries in question are installed system-wide but for some reason the ones you shipped can't be loaded, the dynamic linker will fall back on the system-provided ones.
    • The requirement to call a shell script means you have an extra fork/exec call, which may make things go wrong. This can be mitigated somewhat by using the exec command in your shell script (so that the script gets replaced by the php binary, and so that your php program is a proper child of the parent), but it's still messy

    On the other hand, it allows you some flexibility with where you store your libraries (i.e., if the system-provided one is good enough in some cases, it's fine if you remove it from your LD_LIBRARY_PATH directory)

  • rpath

    Here, the idea is that you tell the compiler (by way of gcc -Wl,-rpath,'/path/to/library') exactly where to look for the library. This gets hardcoded into the program at compile time, and the dynamic linker will then absolutely ignore versions of the library that are outside your provided rpath, including system-provided versions. This avoids the messiness of the LD_LIBRARY_PATH above, but the downside is that this makes things less flexible; if you need to move things around in the filesystem, you need to recompile everything.

    It also means that if your users want to see things installed in a different way, they're shit outta luck. They may not like that.

Both methods are documented in the ld.so man page.

  • Shipping changed libraries

    Here, the idea is that rather than trying to link to libk5crypto.so.3, you link to libmycorp-k5crypto.so.3. There will be zero chance of the dynamic linker picking up the system-provided libk5crypto.so.3 in that case. The advantage here is that it's fairly easy and elegant once installed; The downside is that people might start wondering whether you changed libk5crypto at all (and ask you for patches), and you'll also have to dive deep into the libk5crypto.so build system to make it actually emit a libmycorp-k5crypto.so library. It might also look bad in the long run, so be careful before you go down this route.

  • Compiling multiple times

    Rather than shipping the libraries that are also provided system-wide, you can just compile your application on every supported distribution, and ship a package for each and every distribution, rather than shipping your libraries. Things like packagecloud.io make that easier to do. Since there is only one library with a given name on the system, there is only one library to pick and no chance of picking the wrong one. The downside is that you have a larger range of things to test, so you have more work at release time (and you better have a good test suite).

    The advantage is that this method ensures you ship less than you otherwise would (so you have less to support), and you can tell users who are on a distribution which has an older version of libk5crypto.so that you don't support anymore, that they should update that first.

  • Thanks a lot. I will try the differents method. A question with rpath, can we set it to $ORIGIN/../lib ? – Sébastien Legrand Feb 14 '18 at 11:20
  • It works. Just before all the "make" i did : export LDFLAGS='-Wl,-rpath,\$${ORIGIN}/../lib' – Sébastien Legrand Feb 14 '18 at 16:03
2

I'm not sure if it's possible, but it shouln't be; it's a very bad idea.

Library SONAMEs (the libfoo.so.X thing) are defined in the library. You may think the full path is in your php binary, but it is not; only the SONAME is. This is why the ldd output shows libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 in the output: the name libk5crypto.so.3, on this system, resolves to the file under that /usr/lib/x86_64-linux-gnu directory.

The libk5crypto.so.3 file is not guaranteed to always be found on that location. The x86_64-linux-gnu part in the path is a dead giveaway that you are running Debian or one of its derivatives; other distributions which only support biarch rather than full multiarch, like Red Hat, use /usr/lib64 instead. It's up to the run-time dynamic linker, which you can debug by way of ldd, to figure out where your libk5crypto.so.3 is found, by using its configuration (typically /etc/ld.so.conf).

The SONAME has very particular semantics. If you're interested in the full technical details, I can heartily recommend Ulrich Drepper's excellent document on the subject; but absent that, you should understand that the .so.3 part of the filename encodes the compatible part of the API. The idea is that when you update libk5crypto for some reason, the system installs the new library as, say, libk5crypto.so.3.2, moves the symlink, and finally removes the old library. This means that, as long as the library remains ABI compatible, any programs compiled against it do not need to be recompiled just because you update the library.

If you encode the library's full name into the binary, however, that advantage goes away entirely, and as a result you'll have to recompile on every upgrade of the library. You almost certainly don't want that.

Having said all that, this question appears to be an XY problem. What is it, exactly, that you're trying to achieve?

  • I didn't want to explain too much the first time because I did not want to bore you, I will edit my question to add more details. – Sébastien Legrand Feb 12 '18 at 15:32

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.