Building and running binaries using Cmake (on Linux) linking problem - cmake

I have built a server binary using cmake (and also make) for arm and x86 targets. I am able to run my server on arm using correct linking paths for RPATH, for example populating CMAKE_INSTALL_RPATH. However when I try to run my x86 server it complains about not being able to find my databases. Would I be right in saying that CMAKE_INSTALL_RPATH is used for libraries only and not to find files or databases. Is there another cmake variable that is used to find files or databases at run time or by correctly populating CMAKE_INSTALL_RPATH it should find files and databases as-well as libraries.
Thanks Paul.

You are correct that the CMAKE_INSTALL_RPATH only deals with finding shared libraries. Specifically, setting the RPATH just gives the dynamic linker a list of directories to search for shared libraries.
If you want to find a file or database at runtime from within your application, you have to get the paths into your application some other way. This could be via a config file or hardcoded constants that are different for each platform.

Related

How to tell CMake NOT to search system paths for libraries

I have a project that uses several different open source libraries (FFmpeg, OpenSSL, for example).
No matter what I try, CMake is linking against the SYSTEM installed versions of these libraries, rather than the custom built ones I need for my projects.
Here is an example of what I've tried to add the FFmpeg library 'libswresample':
set(FFMPEG_PATH "/shared/dev/libs/ffmpeg/3.4.2")
find_library(LIBSWRESAMPLE_LIB NAMES swresample
PATHS ${FFMPEG_PATH}/lib/darwin-amd64
NO_DEFAULT_PATH
NO_CMAKE_ENVIRONMENT PATH
NO_CMAKE_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH
NO_CMAKE_FIND_ROOT_PATH)
list(APPEND includes "${FFMPEG_PATH}/include")
link_directories("${FFMPEG_PATH}/lib/${ARCH}")
list(APPEND libs ${LIBSWRESAMPLE_LIB})
MESSAGE(STATUS "libs: ${libs}")
I've tried setting CMAKE_PREFIX_PATH to the location of my shared libraries - no luck.
I've tried this with various combinations of the "NO_SOMETHING_PATH" options, which doesn't seem to help. I also tried just giving ${FFMPEG_PATH} to the PATHS parameter of find_library() and providing PATH_SUFFIXES lib ${ARCH} (which would be ideal, since I build this project for multiple platforms), but that didn't work either.
No matter what I've tried, MESSAGE outputs libs: /usr/local/lib/libswresample.dylib, rather than libs: /shared/dev/libs/ffmpeg/3.4.2/lib/darwin-amd64/libswresample.dylib
I've found several FindFFMpeg modules, but they all are pretty much doing what I'm trying here and wind up finding the system installed FFmpeg libraries rather than the one I actually want to link with.
If I explicitly provide the absolute path to the library I can get it to work, but this is obviously not optimal since some platforms use static libraries, some use shared libs, and so on. If I were to go that route, I'd have to additional work to figure out which platform I'm building for, and that doesn't seem like the right way to go about it anyways.
I know I must be missing something simple. Can anyone point me in the right direction?
The code works, but you should clear CMake cache (remove CMakeCache.txt file from build directory) for re-search the library.
Option NO_DEFAULT_PATH implies all other NO_* options, so you may omit them.

Package vs Library

I've just started working with CMake and I noticed that they have both a find_package and a find_library. And this confuses me. Can somebody explain the difference between a package and a library in the world of programming? Or, in the world of CMake?
Appreciate it, guys!
Imagine you want to use zlib in your project, you need to find the header file zlib.h, and the library libz.so (on Linux). You can use the low-level cmake commands find_path and find_library to find them, or you can use find_package(ZLIB). The later command will try to find out all what is necessary to use zlib. It can be extra macro definitions, or dependencies.
Update, more detail about find_package: when the CMake command find_package(SomeThing) is called, as in the documentation, there are two possible modes that cmake can run:
the module mode (that searches for a file FindSomeThing.cmake)
or the config mode (that searches for a file named SomeThingConfig.cmake)
For ZLIB, there is a module named FindZLIB, shipped with CMake itself (on my Linux machine that is the file /usr/share/cmake/Modules/FindZLIB.cmake). That module is a CMake script that uses the CMake API to search for ZLIB files in default locations, or ask the user for the location if it cannot be found automatically.

How to find RelWithDebInfo or MinSizeRel libraries with CMake?

