Mac OS with Matlab: Library not loaded / Image not found

Hi,

I am trying to run the minimal_example_ocp.m in Matlab on Mac OS. I’ve sourced the env.sh and then launched Matlab from the same shell. It compiles the MEX file but then I get the following error:

Error using acados_ocp (line 192)
Exception:
	MATLAB:mex:ErrInvalidMEXFile
	Invalid MEX-file '/usr/local/lib/ocp_create.mexmaci64': dlopen(/usr/local/lib/ocp_create.mexmaci64, 6): Library not loaded: @rpath/libacados.dylib
  Referenced from: /usr/local/lib/ocp_create.mexmaci64
  Reason: image not found


Error in minimal_example_ocp (line 107)
ocp = acados_ocp(ocp_model, ocp_opts);

I haven’t found any related forum entry, and all the people I’ve asked told me they only used ACACOS on Linux and not Mac so far.

Is this supposed to work or am I missing something?

It looks like it just does not see the path, so it might be relatively easy to fix maybe, and I just do not have the experience.

Thanks in advance,
Johannes

EDIT:
otool -L /usr/local/lib/ocp_create.mexmaci64 gives:

/usr/local/lib/ocp_create.mexmaci64:
	@rpath/libacados.dylib (compatibility version 0.0.0, current version 0.0.0)
	libhpipm.dylib (compatibility version 0.0.0, current version 0.0.0)
	libblasfeo.dylib (compatibility version 0.0.0, current version 0.0.0)
	libqpOASES_e.3.1.dylib (compatibility version 3.1.0, current version 0.0.0)
	@rpath/libmx.dylib (compatibility version 0.0.0, current version 0.0.0)
	@rpath/libmex.dylib (compatibility version 0.0.0, current version 0.0.0)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 904.4.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)

EDIT2:
If I copy the required dynamic libraries from ACADOS_INSTALL_DIR/lib (1) to /usr/local/lib (2), it works. Both paths, (1, 2), are on the Matlab path. However, it only sees the one in (2).

Hi Johannes,

Did you see this post?

The Matlab interface has not been tested on MacOS as far as I know.

I guess using DYLD_LIBRARY_PATH instead of LD_LIBRARY_PATH should do the trick.

Can you replace the last paragraph in env.sh with this and let me know if it works?

# if model folder not specified assume this folder
MODEL_FOLDER=${MODEL_FOLDER:-"./build"}
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$ACADOS_INSTALL_DIR/lib:$MODEL_FOLDER
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:$ACADOS_INSTALL_DIR/interfaces/acados_template/tera_renderer/t_renderer/target/release
echo
echo "DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH"

Cheers,
Jonathan

Hi Jonathan,

Thanks for the reply. I had tried that, no difference. I investigated a bit more and found that the problem is related to Mac Security properties. https://ch.mathworks.com/matlabcentral/answers/374930-append-library-path-to-dyld_library_path-in-mac
Contrary to what they say in the link, it seems it is not even possible to use a local variable in the shell before starting Matlab from it. It seems the security features just ignore any attempt to write to LD_ or DYLD_LIBRARY_PATH.

According to this Apple Developer website https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryUsageGuidelines.html the LD_LIBRARY_PATH is indeed a valid Mac variable. However, we cannot change it.
So my workaround for now is to copy the whole content of acados/lib to the folder $HOME/lib (need to create) which is one of the default fallback paths for the dynamic linker (DYLD_FALLBACK_LIBRARY_PATH).

So for ACADOS, it would be nice to have a CMake option to set the $HOME/lib path conveniently as install path in all the subfolder CMakeLists files, instead of the hardcoded lib:

install(TARGETS acados EXPORT acadosTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin)

Or there might be yet another, better solution.

Best,
Johannes

Hi Johannes,

I think the cmake option

-DACADOS_INSTALL_DIR=$HOME/lib

does exactly what you want.
Or am I missing something?

Hi Jonathan,

I tried that. I see two reasons so far why it doesn’t work:

  • The link_libs.json is not written to the ACADOS_INSTALL_DIR/lib but to the source folder/lib.

  • The interfaces folder is not written to the ACADOS_INSTALL DIR.

