CMake cannot resolve runtime directory path - cmake

After running cmake CMakeLists.txt
I get the following warning
CMake Warning at src/CMakeLists.txt:32 (add_executable):
Cannot generate a safe runtime search path for target MMPEditor because
files in some directories may conflict with libraries in implicit
directories:
runtime library [libQt5Widgets.so.5] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
/home/ch/Qt/5.2.1/gcc_64/lib
runtime library [libQt5Core.so.5] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
/home/ch/Qt/5.2.1/gcc_64/lib
runtime library [libQt5Gui.so.5] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
/home/ch/Qt/5.2.1/gcc_64/lib
runtime library [libQt5OpenGL.so.5] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
/home/ch/Qt/5.2.1/gcc_64/lib
Some of these libraries may not be found correctly.
What does it mean for one file to be hidden by another and how can I allow CMake to determine which is the right folder to link to?

What the warning actually implies:
The project requests linking with the shared library, which is contained in two directories. That is, both these directories have the file named like foo.so.x.y.
CMake perfectly understands which library file is chosen for linking. That is, it may pass the "right" directory to the runtime loader, so the loader will search the library there.
For some reason, CMake cannot prevent the loader to search under the "wrong" directory too. E.g. that directory is searched by default, or it contains other libraries needed for the same executable.
As a result, CMake cannot guarantee that, when you run the executable, the loader will find the proper library.
For examples, the message
runtime library [libQt5Widgets.so.5] in /usr/lib/x86_64-linux-gnu may be hidden by files in:
/home/ch/Qt/5.2.1/gcc_64/lib
means, that the project requests to link with the library libQt5Widgets.so.5 located in the directory /usr/lib/x86_64-linux-gnu.
But library with the same name exists also in the directory /home/ch/Qt/5.2.1/gcc_64/lib, which CMake treats as "implicit directory", where the loader will search in any case. (Probably, because this directory is listed in the variable LD_LIBRARY_PATH).
The consequences of the warning:
The project can be configured without the errors.
The project can be built without errors.
But when run the executable, the loaded may load wrong library. And that could lead to unpredictable results.
Because unpredictable results on running are rarely acceptable, it is better to fix the warning. Possible ways include the following:
Make sure that CMake chooses the library which you are actually intended to use.
E.g. you could actually intend to use the custom installation of QT under /home/ch/Qt/5.2.1/gcc_64. In that case you need to hint CMake about your intentions. E.g. by setting CMAKE_PREFIX_PATH variable.
Uninstall the library located in the "wrong" directory.
E.g. if you have newer version of the library and never intend to use the older one, then for avoid confusion it is better to uninstall the later.
If the "wrong" directory is searched by the loader because it is included into the variable LD_LIBRARY_PATH, then set this variable to not contain that directory.
CMake is able to correctly build projects for run without LD_LIBRARY_PATH settings.
If "wrong" directory is searched by the loader because it contains some other libraries, eliminate usage of that libraries in your executable.
If you have two "repositories" of libraries on your PC, then compatibility between libraries is guaranteed only within a single repo. Mixed usage of libraries could lead to incompatibility problems at runtime.

If you're dealing with find_library
find_library(LIBRARY_NAME PATHS "/usr/lib/x86_64-linux-gnu" NO_DEFAULT_PATH) where
PATHS stands for the exact path to the libs
NO_DEFAULT_PATH means, that cmake will not search anywhere else
check the values of lib and include paths with message(status, ${LIBRARY_NAME})
If you're dealing with find_package:
It's a bit more complicated than the previous example, but it's essentially the same.
For each package you have to run find_package for:
Create file with name Find<Packagename>.cmake, e. g. if you're looking for cppunit, you'll have to create FindCPPUNIT.cmake.
In that file, you'll have to run find_path on include files and find_library on lib files, like in "If you're dealing with find_library".
find_path(CPPUNIT_INCLUDE_DIR PATHS "/usr/include/x86_64-linux-gnu" NO_DEFAULT_PATH)
find_library(CPPUNIT_LIBRARY PATHS "/usr/lib/x86_64-linux-gnu" NO_DEFAULT_PATH)
And then you have to add the path to the file to CMAKE_MODULE_PATH.

