automake program libtool wrapper linking - macos

Am stumped on an automake link. Even after pouring over the manuals for hours and searching online it is probably a misunderstanding of autotools.
I have one .la library made by libtool, one .dylib shared library and am creating a program. The .la is linked to the .dylib and the program uses the .la.
Makefile.am for the .la library
lib_LTLIBRARIES = libA.la
libA_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined
libA_la_LIBADD = $(LIBM) -Ldir/to/ -lB
libA_la_CPPFLAGS = ${AM_CPPFLAGS}
Makefile.am for program with libtool wrapper
noinst_PROGRAMS = test
test_SOURCES = test_source.c
test_LDADD = libA.la -Ldir/to/ -lB
libA.la is created and links to B.dylib but the test program "wrapper" created by automake is exporting DYLD_LIBRARY_PATH to find libA.la while not linking to B.dylib. Giving the error
dyld: Library not loaded: ./B.dylib
Referenced from: /dir/to/test/.libs/test
Reason: image not found
Trace/BPT trap: 5
Some things that I have tried are adding -Ldir/to/ -lB to test_LDFLAGS in addition to already being added in test_LDADD. And have tried setting test_LDFLAGS = -rpath -Ldir/to in the hopes that setting the runtime search path to the directory where B.dylib is would help.
If I manually export DYLD_LIBRARY_PATH to include /dir/to/B.dylib then the test program is able to run but I'm looking to have autotools take care of this rather than requiring someone to export a path before being able to run it.

