How to set libs order in qmake? - linux

We have a problem building out C++ software on Ubuntu Linux with qmake.
Problem is: we use some library, for example OpenCV, that can have different versions in one system.
qmake automatically add -L/usr/lib or -L/usr/lib/x86_64-linux-gnu to g++ arguments, and contents of LIBS variables after it.
So there conflicts with different versions of OpenCV, the system version is used, but we need custom one, located at our build tree.
Are there any methods to change libs order in -L or something else to solve this problem?

There are two components to doing this:
First, you need to make sure to include them in your .pro file correctly. Do this with something like (this is from my current project):
LIBS += L${OPENCV_HOME}/lib \
-lopencv_core \
-lopencv_highgui \
You can replace the environment variable with whatever your path is. I've found it convenient to use environment variables like this because you also need header includes:
INCLUDEPATH += $$(OPENCV_HOME)/include/opencv2 \
$$(OPENCV_HOME)/include/opencv \
$$(OPENCV_HOME)/include
This allows you to create projects and build them correctly.
When you attempt to run them, however, you will likely run into all sorts of issues due to your app finding the wrong libraries (from system libraries like you say) - you need to set your LD_LIBRARY_PATH variable correctly. In this case I have a launch script (you can do this in your user profile or elsewhere) which contains:
export LD_LIBRARY_PATH=${OPENCV_HOME}/lib
Which then looks to that (as well as other) locations on the LD_LIBRARY_PATH first, before system libraries.

Another hack is to exploit the LIBS = $(SUBLIBS) ... part of the Makefile qmake writes.
Namely, invoke the generated Makefile with
make SUBLIBS=-L/path/to/your/opencv

I had the same issue which I fixed by setting QMAKE_LIBDIR to the lib directory of the build tree. QMake automatically added the system library path after this value, thus allowing to correctly detect the desired libraries:
QMAKE_LIBDIR = /path/to/desired/opencvlib

I have two OpenCV versions on my PC, one installed by default in /usr and another installed by compiling the sources in a custom dir (not /usr).
The first worked just fine with Qt, the other didn't. I struggled a lot trying to make the Qt Creator work with my OpenCV compiled sources. So I added -L/opencv_lib_path but it always said 'undefined reference' for some OpenCV API I was using. It simply doesn't want to look there for the libs, it will look in LD_LIBRARY_PATH instead. I tried adding my opencv_lib_path to the LD_LIBRARY_PATH, no joy either.
The only thing that worked was Frodon's solution, just add this in your Qt .pro file and it will work.
QMAKE_LIBDIR = /path_to_installed_opencv/lib

Related

Add linker flag during conan install

I'm working in a project that uses a number of external libraries. These libraries are included using Conan. The project is primarily written for Unix, but it also need to compile and run on Windows.
My current problem is that Windows defaults fopen() to be O_TEXT, while Unix expects this to be O_BINARY. I have a fix that works for my own code, simply include binmode.obj when linking to change this default to O_BINARY.
The problem is that this does not affect my third party libraries. Googling for this didn't turn up much, most suggestions seems to be based on where you are creating your own package and want flags added, rather than how to add flags when using other's packages.
What I have tried so far:
Make binmode.obj come before libraries, in case the linking order matters. Made no difference.
Added --env 'CL=link binmode.obj' to conan install, but this flag did not end up as part of the compile flags nor link flags.
Any suggestions for what I could try?
EDIT: I was wrong about "CL" taking no effect. This was caused by confusing output. But I did observe that CL seems to be applied for both compiler and linker, which makes it somewhat challenging what flags to give. Using "/link" prefix makes it work with compiler, but does not work with linker.
EDIT 2: More confusions... I didn't realize that the syntax of the CL value was: "<compile flags> /link <link flags>". It affected compile, but not link, however. So this environment variable apparently can't be used to make Conan add a linker flag for autotools based packages.
Hi Mats L welcome to our community!
I once had a similar problem and what I end up doing was quite hacky but quite simple also:
On my conan profile located at ~/.conan/profiles/default or any other profile actually I added an enviromental variable as such:
CXX=/usr/bin/clang++ -fms-compatibility. This one made me compile all the c++ sources with this flag (that can understand windows specific code).
So in your case you can run which c++ to find the location of your compiler
and edit the CXX environmental variable in the conan profile you use your final file will probably look like :
[settings]
os=Macos
os_build=Macos
arch=x86_64
arch_build=x86_64
compiler=clang
compiler.version=11
compiler.libcxx=libc++
build_type=Release
[options]
[build_requires]
[env]
CXX=c++ --required_flag
Some additional notes: You might also want this flag set on your CC enviromental variable .
It's preferable to not change the default profile but copy it (lets say on a file named default_edited_copy) and then invoke the other profile with conan ... --profile default_edited_copy

Bash command: export BLAS_LIBS="-L$LAPACKHOME/lib -lblas"

