Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cx_Oracle - Oracle client on Mac OS X - RPATH issue #48

Closed
ggordham opened this Issue Jul 17, 2017 · 12 comments

Comments

Projects
None yet
3 participants
@ggordham
Copy link

ggordham commented Jul 17, 2017

  1. What is your version of Python? Is it 32-bit or 64-bit?
    Python 2.7.10 64-bit
    Mac OS X Sierra

  2. What is your version of cx_Oracle?
    6.0rc1

  3. What is your version of the Oracle client (e.g. Instant Client)? How was it
    installed? Where is it installed?
    Oracle Instant client Mac OS X 12.1
    (actually I've installed it multiple times in multiple location)
    I have followed the Oracle method to the letter:
    http://www.oracle.com/technetwork/topics/intel-macsoft-096467.html#ic_osx_inst
    (and I tired a number of other options including putting dynlib files in /usr/local/lib with no luck)

  4. What is your version of the Oracle Database?
    N/A

  5. What is your OS and version?
    Mac OS X Sierra 10.12.5

  6. What compiler version did you use? For example, with GCC, run
    gcc --version.

gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
  1. What environment variables did you set? How exactly did you set them?
    Ok, so I tried a lot of environment variables.
export OCI_LIB_DIR=$ORACLE_HOME'
export LD_LIBRARY_PATH=/usr/local/lib:~/lib:$ORACLE_HOME
export DYLD_LIBRARY_PATH=/usr/local/lib:~/lib:$ORACLE_HOME`

I also tried setting PYTHONPATH and adding the Oracle client directory to sys.path using .pth and the site.py configuration options.

  1. What exact command caused the problem (e.g. what command did you try to
    install with)? Who were you logged in as?
    python -c "import cx_Oracle; print cx_Oracle.version"

  2. What error(s) you are seeing?
    No matter what I tried I would get this error:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "build/bdist.macosx-10.12-intel/egg/cx_Oracle.py", line 7, in <module>
  File "build/bdist.macosx-10.12-intel/egg/cx_Oracle.py", line 6, in __bootstrap__
cx_Oracle.DatabaseError: DPI-1047: Oracle Client library cannot be loaded: dlopen(libclntsh.dylib, 1): image not found. See https://oracle.github.io/odpi/doc/installation.html for help

So there are lots of antidotal references to this being related to SIP (System Integrity Protection), though I could find no specific technical note from Apple that says exactly what is causing the above error (inability to find dynamic linked library at run time).

So I did find a solution that did not require disabling SIP on Mac OS X. It is pretty simple, and seems to support the theory of SPI being an issue, and matches a lot of notes about discontinuing usage of the LD and DYLD paths.

From the source code download, I ran:
python setup.py build

once it is built I then modified the rpath of the cx_Oracle.so library to include the Oracle instant client location:
install_name_tool -add_rpath ~/instantclient_12_1 ./build/lib.macosx-10.12-intel-2.7/cx_Oracle.so

I could very it was added by using the otool command:
otool -l ./build/lib.macosx-10.12-intel-2.7/cx_Oracle.so

Load command 12
          cmd LC_RPATH
      cmdsize 48
         path /Users/ggordham/instantclient_12_1 (offset 12)

Now that it has been modified, I can do the normal install.

sudo python setup.py install

This puts the cx_oracle egg into the normal system path

Post this modification I can now call python and use cx_Oracle on Mac OS X normally.

The biggest issues for this are:

  • having Oracle client directory in a "known" location before building cx_Oracle
  • having to rebuild the cx_Oracle if you change Oracle client location (possibly due to version)

I beat my head on a wall for at least two days trying all the normal workarounds. This was the only model that worked.
Admiralty I didn't try any of this with Pip, I only did this from source code.
I also tied setting FORCE_RPATH=1 but on introspection it never updated the .so file correctly.

Hope this helps some future install issues.
Thanks,
Gary

@anthony-tuininga

This comment has been minimized.

Copy link
Member

anthony-tuininga commented Jul 17, 2017

Ok, so I tried a lot of environment variables.
export OCI_LIB_DIR=$ORACLE_HOME
export LD_LIBRARY_PATH=/usr/local/lib:/lib:$ORACLE_HOME
export DYLD_LIBRARY_PATH=/usr/local/lib:/lib:$ORACLE_HOME

OCI_LIB_DIR is never examined. LD_LIBRARY_PATH and DYLD_LIBRARY_PATH are ignored when SPI is enabled, as you indicated in a later part of your issue, so it is unsurprising that these didn't help you!

I also tried setting PYTHONPATH and adding the Oracle client directory to sys.path using .pth and the site.py configuration options.

PYTHONPATH is only for Python's use finding its own modules, and has nothing to do with finding binary dependencies like the instant client, so also unsurprising that it didn't help you.

cx_Oracle.DatabaseError: DPI-1047: Oracle Client library cannot be loaded: dlopen(libclntsh.dylib, 1): image not found. See https://oracle.github.io/odpi/doc/installation.html for help

Did you look at the web page indicated in the error message? This link goes directly to the macOS section (https://oracle.github.io/odpi/doc/installation.html#macos) and is very simple to implement.

I also tried setting FORCE_RPATH=1 but on introspection it never updated the .so file correctly.

That option has been removed in v6 because RPATH wasn't working on Linux. That is due to the way the Oracle instant client is linked and the fact that v6 now uses dynamic loading to load the Oracle Client libraries. It would seem that this works differently on macOS. I'll have to check that out!

I am also working on an installation guide for cx_Oracle which will cover these and other issues that people have had in the past. I'll update this post with the location when it is complete.

@ggordham

This comment has been minimized.

Copy link
Author

ggordham commented Jul 17, 2017

HI Anthony,

Thanks for the feedback. Just to be clear, the standard library search paths never worked for me on Mac ($HOME/lib and /usr/local/lib). I tired it with both symbolic links to the instant client libraries, and by copying the full libraries into those locations.

Again, I never found specific info on what SIP was blocking. There did not seem to be any log or any information on "what it did not do". Most of the solutions for issues on the Mac like this that I found involved updating the RPATH environment. The above steps seemed to be a logical way to affect the cx_Oracle and still follow a somewhat normal install.

I really don't know why /usr/local/lib or $HOME/lib did not work, but I tired it many times, and even forced those into path settings. One odd thing that did work. If I started python from a working directory of /usr/local/lib or $HOME/lib (or any directory that contained the instant client), then it did work. So it would seem '.' is forced into the dynamic load library path, even though the other locations were not.

Gary

@anthony-tuininga

This comment has been minimized.

Copy link
Member

anthony-tuininga commented Jul 17, 2017

Thanks for the feedback. Just to be clear, the standard library search paths never worked for me on Mac ($HOME/lib and /usr/local/lib). I tired it with both symbolic links to the instant client libraries, and by copying the full libraries into those locations.

I'm no macOS expert by any means so would have no idea why that doesn't work -- especially when it is documented as such! Perhaps check the value of the environment variable DYLD_FALLBACK_LIBRARY_PATH?

Are you able to run with strace (or equivalent) and see what it is actually trying to do? I'd do it myself....but it works for me!

@cjbj

This comment has been minimized.

Copy link
Member

cjbj commented Jul 17, 2017

Can you show us an ls -l of ~/lib or /usr/local/lib?

Don't get tricked by DYLD_LIBARARY_PATH working when you invoke Python from a shell, only for Python to fail if it is opened by a subshell. I believe that's what SIP prevents.

@cjbj

This comment has been minimized.

Copy link
Member

cjbj commented Jul 17, 2017

For the record:

cjones@mac:~$ which python
/usr/local/bin/python
cjones@mac:~$ python
Python 2.7.13 (default, Dec 17 2016, 23:03:43) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cx_Oracle
>>> cx_Oracle.version
'6.0rc1'
>>> 
cjones@mac:~$ ls -l ~/lib
total 8
lrwxr-xr-x  1 cjones  staff  48 20 Mar 15:12 libclntsh.dylib -> /Users/cjones/instantclient/libclntsh.dylib.12.1
cjones@mac:~$ ls -l ~/instantclient
lrwxr-xr-x  1 cjones  staff  32  2 Dec  2016 /Users/cjones/instantclient -> /Users/cjones/instantclient_12_1
cjones@mac:~$ ls -l ~/instantclient_12_1/
total 396920
-rw-rw-rw-@ 1 cjones  staff        485 13 Sep  2016 BASIC_README
-rw-rw-rw-@ 1 cjones  staff        489 13 Sep  2016 SQLPLUS_README
-rwxrwxrwx@ 1 cjones  staff      10220 13 Sep  2016 adrci
-rwxrwxrwx@ 1 cjones  staff      40472 13 Sep  2016 genezi
-r-xr-xr-x@ 1 cjones  staff        342 25 Apr  2015 glogin.sql
lrwxr-xr-x  1 cjones  staff         20  7 Jul 17:06 libclntsh.dylib -> libclntsh.dylib.12.1
-rwxrwxrwx@ 1 cjones  staff   67437336 12 Sep  2016 libclntsh.dylib.12.1
-rwxrwxrwx@ 1 cjones  staff    4532196 12 Sep  2016 libclntshcore.dylib.12.1
-rwxrwxrwx@ 1 cjones  staff    9173288 12 Sep  2016 libnnz12.dylib
-rwxrwxrwx@ 1 cjones  staff    1483956 12 Sep  2016 libocci.dylib.12.1
-rwxrwxrwx@ 1 cjones  staff  109548684 13 Sep  2016 libociei.dylib
-rwxrwxrwx@ 1 cjones  staff     159884 12 Sep  2016 libocijdbc12.dylib
-rwxrwxrwx@ 1 cjones  staff     238764 12 Sep  2016 libons.dylib
-rwxrwxrwx@ 1 cjones  staff      79524 12 Sep  2016 liboramysql12.dylib
-rwxrwxrwx@ 1 cjones  staff    1273000 13 Sep  2016 libsqlplus.dylib
-rwxrwxrwx@ 1 cjones  staff    1565732 12 Sep  2016 libsqlplusic.dylib
drwxr-xr-x  3 cjones  staff        102  8 Jul 11:20 log
-rw-rw-rw-@ 1 cjones  staff    3692096 12 Sep  2016 ojdbc6.jar
-rw-rw-rw-@ 1 cjones  staff    3698857 12 Sep  2016 ojdbc7.jar
drwxrwxrwx@ 8 cjones  staff        272 13 Sep  2016 sdk
-rwxr-xr-x@ 1 cjones  staff       8672 13 Sep  2016 sqlplus
-rwxrwxrwx@ 1 cjones  staff     150348 13 Sep  2016 uidrvci
-rw-rw-rw-@ 1 cjones  staff      71202 12 Sep  2016 xstreams.jar
@ggordham

This comment has been minimized.

Copy link
Author

ggordham commented Jul 17, 2017

Anthony,

That is correct on the library path locations, and that is why I was beating my head so badly.

As to the version, I'm using 2.7.11 that is included with XCode development tools:

which python
/usr/bin/python

Which ends up pointing to:
/System/Library/Frameworks/Python.framework/Versions/2.7/bin
Or whatever is "current" on your system.

As to the files in /usr/local/lib and #HOME/lib, I tried all kinds of combinations. So current contents really don't matter. I've been working with Oracle databases since version 6 (25 Years), so I'm very familiar with the OCI drivers and what is needed. At the end of the day to just load the cx_Oracle library all it should need is libclntsh.dylib, what you need after that depends on a lot of things like your session character set, RAC failover, data types, etc...

ls -l /usr/local/lib
total 518848
drwxr-xr-x  10 wheel        340 Jul 17 08:17 ./
drwxrwxrwx   6 wheel        204 Jul 14 15:44 ../
-rwxr-xr-x   1 wheel   67437336 Jul 17 08:16 libclntsh.dylib*
-rwxr-xr-x   1 wheel   67437336 Jul 17 08:16 libclntsh.dylib.12.1*
-rwxr-xr-x   1 wheel    4532196 Jul 17 08:16 libclntshcore.dylib*
-rwxr-xr-x   1 wheel    4532196 Jul 17 08:16 libclntshcore.dylib.12.1*
-rwxr-xr-x   1 wheel    9173288 Jul 17 08:17 libnnz12.dylib*
-rwxr-xr-x   1 wheel    1483956 Jul 17 08:17 libocci.dylib*
-rwxr-xr-x   1 wheel    1483956 Jul 17 08:17 libocci.dylib.12.1*
-rwxr-xr-x   1 wheel  109548684 Jul 17 08:17 libociei.dylib*

Overall I think the issue is that you have to have RPATH information in the library, or you need to have the Oracle client in a Python system location. Again, I can't find any specific documentation from Apple that says "here is what SIP" allows or denies. And yes the LD variables are all but worthless now.

Gary

@anthony-tuininga

This comment has been minimized.

Copy link
Member

anthony-tuininga commented Jul 17, 2017

So, do you have a value in the environment variable DYLD_FALLBACK_LIBRARY_PATH?

Are you able to try with the Python installations from Python.org?

Can you respond to Chris' comments?

@ggordham

This comment has been minimized.

Copy link
Author

ggordham commented Jul 17, 2017

I do not set DYLD_FALLBACK_LIBRARY_PATH, and it is not set or used as far as I can tell. All the DYLD and LD path variables seem to be disabled by SIP.

It's pretty clear those variables are not getting passed to Python

export DYLD_FALLBACK_LIBRARY_PATH=/usr/local/bin
python -c "import os; print os.environ['DYLD_FALLBACK_LIBRARY_PATH']"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/UserDict.py", line 23, in __getitem__
    raise KeyError(key)
KeyError: 'DYLD_FALLBACK_LIBRARY_PATH'

I did not try Python from python.org, I was trying to use the built in version with Mac OS X.
Unless there is a setting in the compile time of the python.org version that loosens up RPATH / Dynamic linking libraries I don't think it will matter. Also if this does get loosened up with the python.org version then it needs to be documented as such I would hope.

I also edited my last post which should have answers to all of Chris's questions.

@anthony-tuininga

This comment has been minimized.

Copy link
Member

anthony-tuininga commented Jul 17, 2017

Hmm, looks like I have the same issue with /usr/bin/python. It appears to be an executable "signed with restricted entitlements". The executables provided by Homebrew and Python.org do not have these restrictions -- which is probably why most people prefer them over the ones provided by Xcode. :-) I'll look into it further.

@ggordham

This comment has been minimized.

Copy link
Author

ggordham commented Jul 18, 2017

Yea, so just to be clear. I didn't put this in as a ask to change the product. I think it was more of putting information out there since two days of reading forums and running down rabbit holes were of no value.

As I stated above I think putting the Oracle client in a known location is probably the best option. Following and going through about a dozen random install forum postings including the official Oracle install instructions for Mac OS X never left me with the right information.

If the short answer is "put the instant client in $HOME/lib" and use a program that is linked to use a RPATH of $HOME/lib (possibly such as python.org executable). Then that is adequate, but it's not documented anywhere.

There is a lot of old notes and rabbit holes that never explain what is really happening. Also way too many forum postings about "xcode python sucks", which may be true, but does not say why.

So again, just trying to provide some info for others that might be hitting this issue. Instead of just shooting in the dark at 20 random things, getting some facts down.

Gary

@anthony-tuininga

This comment has been minimized.

Copy link
Member

anthony-tuininga commented Jul 18, 2017

Thanks, @ggordham. Even if the product itself doesn't get changed, the documentation should be! We're working on that and trying to get a set of definitive documentation that people can follow -- so this was helpful. Thanks again!

@cjbj

This comment has been minimized.

Copy link
Member

cjbj commented Aug 5, 2017

The cx_Oracle 6 install doc mentions this now. See http://cx-oracle.readthedocs.io/en/latest/installation.html

Thanks for working through this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.