Linker fails to find library - with correct searchpath - makefile

I have encountered a mysterious problem.
While having to compile some libraries for use on an Android Device, I met some linking problems between my code and OpenSSL.
I first compiled OpenSSL to Android, using a stand-alone toolchain, as described here. Then I had to link this with another library, which I configured to use the same toolchain.
./configure --host=aarch64-linux-android CPPFLAGS="-I/tmp/openssl-OpenSSL_1_1_1n/include -DDEBUG" LDFLAGS=-L/tmp/openssl-OpenSSL_1_1_1n
This configures fine, and then I run make.
Now the interesting thing pops up - the linker fails to find my library, as shown in the following error message.
libtool: link: aarch64-linux-android-gcc -DDEBUG -g -O2 -o .libs/credentialmanager credentialmanager-credentialmanager.o -L/tmp/openssl-OpenSSL_1_1_1n ./.libs/libcredentialutils.so ./.libs/libcredentialstack.so -L/usr/local/lib
/tmp/ndk-benlar/aarch64-linux-android/bin/../lib/gcc/aarch64-linux-android/4.9.x/../../../../aarch64-linux-android/bin/ld: warning: libcrypto.so.1.1, needed by ./.libs/libcredentialutils.so, not found (try using -rpath or -rpath-link)
I notice that it had two "-L" flags, however looking at the manpage, it should only add it to the search path, not replace it.
-L <dir> Add directory to library search path
Looking in my temporary directory, I do see the library is located there.
lrwxrwxrwx 1 user user 16 Apr 28 11:58 libcrypto.so -> libcrypto.so.1.1
-rwxrwxr-x 1 user user 2754192 Apr 28 11:58 libcrypto.so.1.1
Why is the linker complaining about not finding the library, when it's obviously looking in the right folder, the files are the right name and the toolchain is the same.

The error message gives you a hint as to the problem. The -L option tells the linker where to find libraries to link, but that's not the issue here. You are not linking libcrypto (there is no -lcrypto on your link line). You are linking credentialutils, and that library is already linked to crypto.
It's that library that can't find its required libraries.
You need to either set the rpath on the credentialutils library so it knows where to look, or copy the crypto library into a place where it will be found, or set the LD_LIBRARY_PATH environment variable to point to its location, or invoke the linker with -rpath pointing to the right location to look.

Related

Modify default library search dirs that gcc passes to ld

I want to force new GCC 12 on my old debian (that only has GCC 6 by default) to use fresh libstdc++ headers with new header-only features, but link with old stdlibc++,gcc_s (and other system/compiler libs used by GCC6) to keep binary compatibility with native runtime of old debian (so that users of old GCC6 can link with my binaries without having GCC12).
Of course I know that some functionality in the old runtime will be missing, and ABI is also different, but I guess I can fight with that. Afterall RedHat seems to be using similar scheme for their devtoolset packages (they try to link missing functionality of new runtime statically to your binary if these symbols are not found in native old runtime)
So far I am stuck with -L arguments that GCC is passing to ld.
Here is complete output of /usr/local/gcc12/bin/x86_64-linux-gnu-gcc-12 main.cpp -Wl,-v -v command for simple hello-world main.cpp:
https://pastebin.com/JhYSfg4x
The question: Where does GCC take all these -L paths from, and how do I remove/modify them? I don't want to accidentally link with new version of libraries that were built with GCC12:
-L/usr/lib/gcc/x86_64-linux-gnu -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12 -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/gcc -L/usr/local/gcc12/lib/gcc/x86_64-linux-gnu/12/../../.. /tmp/ccXfhCs4.o
System ld.conf does not mention any paths to /usr/local/gcc12 folder.
-nostdlib and -nodefaultlibs are removing some standard -l flags, but they are not doing anything to -L flags.
Update: I ended up just removing all *.a, .so, *.la files from include, lib and lib64 folders of gcc12, and I also added -L path to native libraries. This way I am sure gcc12 can't pickup one of its libraries for li nking. Not sure if this is good solution, but it works.

ld: building for macOS-x86_64 but attempting to link with file built for macOS-x86_64