Can any body explain to me what does the whole sentence mean?
I know this is to set Macro BLAS_LIBS as another string.
But I'm not sure what's the "-lblas" mean and I don't know how to use it.
Similar as the following code. "-llapack"
export LAPACK_LIBS="-L$LAPACKHOME/lib -llapack"
How can the program find out the BLAS and LAPACK libraries just by "-lblas" and "-llapack" ?
Thanks for advance.
I'm not sure why you say "just by -llapack" because that's not what is happening here. Specifically, the -L option just before it specifies a directory path to add to the library resolution path. This works roughly like PATH in the shell.
For example, with the command line fragment gcc -Lfoodir -Lbardir -lfoo -lbar, you basically instruct the linker to search the directories foodir and bardir for the library files libfoo.a and libbar.a.
The -l option is described in GCC: Options for Linking and -L and friends in the following section GCC: Options for Directory Search.
This build arrangement -- configure the build to show where the required files are before compiling -- is common for libraries, where if a user has already downloaded and compiled a required library for some other project, they don't need to rebuild it; they can just point the compiler to wherever they already have the stuff needed for this project.
Building your own libraries is becoming increasingly unnecessary anyway, as prepackaged binaries of most common libraries are available for most systems these days. But of course, if you are on an unusual platform, or have specialized needs which dictate recompilation with different options than any available prebuilt binary, you will still need to understand how to do this.

My library does not load on other systems but works fine on the system it was compiled on

My project includes a library and example projects for how to use it. I place the library in the "bin" folder along with all executable examples. I can run the example projects on the machine where they were compiled but when I try to run them on another machine I get:
./example: error while loading shared libraries: libMyLib.so: cannot
open shared object file: No such file or directory
This makes no sense since the library is in the same folder. What is causes it to ignore the library on other machines?
Just because the library is in the same directory as the executable doesn't mean it will look there for it. By default on linux, executables will only look in a limited set of directories, set by ldconfig and the LD_LIBRARY_PATH environment variable.
One trick that is very useful is to link your program with the extra linker option
-Wl,-rpath,'$ORIGIN'
which will cause the executable to also look in the directory the executable is in for shared objects.
You can usually set this by adding to your Makefile:
LDFLAGS := -Wl,-rpath,'$$ORIGIN'
Note the double-$ here -- make will interpret this as a make variable which expands to just $
The current directory is not necessarily a place where the dynamic linker will look for dynamic libraries. The directory where the executable is much less.
You might want to check ldconfig to see where it looks for them.

linking clapack on linux

I am moving a project which uses clapack from osx to linux and experiencing some problems with it. I use clapack by downloading the cmake project, compiling and moving the necessary .h and .a files to a relevant location within my project.
I have used the same steps in both scenarios (osx and linux) and have the same exact source code on both machines however I cannot get the everything to link properly on linux.
the lined of code in my cmake file look like this
#-----------------------------------------------------------------------------
# INCLUDE CLAPACK
#-----------------------------------------------------------------------------
INCLUDE_DIRECTORIES(${VMT_PRJ_SOURCE_DIR}/CLAPACK)
LINK_DIRECTORIES(${VMT_PRJ_SOURCE_DIR}/CLAPACK/lib)
LINK_LIBRARIES(blas f2c lapack tmglib)
and the error I am getting looks like this
/CLAPACK/lib/liblapack.a(sgesvd.c.o): In function `sgesvd_':
sgesvd.c:(.text+0x456): undefined reference to `s_cat'
sgesvd.c:(.text+0x1fa4): undefined reference to `s_cat'
This is the first time I have done a port from osx to linux and don't know if there are some different requirements I need to make in order to link or what the problem is
Any help would be much appreciated.
Scott
The order of linking matters. Since liblapack.a needs functions from libf2c.a, the latter needs to come after the former. So changing
LINK_LIBRARIES(blas f2c lapack tmglib)
to
LINK_LIBRARIES(blas lapack f2c tmglib)
should help.

Globally use Google's malloc?

I'd like to experiment with Google's tcmalloc on Linux... I have a huge project here, with hundreds of qmake generated Makefile's... I'd like to find a way to get gcc to globally link against tcmalloc (like it does with libc)... Is this possible? Or will I have to edit every Makefile?
(I'd prefer not to edit all the pro files as there are hundreds of them)
(Also, we've already tried the LD_PRELOAD method and it's not working quite right)...
How do your makefiles access the compiler (gcc/g++/cc/c++)?
If it's just by name (g++), and not by explicit path (/usr/bin/g++), you can simply create a replacement g++ in whatever directory you prefer, and prepend that directory to your path.
E.g.: Create a ~/mytmpgccdir/g++ file:
#!/bin/tcsh -f
exec /usr/bin/g++ -Lfoo -lfoo $*:q
Adding whatever extras (-Lfoo -lfoo) you like, either before or after the other arguments ($*:q).
Then pre-pend it to your path and make normally.
#tcsh version
% set path = ( ~/mytmpgccdir/ $path:q )
% make clean
% make
p.s. If it is by explicit name, you may be able to override it on the command line. Something like: make all GCC=~/mytmpgccdir/gcc
p.p.s If you do use LD_PRELOAD, you might want a script like this to setenv LD_PRELOAD before running your program. Otherwise it's easy to wind up LD_PRELOAD'ing on every command like /bin/ls, make, g++, etc.
First, check the qmake documentation. There is an easy way to specify (in a .pro file) that a certain library should always be linked in.
Also, since you are just experimenting, simply use LD_PRELOAD - no recompilation necessary:
LD_PRELOAD="/usr/lib/foo/libtcmalloc.so" ./your_program
You do not have to have linked "your_program" against google's tcmalloc library.

Resources