Your system libraries are conflicting with your local custom build Qt libraries. Its a warning but you might not get expected results in your application because of this. You need to tell CMake that it should exclude system path while searching for libraries in your CMakeModule. From this documentation
If NO_DEFAULT_PATH is specified, then no additional paths are added to
the search.
Also in same documentation one more flag is mentioned NO_CMAKE_SYSTEM_PATH which only include platform specific default paths.

Related

CMake: Error including library from another package [duplicate]

I am writing a C++ library (header-only) and am using CMake to generate my (Visual Studio) project and solution files. I'm also writing a test suite, which is part of the same CMake project.
My problem occurs when I call target_include_directories() on the target that represents my header-only library, so that consumers of my library may find its header files. I get the following error message (even though generation is NOT aborted).
CMake Error in CMakeLists.txt:
Target "Fonts" INTERFACE_INCLUDE_DIRECTORIES property contains path:
"D:/Projects/GPC/fonts/include"
which is prefixed in the source directory.
(D:/Projects/GPC/Fonts being the top-level directory of my library project. Btw the problem remains if I move my header files to the top directory.)
The offending line in my CMakeLists.txt is this (adapted for simplicity):
target_include_directories(Fonts INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
I do not understand what I'm doing wrong. Without target_include_directories(), code of consumer projects simply can't include my header files (unless in installed form, but I haven't gotten to that yet, and in any case I want to be able to use my library from its build tree, without installation.)
I feel like I'm missing something basic here; yet I've searched for hours without finding a solution or explanation.
The origin of the problem is not the target_include_directories command itself, but the attempt to install a target that has a public or interface include directory prefixed in the source path (i.e. the include directory is a subdirectory of your ${PROJECT_SOURCE_DIR}.)
While it is perfectly fine and desirable to use absolute paths when building the library from scratch, a third party library that pulls in a prebuilt version of that library will probably want to use a different include path. After all, you do not want all of your users to mirror the directory structure of your build machine, just to end up in the right include path.
CMake's packaging mechanism provides support for both of these use cases: You may pull in a library directly from the build tree (that is, check out the source, build it, and point find_package() to the directory), or from an install directory (run make INSTALL to copy built stuff to the install directory and point find_package() to that directory). The latter approach needs to be relocatable (that is, I build and install on my machine, send you the resulting directory and you will be able to use it on your machine from a different directory structure), while the former is not.
This is a very neat feature, but you have to account for it when setting up the include directories. Quoting the manual for target_include_directories:
Include directories usage requirements commonly differ between the
build-tree and the install-tree. The BUILD_INTERFACE and
INSTALL_INTERFACE generator expressions can be used to describe
separate usage requirements based on the usage location. Relative
paths are allowed within the INSTALL_INTERFACE expression and are
interpreted relative to the installation prefix. For example:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
$<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
)
The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions do all the magic:
$<INSTALL_INTERFACE:...>
Content of ... when the property is exported using install(EXPORT), and empty otherwise.
$<BUILD_INTERFACE:...>
Content of ... when the property is exported using export(), or when the target is used by another target in the same buildsystem.
Expands to the empty string otherwise.

Best practices with CMake with non-standard include and library directories

I have been trying to build Mozilla RR on a Linux box at work using CMake. We have a slightly eccentric arrangement where shared libraries are stored on network drives in locations like /sw/external/product-name/linux64_g63.dll/. Further, I have built some dependencies for the project in $HOME/sw/. (I am not a sudoer on this box.)
I am rather baffled as how I am supposed to communicate to CMake to look in non-standard directories. So far I have fudged:
PKG_CONFIG_PATH=$HOME/sw/capnproto-0.6.1/lib/pkconfig \
CC=gcc-6.3 CXX=g++-6.3 \
cmake \
-DCMAKE_INSTALL_PREFIX=$HOME/sw/rr-5.1.0 \
-DPYTHON_EXECUTABLE=$HOME/bin/python2 \
-DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/ \
../src/
Which is obviously not a scalable solution, but it does at least complete the configuration successfully and emit some Makefiles.
If I omit -DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/, CMake fails, complaining about a missing libseccomp-2.2.3 dependency. But it works if I do have that definition, telling me that CMake understands where the libseccomp-2.2.3 files are and so will properly add the paths to the necessary compiler invocations.
However, make does not succeed, because gcc fails to find a required header file from the libseccomp probject. Examining make VERBOSE=1, I find that CMake hasn't added -I$HOME/sw/libseccomp-2.2.3/include to the gcc invocation.
I feel like this is not the right approach. The other answers I have looked at tell me to modify the CMakeLists.txt file, but surely
that is not going to be scalable across multiple CMake projects, and
for each project, that will need me to maintain a separate CMakeLists.txt file for every platform (Solaris/Linux/Darwin/Cygwin) I build the software on.
Is there a canonical solution to solving this problem? Perhaps a per-site configuration file that will tell CMake how to find libraries and headers, for all projects I build on that site?
Your approach is correct, but cmake is never told to include SECCOMP - see end of this post.
The way cmake can be informed about custom dependency directory depends on how the dependency is searched (i.e. on what is written in CMakeLists.txt).
find_package/find_library/find_path/find_program
If dependency is found with one of above-mentioned commands, custom search directories can be easily added with CMAKE_PREFIX_PATH. There is no need to add full path to include, lib or bin - when package root is added find_-command will check appropriate sub-directories. CMAKE_PREFIX_PATH can be also set with environment variable.
Second option is CMAKE_FIND_ROOT_PATH. Every path added to CMAKE_FIND_ROOT_PATH list treated as separate root directory and is searched before system root directory.
Note that CMAKE_FIND_ROOT_PATH will be ignored by find_-commands with NO_CMAKE_FIND_ROOT_PATH argument.
Following four variables may be used to tune the usage of CMAKE_FIND_ROOT_PATH:
CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
When use of host system default libraries is undesired setting CMAKE_FIND_ROOT_PATH_MODE_INCLUDE and CMAKE_FIND_ROOT_PATH_MODE_LIBRARY to ONLY is a good practice. If dependency library or header is not found in CMAKE_FIND_ROOT_PATH the configuration will fail. If cmake is allowed search system paths too, it is most likely that errors will occur during linking step or even runtime.
See find_package docs for more details.
find_package only
All above applies to find_package command too.
find_package can operate in two modes MODULE and CONFIG.
In MODULE mode cmake uses Find[PackageName].cmake script (module) to find dependent package. CMake comes with large number of modules and custom modules can be added with CMAKE_MODULE_PATH variable. Often find-modules can be informed about custom search paths via environment or cmake variables.
E.g. FindGTest.cmake searches path stored in GTEST_ROOT variable.
If no find module is available, find_package enters CONFIG mode. If a dependency package provides [PackageName]Config.cmake or [LowercasePackageName]-config.cmake cmake can be easily informed about that package with [PackageName]_DIR variable.
Example:
CMakeLists.txt contains:
find_package(Qt5)
FindQt5.cmake is not available, but ~/Qt5/Qt5.8/lib/cmake/Qt5Config.cmake file exists, so add
-DQt5_DIR="${HOME}/Qt5/Qt5.8/lib/cmake"
to cmake call.
pkg-config
CMake can use information provided by external pkg-config tool. It is usually done with pkg_check_modules command. Directory used by pkg-config can be customized with PKG_CONFIG_PATH environment variable. According to cmake documentation instead of setting PKG_CONFIG_PATH, custom .pc-files directories can be added via CMAKE_PREFIX_PATH. If CMake version is pre-3.1, PKG_CONFIG_USE_CMAKE_PREFIX_PATH have to be set to TRUE(ON) to enable this feature.
Methods of customizing dependencies search path is defined by CMakeLists.txt content. There is no universal solution here.
And now back to missing SECCOMP headers...
In CMakeLists.txt SECCOMP header is found with
find_path(SECCOMP NAMES "linux/seccomp.h")
but I cannot find any command telling CMake to use the found header. For example:
target_include_directories(<target_name> ${SECCOMP})
or globally:
include_directories(${SECCOMP})
I belive that CMakeLists.txt should be fixed. It is not a platform dependent solution.

CMAKE - runtime library hidden files

I am running Linux Redhat, I have Anaconda installed and I am trying to install a program (libspimage) using CMAKE amd I get the following warning/error:
CMake Warning at src/CMakeLists.txt:74 (ADD_LIBRARY):
Cannot generate a safe runtime search path for target _spimage_pybackend
because files in some directories may conflict with libraries in implicit
directories:
runtime library [libtiff.so.5] in /usr/lib64 may be hidden by files in:
/home/michantia/anaconda2/lib
Some of these libraries may not be found correctly.
When I do:
echo $PATH
I get:
/home/mi_a/anaconda2/bin:/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/michantia/.local/bin:/home/michantia/bin
I tried:
export PATH=/usr/lib64:$PATH
hoping cmake would find the libraries in this directory before finding them in anancoda's, but that did not work. I also tried two other similar suggestions for a similar problem that I saw in stackoverflow, but that did not work.
Any other ideas are highly welcomed.
Warning message
Cannot generate a safe runtime search path for target
is related neither with CMake ability to find a library (libtiff.so.5 in your case) nor with a linker ability to link the library.
The warning message means that when a target (_spimage_pybackend) will be loaded, the loader will be unable to choose the correct library: according to the loader's algorithm and the target's setting, file /home/michantia/anaconda2/lib/libtiff.so.5 will be choosen instead of proper one /usr/lib64/libtiff.so.5.
The error is usually resulted in linking into the single target two libraries from different directories, when the directory with a second library also contains a file with the name of the first library:
Directory /usr/lib64 contains a library libtiff.so.5, which is linked into the target.
Directory /home/michantia/anaconda2/lib contains a library <A> which is also linked into the target; but this directory also contains a file libtiff.so.5.
According to CMake algorithm, runpath for the binary file of such target will include both directories, so both libraries could be found. But such runpath confuses the loader to find the first library properly.
Except from avoiding such situation (when a library is contained in two directories), one hardly is able to handle this warning.

default search paths for CMake include() vs. find_package()

I have VTK6 installed on my Debian machine and it places all its CMake files under
$ ls /usr/lib/cmake/vtk-6.3/
[...]
VTKConfig.cmake
vtkModuleAPI.cmake
[...]
When I do
find_package(VTK)
in another project, it all works out fine. However,
include(vtkModuleAPI)
yields the error
include could not find load file:
vtkModuleAPI
I had always been under the impression that find_package() and include share the same search paths, specifically CMAKE_MODULE_PATH. Apparently that's not correct.
Note that
SET(CMAKE_MODULE_PATH "/usr/lib/cmake/vtk-6.3")
include(vtkModuleAPI)
does work.
Also note that I'm using CMake 3.5, so there no longer is a FindVTK.cmake as it used to be.
What are the default search paths for find_package() and include()? Why is vtkModuleAPI.cmake not found?
There are two modes of find_package, which have many differences:
Module mode tries to locate FindXXX.cmake file. The file is searched under directories listed in CMAKE_MODULE_PATH plus under directory where CMake is installed.
Config mode tries to locate XXXConfig.cmake file. The file is searched under directories listed in CMAKE_PREFIX_PATH and some other, system-specific variables. (Full algorithm see in the documentation, linked at the beginning of the post).
Command include searches modules only under directories in CMAKE_MODULE_PATH and special CMake module directory.
As you can see, command include and command find_package in module mode uses similar search paths. But in your case, VTKConfig.cmake can be searched only in config mode of find_package, which uses completely different search algorithm.
In case of VTK, CMake has shipped FindVTK.cmake file, which is used when you call find_package(VTK). But inside, this script uses find_package(VTK QUIET NO_MODULE).
If this call locates file /usr/lib/cmake/vtk-6.3/VTKConfig.cmake, it executes this script, and the script includes vtkModuleAPI.cmake one.
If your VTKConfig.cmake is not located by CMake, you may help it by setting VTK_DIR variable to /usr/lib/cmake/vtk-6.3/.
[Starting with CMake-3.1, FindVTK.cmake is no longer shipped with CMake, so find_package(VTK) immediately tries to locate VTKConfig.cmake].
In any case, modules in directory /usr/lib/cmake/vtk-6.3/ shouldn't be included directly: this directory is private for VTK.
find_package(VTK) uses FindVTK.cmake (in it's module mode, c.f. docu on find_package()), which is shipped by CMake and (in your case) should be located in /usr/share/cmake/Modules.
After adding /usr/lib/cmake/vtk-6.3 to CMAKE_MODULE_PATH, find_package(VTK) will still use the same FindVTK.cmake module.
In case you want to use another FindVTK.cmake module, prepend the path to that FindVTK.cmake module to CMAKE_MODULE_PATH.
include() will not use a find module and only sees files located in the CMAKE_MODULE_PATH.

CMake find package files, how are the config files used?

I have a project that uses a 3rd party library (let's call it somelib) for which I wrote a cmake file to search for it.
This is the somelibConfig.cmake file I wrote and placed in /usr/local/lib/cmake/somelib/:
FIND_LIBRARY(somelib_LIBRARY somelib
PATHS /usr/local/lib
NO_DEFAULT_PATH
)
SET(somelib_LIBRARIES ${somelib_LIBRARY})
FIND_PATH(somelib_INCLUDE_DIR somelib.hpp
PATHS /usr/local/include/somelib
NO_DEFAULT_PATH
)
SET(somelib_INCLUDE_DIRS ${somelib_INCLUDE_DIR})
Then, if I do find_package(somelib REQUIRED) it works ok.
However, if I move and rename somelibConfig.cmake to myproject/CMakeModules/Findsomelib.cmake (this directory is added to CMAKE_MODULE_PATH), after find_package I see that variables somelib_INCLUDE_DIRS and somelib_LIBRARY are correctly filled, but somelib_FOUND is not set (and even so, find_package does not abort the compilation).
Is that *Config.cmake valid for a Find*.cmake?
How is it possible that all the variables but the *_FOUND one are set?
Why does not find_package with REQUIRED abort the compilation if *_FOUND is not set?
Config files and find-modules are fundamentally different.
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
Only the developers of somelib ship a config file (if they do). If they don't, then you need to write a find-module to find somelib. Such a find-module should not be copied to /usr/local as you did. Just keep it with your project and ask the somelib developers to ship a config file instead. config files shipped by upstream is superior to find modules written by you. It doesn't matter if somelib upstream does not use cmake. Both Qt and LLVM ship config files when using non-cmake buildsystems.
One example of inferiority is that when writing a find-module you need to set the _FOUND variable. More information about writing find-modules is here:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#manual:cmake-developer%287%29
If you are searching in default library folder your parameters should not contain NO_DEFAULT_PATH.
Try this,
SET(libraryName "somelibrary.so") #in linux .a or .so
FIND_LIBRARY(LIBRARY ${libraryName}
PATHS "/usr/local/lib/cmake/somelib/"
)
MESSAGE("library path ${LIBRARY})
If this was successful, LIBRARY_FOUND will be set.
P.S: Note the quotes