Closed metaskills closed 3 years ago
Could you explain a little more?
Sure, I'd like to build a gem like this pre-compiled with static linking (vs /opt directory links) to package as an internal gem. https://github.com/customink/mysql2-lambda
Oracle doesn't provide static client libraries. So it is impossible.
However it is possible to bundle patched Oracle client libraries in a pre-compiled gem if the platform is Linux.
Prepare Oracle instant client and install patchelf in advance.
$ git clone https://github.com/kubo/ruby-oci8.git
$ cd ruby-oci8
$ git checkout ruby-oci8-2.2.9
$ export LD_LIBRARY_PATH=/path/to/oracle/instant/client
$ make
$ cp /path/to/oracle/instant/client/lib*.so* lib # copy all Oracle shared libraries.
$ patchelf --set-rpath '$ORIGIN' lib/libclntsh.so.*
$ patchelf --set-rpath '$ORIGIN' ext/oci8/oci8lib_???.so
$ vi ruby-oci8.gemspec # vi or any editor
Replace these three lines with the following one line.
files += Dir.glob('lib/*.so*')
$ gem build ruby-oci8.gemspec -- current
This gem includes Oracle client libraries along with oci8lib_???.so
. It works on any directory.
Well, I suspect that Oracle doesn't support patched instant client.
Thanks!!! I had to make one small change:
patchelf --set-rpath '$ORIGIN/../../lib' ext/oci8/oci8lib_???.so
After that everything appeared in order after installing the gem again on a fresh container sans the /opt install.
ldd /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/ext/oci8/oci8lib_250.so
linux-vdso.so.1 => (0x00007fff834a0000)
libclntsh.so.11.1 => /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/ext/oci8/../../lib/libclntsh.so.11.1 (0x00007f1db3154000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f1db2f38000)
libgmp.so.10 => /usr/lib64/libgmp.so.10 (0x00007f1db2cc2000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f1db2abe000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f1db2887000)
libm.so.6 => /lib64/libm.so.6 (0x00007f1db2585000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1db21b7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1db5d82000)
libnnz11.so => /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/ext/oci8/../../lib/libnnz11.so (0x00007f1db1dea000)
libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f1db1bd0000)
libaio.so.1 => /lib64/libaio.so.1 (0x00007f1db19cf000)
libfreebl3.so => /lib64/libfreebl3.so (0x00007f1db17cd000)
ldd /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/lib/libnnz11.so
linux-vdso.so.1 => (0x00007fffdf7f9000)
libc.so.6 => /lib64/libc.so.6 (0x00007f98d1268000)
/lib64/ld-linux-x86-64.so.2 (0x00007f98d1a03000)
ldd /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/lib/libclntsh.so.11.1
linux-vdso.so.1 => (0x00007ffe1dbfe000)
libnnz11.so => /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/lib/libnnz11.so (0x00007f92df0a9000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f92deea5000)
libm.so.6 => /lib64/libm.so.6 (0x00007f92deba3000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f92de987000)
libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f92de76d000)
libc.so.6 => /lib64/libc.so.6 (0x00007f92de39f000)
libaio.so.1 => /lib64/libaio.so.1 (0x00007f92de19e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f92e1e6b000)
However, here is what I got when doing a require in IRB.
require 'ruby-oci8'
Traceback (most recent call last):
11: from /var/lang/bin/irb:11:in `<main>'
10: from (irb):1
9: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:37:in `require'
8: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:160:in `rescue in require'
7: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:160:in `require'
6: from /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/lib/ruby-oci8.rb:1:in `<top (required)>'
5: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:85:in `require'
4: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:85:in `require'
3: from /var/lang/lib/ruby/gems/2.5.0/gems/ruby-oci8-2.2.9.0/lib/oci8.rb:112:in `<top (required)>'
2: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:85:in `require'
1: from /var/lang/lib/ruby/site_ruby/2.5.0/rubygems/core_ext/kernel_require.rb:85:in `require'
Thanks!!! I had to make one small change:
patchelf --set-rpath '$ORIGIN/../../lib' ext/oci8/oci8lib_???.so
How did you package the pre-compiled gem?
gem build ruby-oci8.gemspec -- current
copies ext/oci8/oci8lib_???.so
to lib
. So it finds Oracle libraries in $ORIGIN
, not in $ORIGIN/../../lib
.
However, here is what I got when doing a require in IRB.
Are there no lines after the traceback? It usually prints an error message after that.
I guess that the message is LoadError (cannot load such file -- oci8lib_250.so)
. If so, you need to copy the file to lib
.
gem build ruby-oci8.gemspec -- current copies ext/oci8/oci8lib_???.so to lib
It does not tho. I've tried it a few times.
I guess that the message is LoadError (cannot load such file
Nope, that's the whole error right after the require.
Sorry, darn terminal colors, it was LoadError (cannot load such file -- oci8lib_250)
OK this was really helpful. Much like the MySQL project example I have a copy of the gem spec that wraps the gem with additional version changes. So that is why I did not have the oci8lib_???.so
being copied. I did that in my Dockerfile and simplified the patchelf commands. EVERYTHING WORKS!
Here is my final solution with some things missing as part of my project's build scripts. I'm expecting not to be able to post these to Rubygems since it includes Oracle stuff. But it does work! The container still has to install libaio
and I guess I could package that too but this is good for now. Thanks again for your help!
FROM amazon/aws-sam-cli-build-image-ruby2.7
WORKDIR /build
ARG RUBY_VERSION
ARG RUBY_OCI8_VERSION
ARG RUBY_OCI8_BUILD_VERSION
ENV RUBY_OCI8_VERSION=$RUBY_OCI8_VERSION
ENV RUBY_OCI8_BUILD_VERSION=$RUBY_OCI8_BUILD_VERSION
RUN echo '== Oracle Instant Client Files =='
COPY oracle-instant-client-zip .
RUN yum install -y libaio
RUN mkdir -p /opt/oracle \
&& cd /opt/oracle \
&& unzip /build/instantclient-basiclite-linux.x64-11.2.0.4.0.zip \
&& unzip /build/instantclient-sdk-linux.x64-11.2.0.4.0.zip \
&& unzip /build/instantclient-sqlplus-linux.x64-11.2.0.4.0.zip \
&& cd /opt/oracle/instantclient_11_2 \
&& ln -s libclntsh.so.11.1 libclntsh.so \
&& ln -s libocci.so.11.1 libocci.so \
&& echo '/opt/oracle/instantclient_11_2' > /etc/ld.so.conf.d/oracle-instantclient.conf \
&& /sbin/ldconfig \
&& echo 'export PATH="$PATH:/opt/oracle/instantclient_11_2"' >> /etc/profile.d/oracle.sh
ENV PATH=${PATH}:/opt/oracle/instantclient_11_2
RUN echo '== Install patchelf =='
RUN git clone https://github.com/NixOS/patchelf.git \
&& cd ./patchelf \
&& git checkout 0.11 \
&& ./bootstrap.sh \
&& ./configure --prefix=/opt \
&& make \
&& make install
RUN echo '== Install ruby-oci8 Gem and Patch =='
RUN git clone https://github.com/kubo/ruby-oci8.git \
&& cd ./ruby-oci8 \
&& git checkout "ruby-oci8-${RUBY_OCI8_VERSION}" \
&& export LD_LIBRARY_PATH=/opt/oracle/instantclient_11_2 \
&& make \
&& cd ./lib \
&& cp /opt/oracle/instantclient_11_2/lib*.so* . \
&& rm -rf libclntsh.so \
&& rm -rf libocci.so \
&& ln -s libclntsh.so.11.1 libclntsh.so \
&& ln -s libocci.so.11.1 libocci.so \
&& cd .. \
&& mv ./ext/oci8/oci8lib_???.so ./lib \
&& patchelf --set-rpath '$ORIGIN' lib/libclntsh.so \
&& patchelf --set-rpath '$ORIGIN' lib/oci8lib_???.so
RUN echo '== Build Gem File =='
COPY VERSION /build/ruby-oci8
COPY BUILD /build/ruby-oci8
COPY ruby-oci8.gemspec /build/ruby-oci8
RUN cd ./ruby-oci8 \
&& find -path './.*' -delete \
&& echo "$RUBY_VERSION" > RUBY_VERSION \
&& gem build ruby-oci8.gemspec
$ RUBY_VERSION=27 ./bin/build
IMAGE_NAME="ruby-oci8-lambda-${RUBY_VERSION}"
RUBY_OCI8_VERSION=$(cat VERSION)
RUBY_OCI8_BUILD_VERSION=$(cat BUILD)
docker build \
--no-cache \
--build-arg "DOCKER_FROM=amazon/aws-sam-cli-build-image-ruby${RUBY_VERSION}" \
--build-arg "RUBY_VERSION=${RUBY_VERSION}" \
--build-arg "RUBY_OCI8_VERSION=${RUBY_OCI8_VERSION}" \
--build-arg "RUBY_OCI8_BUILD_VERSION=${RUBY_OCI8_BUILD_VERSION}" \
--tag $IMAGE_NAME \
--file "Dockerfile-${RUBY_VERSION}" \
.
docker run \
--rm \
--volume "${PWD}:/var/task" \
"${IMAGE_NAME}:latest" \
sh -c "cp /build/ruby-oci8/ruby-oci8-${RUBY_OCI8_VERSION}.${RUBY_OCI8_BUILD_VERSION}.${RUBY_VERSION}.gem /var/task"
( edited above )
When installing ruby-oci8 I'd like to generate a static file vs "oci8lib_250.so". Do you have any tips on how to do this?