Open erdmann opened 5 years ago
As a follow-up, the value of @rpath can be embedded inside the dynamic library, either during compilation or post facto with the install_name_tool
command [1,2], so as an alternate to the above steps to hard-code the two library locations, the following also makes pyvips pass all tests:
~/src/pyvips$ install_name_tool -add_rpath /usr/local/opt/glib/lib/ build/lib.macosx-10.7-x86_64-3.7/_libvips.abi3.so
One can see the value of @rpath
stored in the file (if any) by using otool -l
and looking for LC_RPATH
:
~/src/pyvips$ otool -l build/lib.macosx-10.7-x86_64-3.7/_libvips.abi3.so
build/lib.macosx-10.7-x86_64-3.7/_libvips.abi3.so:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777223 3 0x00 8 16 1808 0x00000085
...
Load command 15
cmd LC_RPATH
cmdsize 40
path /usr/local/opt/glib/lib/ (offset 12)
On the compile side, I found that the value of rpath can be set as an extra linker flag in the ffibuilder, by adding this extra line in pyvips_build.py
ffibuilder.set_source("_libvips",
r"""
#include <vips/vips.h>
""",
**pkgconfig.parse('vips'),
extra_link_args=['-Wl,-rpath,/usr/local/opt/glib/lib']) # manually added this
The above obviates the need to use install_name_tool
at all. Determining under which circumstances the above line would need to be added is beyond the scope of my severely limited OSX expertise.
[1] https://medium.com/@donblas/fun-with-rpath-otool-and-install-name-tool-e3e41ae86172 [2] https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath
Hi Rob,
I'm glad it's working for you, but I'm afraid this is not a good solution :( Anaconda has its own package system and its own set of libraries and mixing them like this is not supported. For example, what if another conda package pulls in the conda glib-2.0 and the version doesn't match the one in homebrew? Now if you import both packages, you'll get run-time link errors. It can get much worse than that: you can get silent data corruption, mysterious random threading crashes, ... argh!
The only way to really fix it is to make a proper conda package. It's a shame conda lives it it's own weird tiny incompatible world, but of course that's the strength of a cross-platform packaging system too. The other fix is to use homebrew Python.
Hi John,
I think I understand the general principle, but what I think I don't understand is how this interacts with the OSX ability to have a .dylib that hard-links to specific other dependencies.
This sounds plausible that libvips and pyvips can live in their own homebrew world, linking to libraries from homebrew, while other conda packages can have their libraries loaded from the conda world. This is what I was seeing before I fixed the problem, as observed with DYLD_PRINT_LIBRARIES=1 python setup.py test
: specifically that libvips was loading libgobject-2.0.0.dylib from one place (/usr/local/opt/glib/lib) and that other conda things were loading it from another place (somewhere like /opt/anaconda3/lib/...). In other words, both libraries were simultaneously loaded and in action, but the problem was just that _libvips.abi3.so wasn't hard-wired to use the same one as /usr/local/opt/vips/lib/libvips.42.dylib, and was instead picking up the one from conda.
So, I reasoned that I could hard-wire _libvips.abi3.so
to live entirely in the homebrew world with its libraries, and that this would not have any effect on anything in the conda world since I wasn't changing any equivalent of LD_LIBRARY_PATH, and the conda things already know to use libraries under /opt/anaconda3.
Is there a possibility that there is some kind of cross-contamination, given that, after the manual override, _libvips.abi3.so and libvips.42.dylib dynamically link entirely into the homebrew world and conda things dynamically link entirely into the conda world?
Thanks, and apologies for the newbie question.
Yes, macos has a two-level linking system, so you can in theory have g_type_ new()
call two different things from two points in the same executable. But that's only the linker -- what about all the other things that make up a program, like environment variables, threads, per-thread storage, quarks, file handles, pointers, etc. etc., and how they behave when references to them pass from one part of the program to another. It'll perhaps work some of the time if you are lucky, I think is the best you can say.
The macos two level linking system was designed for their "framework" system, where libraries can be added and moved about as separate packages, and it works well for libraries which are designed with that in mind. But most standard *nix software like glib, was never designed to work like that, and it's at best an unsupported hack, unfortunately.
Perhaps I'm being too negative! Anyway, I think a proper conda package would be a better solution.
Hi John,
I've recently had to install libvips and pyvips on a new MacBook Pro for work, and I encountered an identical issue to #24 and #38 by trying to mix homebrew vips and anaconda python, resulting in all tests failing with loads of error messages from libglib-2.0 and libgobject-2.0. It was quite important for me to have pyvips running under a conda-based configuration, so I poked around and I think I've found an easy workaround.
I had previously installed vips via homebrew. When subsequently building pyvips, it was failing to build an API version despite
pkg-config vips --libs
printing the correct information. The API-compilation problem was revealed by running the below command;pkg-config
didn't findlibffi
:That problem was fixed with
$ brew install libffi
followed by
Once these changes were made, running
python setup.py build
in the root directory of the pyvips package actually compiledbuild/lib.macosx-10.7-x86_64-3.7/_libvips.abi3.so
, but I was getting the same errors as #24 and #38 (GLib-CRITICAL **: g_datalist_id_set_data_full: assertion 'key_id > 0' failed
, e.g.). I suspected a clash between libvips' linked libraries and the ones in_libvips.abi3.so
, specifically conflicting versions oflibglib-2.0
andlibgobject-2.0
:Compare to:
I manually set the libraries in
_libvips.abi3.so
to point to the same ones as libvips by running the following:After that, all tests passed, and running
pip install .
installed under anaconda and now everything works fine as far as I can tell (python setup.py pytest
ortox -e py37-test
pass all 28 tests and my own pyvips code seems to work fine so far).I should caution that I've never used a Mac before, so when it comes to OSX I truly have no idea what I'm doing so there's probably a better, more correct way to do this (setting RPATH?). However, this worked for me after a day of frustration, so maybe this will help someone else avoid the same pain.