Omnis Technical Note TNEX0008 April 2020
Loading External Frameworks in macOS Catalina and Newer
For Omnis Studio 10.x
By Andrei Augustin, Omnis Engineering
With macOS Catalina, Apple has introduced app notarization, aimed at delivering a much more secure operating system. As a consequence, the rules on loading external frameworks at runtime are more strict. This means that we will need to make some changes if we want Omnis to be able to load external libraries (dylibs). Examples of external dylibs that you may want to load at runtime include those comprising the Oracle InstantClient, or those comprising the SAP SQLAnywhere ODBC driver.
Traditionally, we would have created a symbolic link to those dylib(s) and placed them in a specific folder where macOS will look for them when Omnis loads them. A notarized app no longer has permission to access libraries that exist outside of the main application.
At the time of writing of this TechNote, the frameworks like Oracle's InstantClient, SAP's SQL Anywhere client and Microsoft's ODBC driver do not seem to meet Apple's requirements to be loaded dynamically at runtime. Because of this, we need to apply a workaround which involves:
- adding their dylibs directly into the Omnis tree
- changing where the dylibs will be loaded from with the help of a command-line tool
- codesign and notarize
Please refer to the Microsoft documentation for guidance on installing the SQL Server ODBC Driver. This step usually involves installing Homebrew, tapping a third party repository via brew tap and installing the msodbcsql17 via: brew install
Once you have the SQL Server ODBC Driver 17, using homebrew on the terminal, please install the dependency unixODBC with the command:
brew install unixodbc
Next we will need to copy the unixodbc into our Omnis tree. UnixODBC is represented by libodbc.dylib which you should be able to find in /usr/local/Cellar/unixodbc/2.3.7/lib/libodbc.2.dylib Versions may change from the time of writing of this tech note, therefore please make sure to check the /usr/local/Cellar/unixodbc/ if your unixodbc version is greater than 2.3.7.
Now copy the libodbc.2.dylib into your Omnis.app bundle Frameworks folder (Omnis.app/Contents/Frameworks/) and rename it libodbc.dylib
Next, let's tell the ODBC DAM xcomp where it should be loading libodbc.dylib from. In order to do this, we will use install_name_tools, so first open up your terminal and navigate to Omnis.app/Contents/MacOS/xcomp/damodbc.u_xcomp/Contents/MacOS/ and execute:
sudo install_name_tool -change "/usr/lib/libiodbc.dylib" "@executable_path/../Frameworks/libodbc.dylib" damodbc
Now, our libodbc.dylib will need two other dylibs to work: libltdl.7.dylib and libodbcinst.2.dylib which we need to add to our Omnis.app bundle Frameworks folder.
libltdl.7.dylib can be found in /usr/local/Cellar/libtool/2.4.6_1/lib/libltdl.7.dylib (make sure you double check the version).
And libodbcinst.2.dylib can be found in /usr/local/Cellar/unixodbc/2.3.7/lib/libodbcinst.2.dylib (make sure you double check the version).
Having copied those two dylibs in our Frameworks folder, now it's time to run some more install_name_tools on them in order to make them aware of each other's new location.
Let's start with libodbcinst.2.dylib, navigate to your Frameworks folder from the terminal and execute:
sudo install_name_tool -change "/usr/local/opt/libtool/lib/libltdl.7.dylib" "@executable_path/../Frameworks/libltdl.7.dylib" libodbcinst.2.dylib
The libodbc.dylib is next, still in the Frameworks folder from the terminal, execute:
sudo install_name_tool -change "/usr/local/opt/libtool/lib/libltdl.7.dylib" "@executable_path/../Frameworks/libltdl.7.dylib" libodbc.dylib
Having sorted out the first dependency, then the next step is to add the SQL Server Driver to our Omnis.app bundle Frameworks folder.
After the SQL Server ODBC Driver 17 installation, we should find its files in /usr/local/Cellar/msodbcsql17/220.127.116.11/lib The version may have changed from the time of writing this tech note, therefore please make sure to check the /usr/local/Cellar/msodbcsql folder. Once you navigate to your SQL Driver installation, you need to copy the libmsodbcsql.17.dylib to your Omnis.app/Contents/Frameworks folder.
Next, open up the terminal and navigate to your Omnis.app Frameworks folder and execute the following on libmsodbcsql.17.dylib:
sudo install_name_tool -change "/usr/local/lib/libodbcinst.2.dylib" "@executable_path/../Frameworks/libodbcinst.2.dylib" libmsodbcsql.17.dylib
And we now have to copy Microsoft's SQL Driver resources in the Contents folder of our Omnis.app. First, navigate to your installation of the MS SQL ODBC Driver, e.g. /usr/local/Cellar/msodbcsql17/18.104.22.168/ and copy the "share" folder into Omnis.app/Contents.
As of Studio 10.x and newer, we can define the key odbcdam.ini with value of path to our odbc.ini file in the config.json, like so:
And our odbc.ini file will contain the connection details as well as the path to our SQL Server ODBC Driver 17 (libmsodbcsql.17.dylib), for example:
Now when trying to connect from within Omnis, make sure you set the $mode to kODBCModeUnix to make sure we load the driver correctly, e.g.
We should be able to successfully connect to our Microsoft SQL Server from Omnis from macOS Catalina!
NOTE: If you were to deploy Omnis.app in a user-specific Application folder e.g. /Users/username/Applications/ then you will have to programmatically change the odbc.ini upon startup to make sure you are pointing to the correct libmsodbcsql.17.dylib in the "Driver" key.
In order to load the Oracle DAM on Studio 10.1 and newer, we will need the following libraries from the Oracle InstantClient:
The first step is to place the dylibs in your MacOS (Omnis Studio 10.1.app/Contents/MacOS/)
The next step is to use the install_name_tool (in the terminal) to change the dependent libraries on the dylib binaries.
We will start with libnnz19.dylib, so open the terminal and go (you can use the cd command to move through directories) to your Omnis MacOS folder (Omnis Studio 10.1.app/Contents/MacOS/) where you will find all the dylibs from InstantClient which you previously moved here.
You can execute the following commands now:
sudo install_name_tool -change "@rpath/libnnz19.dylib" "@executable_path/libnnz19.dylib" libnnz19.dylib
sudo install_name_tool -change "@rpath/libclntshcore.dylib.19.1" "@executable_path/libclntshcore.dylib.19.1" libnnz19.dylib
Next is the libclntshcore.dylib.19.1:
sudo install_name_tool -change "@rpath/libclntshcore.dylib.19.1" "@executable_path/libclntshcore.dylib.19.1" libclntshcore.dylib.19.1
sudo install_name_tool -change "@rpath/libclntsh.dylib.19.1" "@executable_path/libclntsh.dylib.19.1" libclntsh.dylib.19.1
sudo install_name_tool -change "@rpath/libnnz19.dylib" "@executable_path/libnnz19.dylib" libclntsh.dylib.19.1
sudo install_name_tool -change "@rpath/libclntshcore.dylib.19.1" "@executable_path/libclntshcore.dylib.19.1" libclntsh.dylib.19.1
And the last step is the damora8 binary which can be found in Omnis Studio 10.1.app/Contents/MacOS/xcomp/damora8.u_xcomp/Contents/MacOS/damora8. Please cd to the one aforementioned and execute the following:
sudo install_name_tool -change "libclntsh.dylib" "@executable_path/libclntsh.dylib.19.1" damora8
That's it! First thing I would suggest to try next is verify if you can make a connection. You could do a codesign --remove-signature form the terminal on the Omnis Studio 10.app in order to remove any code signature and notarization for testing purposes, make sure you can connect to your database and then codesign, notarize and test connection again.
Please note that as of 10.1, your TNSNAMES.ora is now specified in the config.json file which is situated in the writable directory (AppData on Windows, Application Support on macOS) in the studio folder (e.g. /Users/andreiaugustin/Library/Application Support/Omnis/Omnis Studio 10.1 25120/studio/config.json):
"odbcdam.ini": "ODBCINI=/Library/ODBC/odbc.ini, MYVAR=Custom value",
"oracle8dam.ini": "NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1, TNS_ADMIN=/instantclient_19"
The SQLAnywhere ODBC driver can be obtained from the SAP SQLAnywhere website. (The files can be extracted from a server installation of the product.) Next, we will need the following libraries from ASA17:
First, move the libdbodm17.dylib into the Frameworks folder (Applications/Omnis Studio 10.1.app/Contents/Frameworks).
Next, move all the other libraries in the MacOS folder (Applications/Omnis Studio 10.1.app/Contents/MacOS).
Now, we need to run the following command on libdbodbc17_r.dylib from the terminal (make sure you cd in the directory containing libdbodbc17_r.dylib):
sudo install_name_tool -change "libdbtasks17_r.dylib" "@executable_path/libdbtasks17_r.dylib" libdbodbc17_r.dylib
And the following command on libdbicu17_r.dylib:
sudo install_name_tool -change "libdbtasks17_r.dylib" "@executable_path/libdbtasks17_r.dylib" libdbicu17_r.dylib
And that's it, we can test our connection now. Please make sure you have specified the ODBC.ini in the config.json (e.g. /Users/andreiaugustin/Library/Application Support/Omnis/Omnis Studio 10.1 25120/studio/config.json):
"odbcdam.ini": "ODBCINI=/Library/ODBC/odbc.ini, MYVAR=Custom value"