libB.dylib includes an rpath that gets copied into your binary and that is used to resolve -lB at runtime.
And it seems that this rpath is not /path/to, so libB.dylib cannot be resolved by the runtime linker.
The reasons why it works for libA.la is that libtools knows that the rpath in libA.dylib is wrong anyhow (as you haven't done a make install) and so it needs to be set manually.
The only way around this that i have found is to use install_name_tool to fix the stored rpath in the resulting binary.
(that is: I don't think that libtool will do this for you, as it contradicts the intended use of libB.dylib - as declared in its rpath)

The problem is that Libtool wasn't involved in building libB.dylib, so it does not know how to fix up your environment to find it. That means it is up to you. You can add path/to/ libB in your environment, or add a hardcoded search path to libA.la so that libA will find it.
libA_la_LIBADD = $(LIBM) -Ldir/to/ -rpath dir/to/ -lB
This will not only add the path to B in libA's binary, but will add it to dependency-libs in Libtool's libA.la file so that on platforms that won't automatically inherit the rpath specification it can be added by Libtool when linking.

Related

Weird behavior of gcc while linking BLAS library

I have ATLAS library "libatlas.so" in an unstandard directory "/opt/apps/gcc4_7/atlas/3.10.2/lib/"
I put the path along with other search paths in environment variable
LD_LIBRARY_PATH=/opt/apps/gcc4_7/atlas/3.10.2/lib:and_others
Then link my code with it as follow:
g++ mycode.o -L$LD_LIBRARY_PATH -latlas
It then say "ld: cannot find -latlas"
But if I add the path again as follow:
g++ mycode.o -L$LD_LIBRARY_PATH -L/opt/apps/gcc4_7/atlas/3.10.2/lib/ -latlas
I have no issues.
I cannot think of any reasons this could happen. Is it because the $LD_LIBRARY_PATH has too many paths in it?

Autotools - libtool: link: -rpath with #executable_path on MacOS

I'm trying to build a framework with Autotools on MacOS. This frameworks contains a library, let's call it libmytools.dylib, and an executable that uses the library.
What I want is to link this library dynamically at runtime.
The executable is usually installed to /Library/Frameworks/mytools.Framework/Versions/Current/Commands/mytools
The library is usually installed to
/Library/Frameworks/mytools.Framework/Versions/Current/Libraries/libmytools.dylib
In case the framework is installed in that location, everything works fine, but when the framework is not installed on the machine but instead it's only embedded in another project, the library can't be found.
What I need is a so called "Runpath Dependent Library" as described here:
https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/RunpathDependentLibraries.html
So what I did was adding mytools_LDFLAGS = -rpath #executable_path/../Libraries to the makefile.
But unfortunately libtool refuses to link my executable with the dynamic -rpath
and shows the following error: libtool: link: only absolute run-paths are allowed.
I also tried mytools_LDFLAGS = -dynamic -rpath #executable_path/../Libraries but the result is the same...
What am I doing wrong??
This is the current libtool design. This thread from the libtool patches list may have a suggestion which will work for you. The suggestion is:
build as normal and then postprocess using install_name_tool
If you don't like this suggestion, it may be possible to adapt the hacky patch that started off that thread to work for you, and apply the patch to the generated libtool as part of bootstrap.sh configuration.

Building a Shared Library but linking against a Static One

I have an Autogen Makefile.am that I'm trying to use to build a test program for a shared library. To build my test binary, I want to continue building the shared library as target but I want the test program to be linked statically. I've spent the last few hours trying to craft my Makefile.am to get it to do this.
I've tried explicitly changing the LDADD line to use the .a version of the library and get a file not found error even though I can see this library is getting built.
I try to add the .libs directory to my link path via LDFLAGS and still it can't find it.
I tried moving my library sources to my test SOURCES list and this won't work because executable object files are built differently than those for static libraries.
I even tried replicating a lib_LIBRARIES entry for the .a version (so there's both a lib_LTLIBRARIES and a lib_LIBRARIES) and replicate all the LDFLAGS, SOURCES, dir and HEADERS for the shared version as part of the static version (replacing la with a of the form _a_SOURCES = _la_SOURCES. Still that doesn't work because now it can't figure out what to build.
My configure.ac file is using the default LT_INIT which should give me both static and dynamic libraries and as I said it is apprently building both even if the libtool can't see the .a file.
Please, anyone know how to do this?
As #Brett Hale mentions in his comment, you should tell Makefile.am that you want the program to be statically linked.
To achieve this you must append -static to your LDFLAGS.
Changing the LDFLAGS for a specific binary is achieved by changing binary_LDFLAGS (where binary is the name of the binary you want to build).
so something like this should do the trick:
binary_LDFLAGS = $(AM_LDFLAGS) -static

ld: After successful linking shared lib not found on execution

I am currently working on a simple data synchonizer in a mixture of Fortran and C/C++ by using OpenMPI libraries. The synchonizer compiles and links correctly, as far as I can see:
f95 -o fortran_mpi_test *.o -L/usr/lib/gcc/x86_64-redhat-linux/4.1.1/
-L/usr/lib64/openmpi/1.4-gcc/lib/ -lmpi -lmpi_cxx -lstdc++
But when I execute the resulting executable on the same machined I get an error stating that one of the shared libraries is not found. That is confirmed by ldd.
Nevertheless the missing library libmpi_cxx.so.0 is located in one of the specified folders.
Could anyone give me a hint what I could have done wrong?
Check your environment variables. If your LIBRARY_PATH, LD_LIBRARY_PATH or similar vars have gotten out of sync or set to silly values you might not be searching the same directories for static libraries as you do for dynamics.
Also check out the ld.so manpage

configure.in: AM_DISABLE_SHARED doesn't change my Makefile

I'm extremely new to using Makefiles and autoconf. I'm using the Camellia image library and trying to statically link my code against their libraries. When I run "make" on the Camellia image library, I get libCamellia.a, .so, .la, and .so.0.0.0 files inside my /usr/local/lib directory. This is the command I use to compile my code with their libraries:
gcc -L/usr/local/lib -lCamellia -o myprogram myprogram.c
This works fine, but when I try to statically link, this is what I get:
gcc -static -L/usr/local/lib -lCamellia -o myprogram myprogram.c
/tmp/cck0pw70.o: In function `main':
myprogram.c:(.text+0x23): undefined reference to `camLoadPGM'
myprogram.c:(.text+0x55): undefined reference to `camAllocateImage'
myprogram.c:(.text+0x97): undefined reference to `camZoom2x'
myprogram.c:(.text+0x104): undefined reference to `camSavePGM'
collect2: ld returned 1 exit status
I want to statically link because I'm trying to modify the Camellia source code and I want to compare my version against theirs. So after some googling, I tried adding AM_DISABLE_SHARED into the configure.in file. But after running ./configure, I still get the exact same Makefile. After I "make install", I still get the same results above.
What is an easy way to get two versions of my code, one with the original Camellia source code compiled and one with my modified version? I think static libraries should work. There is an easy way to get static libraries working or are there other simple solutions to my problem? I just don't want to re-"make" and re-"make install" everytime I want to compare my version against the original.
Did you re-run autoconf after adding AM_DISABLE_SHARED and before configure, make, make install? You also can just use configure --disable-dynamic to stop it building the shared libraries. Make sure you delete any previously installed ones - make uninstall should do that. I can't see anything else obviously wrong. Try being explicit:
gcc -static -o myprogram myprogram.c /usr/local/lib/libCamellia.a
or break it down into two steps and check the symbols in myprogram.o are what you expect with nm myprogram.o.
I am not skillful with autoconf and I don't know why your attempt to link statically fails, but if linking dynamically works I think using shared libraries would actually solve your problem a little better.
Just make two shared libraries, one with the original Camellia code and one with your modified version. Put them in two different directories, and when you run myprogram you can choose between them either by switching LD_LIBRARY_PATH (or whatever you're using to find libraries) or by keeping a symbolic link in /usr/local/lib and switching it between libraries. The advantage of this over static libraries (apart from the fact that this works) is that you can tinker with your modified code, rebuild the shared library and run without having to rebuild myprogram (as long as you don't modify the signatures).
P.S. An experiment: try removing the shared libraries from /usr/local/lib and rebuilding without the -static flag, just as if you were using the shared libraries. In theory this should cause gcc to use the static libraries instead. The results may give a clue to why the static link is failing.

Resources