What I find in the ACADOS_INSTALL_DIR, in this case $HOME/lib, is a ‘cmake’, ‘include’, and ‘lib’ folder (where ‘lib’ doesn’t contain the mentioned JSON file).

Best,
Johannes

Hi Johannes,

In Matlab, you should be able to set the option output_dir such that the interface is compiled there, see e.g.: acados/ocp_compile_interface.m at master · acados/acados · GitHub
As for the link_libs.json file, I agree that it should be written into ACADOS_INSTALL_DIR/lib.
That should be fixed with this commit:
CMake: write link_libs.json into ACADOS_INSTALL_DIR/lib · acados/acados@3f8e312 · GitHub

Can you confirm that those two things make it work?

Best,
Jonathan

Hi Jonathan,

For the first part, sorry, I don’t understand how ocp_compile_interface.m is called and what the output_dir is supposed to be.

For the second part, I confirm link_libs.json is written to the intended path ($HOME/lib/lib). However, it seems like this ‘intended’ path doesn’t work. The libraries (.dylib) need to be directly in $HOME/lib to be seen – which is not how the current CMakeLists is configured. Right now, it installs to $HOME/lib, i.e., the resulting structure is

$HOME/lib/
cmake
include
lib/*.dylib

So there is maybe no simple, fast solution / the workaround of copying the dylibs manually seems more practical.

Best,
Johannes

Hi Johannes,

It is called to compile the Matlab (MEX) interface to the acados OCP solver.
You can set the option doing something like:

ocp_opts.set('output_dir', fullfile(getenv('HOME'), 'lib'))

This path is also used for all the generated model functions.

I think you just have to set
-DACADOS_INSTALL_DIR=$HOME
Probably you did
-DACADOS_INSTALL_DIR=$HOME/lib

If adjusting those two things work. One could set the output_dir in the matlab interface to
fullfile(getenv('HOME'), 'lib') automatically for Mac users in the future.

Best,
Jonathan

Hi Jonathan,

Thanks for your efforts. Things didn’t work… So I reverted everything back and tried again. It turns out the proper way to make it work is to do nothing except -DACADOS_INSTALL_DIR=$HOME.

So please dismiss your commit 3f8e312, it was alright before.

The only small, remaining issue is that when using $HOME as install dir, I will also have ‘cmake’ and ‘include’ directories in my $HOME, which is undesirable. I believe I can delete them and it still works. So maybe it’s possible to avoid installing those folders to there. (I installed now to /usr/local with sudo rights, as /usr/local/bin is another dynamic library fallback path on Mac.)

Thanks,
Johannes


Conclusion: For using the Matlab interface on Mac, add the cmake flag
-DACADOS_INSTALL_DIR=$HOME or
-DACADOS_INSTALL_DIR=/usr/local (needs sudo, if you don’t want to spam your $HOME folder).

Thanks for reporting.
I guess nothing will change in acados with respect to this for now.
It is definitely good to have that documented! :slight_smile:

Hi Johannes,

I have just overcome the same issue of my laptop (running macOS Big Sur).

In order to edit the env var DYLD_LIBRARY_PATH you need to disable the System Integrity Protection (SIP) of macOS. To do so, you have to boot you computer in Recovery Mode, open the Terminal from Utilities and type

csrutil disable

More info about SIP here: Configuring System Integrity Protection

Place where I found the solution: DYLD environment variable woes on OS X Sierra when running Ant: Library not loaded libANML_g.dylib · Issue #181 · nasa/europa · GitHub

From now on, you’ll be able to edit the env var, and hopefully, solve the problem in a clean way.

Best,
Andrea

2 Likes

Hi Andrea,

Thanks for the remark. I also came across this method but decided not to disable the SIP. It might, however, be useful for others who read this!

Best,
Johannes

Hi Johannes,

Thanks for your time finding the solution. I am not very advanced concerning CMake or environment variables. Where do I have to put the " -DACADOS_INSTALL_DIR=$HOME " line exactly? Into the CMakeList.txt in the main acados folder or in the env.sh of my respective example?

Best regards,
Max

Hi Max,

I’m sorry, I didn’t get a notification about your reply. You’ve certainly sorted it out in the meanwhile. It’s a CMake argument, so you use it with the cmake command, see here, line 3.
cmake -DACADOS_INSTALL_DIR=$HOME ..

Best,
Johannes