I'm trying to link my project to a external library that I also developed in which also also use CMake to build. When I try to find RelWithDebInfo or MinSizeRel like this:
FIND_LIBRARY(PCM_LIBRARY_DEBUG pcm
PATHS #CMAKE_LIBRARY_OUTPUT_DIRECTORY#
#CMAKE_LIBRARY_OUTPUT_DIRECTORY#/Debug
NO_DEFAULT_PATH
)
FIND_LIBRARY(PCM_LIBRARY_RELEASE pcm
PATHS #CMAKE_LIBRARY_OUTPUT_DIRECTORY#
#CMAKE_LIBRARY_OUTPUT_DIRECTORY#/Release
#CMAKE_LIBRARY_OUTPUT_DIRECTORY#/MinSizeRel
#CMAKE_LIBRARY_OUTPUT_DIRECTORY#/RelWithDebInfo
NO_DEFAULT_PATH
)
SET(PCM_LIBRARIES debug ${PCM_LIBRARY_DEBUG} optimized ${PCM_LIBRARY_RELEASE})
It does not search in ather directories that are not Release or Debug. I also tried creating PCM_LIBRARY_RELWITHDEBINFO and PCM_LIBRARY_MINSIZEREL but the same thing happens because there is only debug and optimized prefixes in SET. Anyone knows how can I link the correct libraries?
This is unfortunately one of the shortcomings of using find_library. There is no easy way around this without introducing tons of boilerplate code.
The problem here is that when passing files as dependencies to target_link_libraries, you can only distinguish between debug and optimized. If you need more fine-grained control, you will have to manipulate the respective target properties like LINK_INTERFACE_LIBRARIES directly. This is not only quite cumbersome, it also requires detailed knowledge about the inner workings of CMake's property system.
Fortunately, there is another way: The aforementioned limitation only applies when specifying dependencies via filenames. When specifying them as targets, this problem does not occur. The most obvious example is if a library and the executable that depends on it are built from the same source:
add_library(foo_lib some_files.cpp)
add_executable(bar_exe more_files.cpp)
target_link_libraries(bar_exe PUBLIC foo_lib)
This 'just works'. The correct library will be chosen for each build configuration. Things get a little more complicated if the library and the executable live in different independent projects. In that case the library has to provide a configure file with an exported target in addition to the binary files.
Instead of calling find_library to locate the binaries, the dependent executable now just loads that config file and can then use the imported target as if it was a target from the same project.
Many modern libraries already use this approach instead of the classical find_library technique (Qt5 is a prominent example). So if you are at liberty to change the CMakeLists of your dependency and you do not need to support very old CMake versions (<2.6), this is probably the way to go.

What is the default search path for find_package in windows using cmake?

I am porting some code over to windows and my cmake checks for the package Libavahi using
find_package(Libavahi)
I have the headers, dll, etc. but I'm not sure where to place these such that cmake will find them.
Where can I put these files to be found by cmake? They're in a folder called usr.
I see that the module path is specified using:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
but I'm wondering if there is a default location that will be searched as well
The CMake manual fully specifies the rather complicated search order for the different find_* commands. Unfortunately, since Windows lacks a default directory structure à la /usr/local/lib, it is hard to come up with reasonable defaults here.
One of the most reliable ways of managing directories is through environment variable hints. You simply add an $ENV{MY_VAR} to the HINTS section of the find command and then document that environment variable in your project's readme. Most users that are capable of compiling a C++ program know how to use environment variables, and it is way more convenient than having to give the path on the command line every time (although it never hurts to leave that as an additional option).
For find_package CMake offers a special mechanism on Windows called the package registry. CMake maintains a list of package information in the Windows registry under HKEY_CURRENT_USER\Software\Kitware\CMake\Packages\. Packages build from source can register there using the export command. Other projects build later on the same machine will then be able to find that package without additional configuration. This is quite powerful if you need to build a lot of interdependent projects from source on the same machine.
Update: Starting with version 3.12, CMake now implicitly considers the <PackageName>_Root environment variable a HINT for every find_package call.
In the newer versions of cmake, you can use the --debug-find option to list the directories that cmake is searching through. Somethin like:
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TOOLS=ON --debug-find .

Is there any interactive shell for module development in cmake?

CMake is awesome, especially with lots of modules (FindOOXX). However, when it comes to write a FindXXX module, a library XXX which your project depends, it's not that easy to handle for non-cmake-expert. I sometimes encounter a library without support to CMake, and I like to make one for it. I'm wondering if there is any interactive shell while writing/testing cmake modules?
Are you writing FindXXX for project "XXX" or is "XXX" a dependency of your project that you're trying to find? If the former, you should instead write a file called XXX-config.cmake (or XXXConfig.cmake) and install it into one of the directories mentioned in the docs for find_package. In general, XXX-config.cmake files are for projects which are expected to be found by CMake (and installed by the project itself) and FindXXX.cmake files are for projects which don't support CMake (and usually have to support finding any version of XXX).
That said, for FindXXX.cmake, usually you just need a few find_file (e.g., for headers), some find_library calls, or even just a single pkg_check_module from FindPkgConfig.cmake followed by a find_package_handle_standard_args call (use include(FindPackageHandleStandardArgs) to get it). FPHSA makes writing proper Find modules a breeze.
For XXX-config.cmake files, I have typically used configure_file to generate two versions: one for the install (which includes your install(EXPORT) file) and one for the build tree (generated by export() calls). Using this, other useful variables can be accurately set such as things like "which exact version of Boost was used" or "was Python support compiled in" so that dependent projects can get a better picture of what the dependency looks like.
I have also recently discovered that CMake ships with the CMakePackageConfigHelpers module which is supposed to help with making these files. There looks to be quite a bit of documentation for it.