I have this strange issue where creating / using a static library works in my Ubuntu VM but not on macOS:
ld: warning: ignoring file ./dist/libXXXX.a, building for macOS-x86_64 but attempting to link with file built for macOS-x86_64
Command to create the static library is:
ar rcs libtest.a obj1.o obj2.o ...
Compiler invocation:
gcc -g -Wall -Wextra main.c -L./dist -lXXXX -o main
Searching on google didn't yield any usable results except for this (maybe) related question on SO:
Possible related question
I realize this is an old post and you found your fix, but let me post this here for anyone else who runs into this problem for whom these answers don't provide a solution.
You might be using two different toolchains unknowingly, one from Apple (installed via Xcode) and one from GNU (installed via Home-brew or MacPorts). If you type ranlib --version and see version info showing that ranlib is GNU, this is likely the case.
Make sure that /usr/bin comes in your $PATH before /usr/local/bin and /opt/local/bin. When you run which -a ranlib, the first result in the list should be /usr/bin/ranlib. Same for which -a ar-- the first result should be /usr/bin/ar. If it is not so, you need to fix your $PATH.
Once you fix your path and clean your project, try building again and things should work.
The issue was solved when I directly put those object files rather than gathering them into a static library, i.e.,
gcc -g -Wall -Wextra main.c obj1.o obj2.o -o main
After that, I got many warnings like ld: warning: object file (obj1.o) was built for newer macOS version (11.0) than being linked (10.14), but it is a warning, and the object is linked, so the problem is solved.
The root cause is that some library passes -mmacosx-version-min=10.14 to gcc, so the object file is built for 10.14, but my macos is now 11.0.
If you want to make things work, try directly using object files rather than creating a static library.
If you want to resolve all the warnings, find ``-mmacosx-version-min` and comment it.
After looking at my script that automatically creates the static library I've found the culprit:
For some reason my tool created object files for header files (resulting in files like header.h.o).
Removing those fixed the issue.

GCC not using Boost folder include flag

I have a project that includes a library that uses boost 1.57, which is also included. However, the GCC compiler (default Xcode CLI tools v6.0 GCC version 4.2.1) does NOT pick up boosts include directory while it DOES pick up other directories. What is going on here?
This is the final GCC command being issued:
gcc -g -stdlib=libstdc++ -Wall -Wno-error -ferror-limit=1000 -fmessage-length=0
-DHCUBE_NOGUI -DTIXML_USE_STL -DMACOS -mmacosx-version-min=10.5 -arch i386 -arch x86_64
-I/Applications/Webots6.3.0/include/controller/c
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/tinyxmldll/include
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/NE/HyperNEAT/NEAT/include
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/JGTL/include
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/boost_1_57_0/boost/ -DXML1
-c ModHyperNEAT/mod_ctrler7.cpp -o controllers/mod_ctrler7_1.o
The error GCC gives me:
In file included from ModHyperNEAT/mod_ctrler7.cpp:30:
In file included from /Users/mtw800/experimentSuite/experiment/../HyperNEAT/NE/HyperNEAT/NEAT/include/NEAT.h:4:
In file included from /Users/mtw800/experimentSuite/experiment/../HyperNEAT/NE/HyperNEAT/NEAT/include/NEAT_Globals.h:4:
/Users/mtw800/experimentSuite/experiment/../HyperNEAT/NE/HyperNEAT/NEAT/include/NEAT_Defines.h:23:10:
fatal error: 'boost/shared_ptr.hpp' file not found
#include <boost/shared_ptr.hpp>
^
1 error generated.
make: *** [experiment-modular] Error 1
The boost include path:
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/boost_1_57_0/boost/
exists and invoking a find `pwd` -name shared_ptr.hpp gives the following result:
MW-020708:boost_1_57_0 mtw800$ pwd
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0
MW-020708:boost_1_57_0 mtw800$ find `pwd` -name shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/asio/detail/shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/interprocess/smart_ptr/shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/serialization/shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/smart_ptr/shared_ptr.hpp
/Users/mtw800/experimentSuite/HyperNEAT/boost_1_57_0/boost/thread/csbl/memory/shared_ptr.hpp
So I know that the boost include library is there, the path is correct and even the header file for shared_ptr is there. Why is GCC not picking up my include folder path?
I have tested that the other include paths ARE being picked up (as they should) by removing all -I flags and re-adding them when GCC gave errors that it could not find them.
The curious thing is, that if i install boost with home-brew, and further change nothing, that my compile script just 'works', because homebrew probably links boost into directories that are searched by GCC by default. That's great, however, I don't want GCC to use the homebrew boost because it has to compile on a system that does NOT use homebrew. What do I do? Why is GCC pestering me by only excluding one include folder and not all the others? what kind of non-deterministic compiler automagick is going on here?
I am using OSX Yosemite 10.10, mentioned Xcode developer tools above. The other computer uses the same OSX and the same GCC (same Xcode dev tools).
You need to remove the last element (boost) from:
-I/Users/mtw800/experimentSuite/experiment/../HyperNEAT/boost_1_57_0/boost/
Given source files use #include <boost/whatever.h>, the preprocessor expects to find the boost sub-directory when it searches that include directory.

libcrypto equivalent missing on Windows

I have a C file that I need compiled on Windows7. I have installed MinGW for gcc. I also need OpenSSL, so followed the links from their site and downloaded the full developer package from Shining Light Productions (along with the 64-bit Redistro package from MS).
When I try to compile my file using this command:
gcc -D_WIN32 -O2 -shared -Wl,--kill-at -lcrypto -I%JAVA_HOME%\include -I%JAVA_HOME%\include\win32 -IC:\OpenSSL-Win64\include -LC:\OpenSSL-Win64\lib -lm -std=c99 osaccess.c -o libosaccess.dll
I get the error:
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -lcrypto
collect2.exe: error: ld returned 1 exit status
What I find particularly peculiar, is the unix-style forward slashes used in the error. Also, the path is correct, but the case is not. The valid path is C:\MinGW\bin... I also cannot find any crypto library (either libcrypto.* or crypt*lib.*) anywhere, so I guess this is why it cannot find -lcrypto. I would've thought that this would've come with the full install. Has anyone else encountered this before, or know of why it may be happening?
The correct library name for the Shining Light distribution is libeay32 (found at lib/libeay32.lib). This library corresponds to libcrypto.

Standard lib path of g++. And how to add new ones

I want to use gtest but execution tells me
./netTest: error while loading shared libraries: libgtest.so.0:
cannot open shared object file: No such file or directory
What are standard paths in that gcc linker looks for libs
What is standard path of Debian to store libs
How do I add libpaths to g++ (-L flag correct?)
Note on 2: I ask because the libs of gtest are in /usr/local/libs/ but in there is just python and gtest. All other libs are in /usr/lib/. Hence i guess the gtest installer made something wrong.
PS. Perhaps you could just instal the Debian libgtest-dev package (if there's one).
What are standard paths in that gcc linker looks for libs
You can see it with gcc -v -x c /dev/null -o /dev/null 2>&1 | grep LIBRARY_PATH
What is standard path of Debian to store libs
Perhaps you meant where the dynamic loader will look for shared libraries.
Check /etc/ld.so.conf and/or files in /etc/ld.so.conf.d/.
How do I add libpaths to g++ (-L flag correct?)
You can use the --rpath option to ld. However, I would suggest using it only during development and not in deployment.
You can also set LD_LIBRARY_PATH to the location of your libgtest.so.0.
The answer to the preceeding problem. gTest does not use precompiled libs anymore.
Use of precompiled libgtest Not Recommended
-------------------------------------------
The Google C++ Testing Framework uses conditional compilation for some
things. Because of the C++ "One Definition Rule", gtest must be
compiled with exactly the same flags as your C++ code under test.
Because this is hard to manage, upstream no longer recommends using
precompiled libraries [1].
-- Steve M. Robbins , Sat, 21 Apr 2012 17:00:56 -0500
Well doesnt surprise me anymore why I did not find the library in Wheezy :)

Resources