mabl / PyPylon

An experimental python wrapper around the Basler Pylon 5 library
BSD 3-Clause "New" or "Revised" License
53 stars 34 forks source link

Can't find camera on OSX #18

Open ryanbahneman opened 8 years ago

ryanbahneman commented 8 years ago

I'm able call into the Pylon library, but I'm not able to find any cameras. Running the C++ Pylon examples (or the Pylon configurator) I'm able to find my camera, so I know it's connected correctly.

During debugging, I created a .cpp file with just the initialization and enumeration code. Building and running the file in Xcode I'm able to see my camera, but linking it into cython and calling it with python3 doesn't work.

Perhaps there is some python/cython configuration on OSX that is preventing discovery from working?

ryanbahneman commented 8 years ago

I tried on python2 today. Still no luck.

ryanbahneman commented 8 years ago

Found this beautiful tool in the Pylon framework

Resources/Tools/pylon-start-with-logging

Running /Library/Frameworks/pylon.framework/Versions/A/Resources/Tools/pylon-start-with-logging ipython3 and then importing pypylon gives the following output:

[2016-10-11 12:43:30,363:pylon.base] NOTICE: Initializing Pylon version 5.0.5.8973 (64 bit) on Mac OS X 10.11.6, Darwin 15.6.0, x86_64.
[2016-10-11 12:43:34,712:pylon.base.TlFactory] NOTICE: Trying to load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_camemu-5.0.5.so'
[2016-10-11 12:43:34,713:pylon.base.TlFactory] NOTICE: Trying to load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gige-5.0.5.so'
[2016-10-11 12:43:34,713:pylon.base.TlFactory] ERROR: Could not load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gige-5.0.5.so' : dlopen(/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gige-5.0.5.so, 10): Library not loaded: @rpath/pylon.framework/Versions/A/Libraries/libgxapi-5.0.5.dylib
  Referenced from: /Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gige-5.0.5.so
  Reason: image not found
[2016-10-11 12:43:34,713:pylon.base.TlFactory] NOTICE: Trying to load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gtc-5.0.5.so'
[2016-10-11 12:43:34,715:pylon.base.TlFactory] NOTICE: Trying to load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_usb-5.0.5.so'
[2016-10-11 12:43:34,716:pylon.base.TlFactory] ERROR: Could not load TL lib '/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_usb-5.0.5.so' : dlopen(/Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_usb-5.0.5.so, 10): Library not loaded: @rpath/pylon.framework/Versions/A/Libraries/libuxapi-5.0.5.dylib
  Referenced from: /Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_usb-5.0.5.so
  Reason: image not found
[2016-10-11 12:43:34,716:pylon.base.TlFactory] ERROR: No device is available or no device contains the provided device info properties.

From the log we can tell that the optional transport layer modules aren't being loaded. If @rpath was defined to be /Library/Frameworks then the library would be found and this would work, so it seems that @rpath is not defined correctly.

This failure is almost certainly being captured and hidden by pylon because these modules are optionally installed and might not exist (you might only need GigE and not USB). However in this case, the load error is occurring because there is an issue and not because the library isn't there.

Running tool -l on /Library/Frameworks/pylon.framework/Versions/A/Libraries/libpylon_TL_gige-5.0.5.so shows that LC_RPATH is not defined.

I was able to work around the issue by setting the runtime library search path manually with

install_name_tool -add_rpath /Library/Frameworks /Library/Frameworks/pylon.framework/Libraries/libpylon_TL_gige.so
install_name_tool -add_rpath /Library/Frameworks /Library/Frameworks/pylon.framework/Libraries/libpylon_TL_usb-5.0.5.so

This feels wrong because I'm hardcoding a path into a framework that should work anywhere, and it doesn't explain why it works in C++ and not python.

ryanbahneman commented 8 years ago

I also found that you can also hack in a workaround by calling

export LD_LIBRARY_PATH=/Library/Frameworks/pylon.framework/Libraries

before you launch python.

felixhol commented 8 years ago

Thanks a lot @ryanbahneman !! Calling export LD.... before launching python indeed did the trick. I'm incredibly happy with this workaround as I'm traveling to Madagascar in a couple of days and would like to use the Basler camera there for some experiments. Awesome to have it up and running just before the trip....

mabl commented 8 years ago

@ryanbahneman very nice debugging! I could not have done this remotely. Now, the question is, if one can tell cython to look at these path for libraries, maybe in the linker stage.

But on the other hand, this part of the OSX code should do this already, right?

compiler_config['extra_link_args'] = ['-rpath', os.path.join(*os.path.split(pylon_dir)[:-1]),

(https://github.com/mabl/PyPylon/blob/master/setup.py#L52)

RonstaMonsta commented 7 years ago

Adding on to this old thread, since I also just hit this issue:

But on the other hand, this part of the OSX code should do this already, right?

Unfortunately, no. The issue is not that the cython module that we are building doesnt have the right library path information - it's that the Basler Pylon libraries don't have the properly configured runtime search paths.

As @ryanbahneman showed above using otool-l output, /Library/Frameworks/pylon.framework/Libraries/libpylon_TL_gige.so and /Library/Frameworks/pylon.framework/Libraries/libpylon_TL_usb-5.0.5.so will go searching for other libraries at the following paths:

Load command 9 cmd LC_LOAD_DYLIB cmdsize 96 name @'rpath/pylon.framework/Versions/A/Libraries/libpylonbase-5.0.5.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 5.0.5 compatibility version 5.0.0 Load command 10 cmd LC_LOAD_DYLIB cmdsize 112 name @'rpath/pylon.framework/Versions/A/Libraries/libGenApi_gcc_v3_0_Basler_pylon_v5_0.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 0.0.0 compatibility version 0.0.0 Load command 11 cmd LC_LOAD_DYLIB cmdsize 112 name @'rpath/pylon.framework/Versions/A/Libraries/libGCBase_gcc_v3_0_Basler_pylon_v5_0.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 0.0.0 compatibility version 0.0.0 Load command 12 cmd LC_LOAD_DYLIB cmdsize 112 name @'rpath/pylon.framework/Versions/A/Libraries/libLog_gcc_v3_0_Basler_pylon_v5_0.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 0.0.0 compatibility version 0.0.0 Load command 13 cmd LC_LOAD_DYLIB cmdsize 56 name /usr/lib/libSystem.B.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 1226.10.1 compatibility version 1.0.0 Load command 14 cmd LC_LOAD_DYLIB cmdsize 96 name @'rpath/pylon.framework/Versions/A/Libraries/libgxapi-5.0.5.dylib (offset 24) time stamp 2 Wed Dec 31 16:00:02 1969 current version 5.0.5 compatibility version 5.0.0

The problem is that @'rpath isn't defined in the libraries for the dynamic linker/loader to find - which is why the workarounds focus on providing similar information to the dynamic linker/loader about where to find the other libraries.

The proper fix to this would be for Basler to update the Pylon libraries to include those paths. Alternately, we could make part of our setup.py process finding the libraries and adding the proper @'rpaths to them. (Which seems sketchier).