CMake FindXercesC.cmake does not find my XercesC - c++

On my system (Fedora 26), I installed XercesC using yum (aka dnf). The XercesC header files are located in
/usr/include/xercesc-2.7.0/xercesc
and the library is
/usr/lib64/libxerces-c.so.27.
I have tried the official FindXercesC.cmake as well as a number of posted versions of this package finder. I also attempted many edits to the posted *.cmake files. None of them can locate XercesC and I have to resort to manually entering the locations for the headers and library.
Is there a CMake package finder for XercesC that will automatically locate XercesC on my system?

Normally, CMake search things only in default directories. E.g., /usr/include directory is automatically searched for the header files.
But directory /usr/include/xercesc-2.7.0 isn't a default for CMake (it is not default for compiler too), so CMake cannot find things there without an explicit hint. For hint CMake about include directory to search, set CMAKE_INCLUDE_PATH variable. E.g., via command line:
cmake -DCMAKE_INCLUDE_PATH=/usr/include/xercesc-2.7.0 <other_params>
Similar is true for searching library files: CMake automatically searches libraries under /usr/lib64/, but not under /usr/lib64/xercesc-2.7.0. Also, CMake can find only library without so-version, so it cannot find file /usr/lib64/libxerces-c.so.27. For finding a file /usr/lib64/xercesc-2.7.0/libxerces-c.so you need to hint CMake with CMAKE_LIBRARY_PATH variable.
According to the xercesc sources, it supports searching the package via pkg-config and via CONFIG mode of find_package. Probably, these variants won't require additional hints.
Searching via pkg-config can be performed with pkg_check_modules, for use find_package in CONFIG mode either add this option to the call find_package(XercesC), or simply remove FindXercesC.cmake script.

Related

Custom library directory for cmake

For my project, I am building specific versions of the dependency libraries in a separate folder, say, /home/ubuntu/libs. I will use real libraries as an example, however, the question is pretty generic.
I was able to build the freetype library and make installed the headers into /home/ubuntu/libs/include, the built library into /home/ubuntu/libs/lib and also added the freetype-config.cmake to /home/ubuntu/libs/lib/cmake.
Now, I am trying to build the freetype-gl library that depends on freetype and has a line
find_package(freetype REQUIRED) in its CMakeLists.txt.
Typically, when I install the freetype library to a common path like /usr/local/lib or /usr/lib, cmake picks up the *-config.cmake files from the corresponding ./cmake directory. However, when I call it with
cmake -DCMAKE_TOOLCHAIN_FILE=/my/custom/toolchain -DCMAKE_LIBRARY_PATH=/home/ubuntu/libs/lib -DCMAKE_INCLUDE_PATH=/home/ubuntu/libs/include /path/to/freetype-gl
it fails with the following error
CMake Error at CMakeLists.txt:102 (find_package):
By not providing "Findfreetype.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "freetype",
but CMake did not find one.
Could not find a package configuration file provided by "freetype" with any
of the following names:
freetypeConfig.cmake
freetype-config.cmake
Add the installation prefix of "freetype" to CMAKE_PREFIX_PATH or set
"freetype_DIR" to a directory containing one of the above files. If
"freetype" provides a separate development package or SDK, be sure it has
been installed.
What am I doing wrong? How to show the place of "freetype-config.cmake" to cmake.
as you state in your second paragraph:
I was able to build the freetype library and make installed the headers into /home/ubuntu/libs/include, the built library into /home/ubuntu/libs/lib and also added the freetype-config.cmake to /home/ubuntu/libs/lib/cmake.
find_package() in CMake works in a way that it checks the standard system paths on default. If you are using CMake version 3.17 you can (instead of reading the documentation) view these paths simply by adding this line to your CMakeLists.txt
SET(CMAKE_FIND_DEBUG_MODE TRUE)
In your case what you need to do is point CMake in the right direction of the cmake file you are looking for. In your case that would be the /home/ubuntu/libs/lib/cmake. So somewhere in the top of your CMakeLists.txt (before you call find_package()) add this line:
LIST(APPEND CMAKE_MODULE_PATH "/home/ubuntu/libs/lib/cmake")
Provided that this bash command:
ls /home/ubuntu/libs/lib/cmake | grep "*.cmake"
Returns an occurance of freetypeConfig.cmake (you get the drill :) )
You can read about CMAKE_MODULE_PATH variable here: https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
In short your CMake doesn't find the config file because it is not in the standard path where it expects to find it.
EDIT: You can ofcourse do the same via these variables as the error suggests - CMAKE_PREFIX_PATH or freetype_DIR
Presumably you also don't want the libraries you build to find their dependencies installed on our system, if any.
I've spent some time investigating how to isolate CMake builds, and my best recipe is below.
First, the terminology:
An installation "prefix" of a library is a directory where the binaries and headers are installed (normally in include and lib subdirectories). I preder distinct prefixes for each library.
A "dependency" of a library is any of other library it needs when compiling.
CMake path separator - the character used to separate path lists for CMake. It's : character on Windows and ; on Linux (when cross-compiling, the host system matters, not the target).
Yes, it's the opposite of what the documentation claims.
By Windows I mean MSYS2. If you want to build outside of it, check that : is still the right separator.
Environment variables for CMake:
PKG_CONFIG_PATH to empty string
PKG_CONFIG_LIBDIR to a :-separated list, for each dependency add <prefix>/lib/pkgconfig and <prefix>/share/pkgconfig.
(I didn't need to do it for any library I used, so this is theoretical. But in any case don't leave this variable unset, at least use an empty string. Otherwise some undesired dependencies from your system might leak in.)
CMake flags:
-DCMAKE_INSTALL_PREFIX=... - the installation prefix for this library.
-DCMAKE_PREFIX_PATH=... - a path list: the installation prefix, followed by the prefixes of all dependencies. Use the CMake path separator, as described above. All paths here must be absolute.
-DCMAKE_FIND_USE_CMAKE_SYSTEM_PATH=OFF
This prevents CMake from finding some system-wide dependencies. If I remember correctly, not doing this makes CMake look for dependencies in directories listed in PATH and their parent directories, which is annoyting.
This has an undesired effect of disabling some ..._SYSTEM_... CMake variables, so we can't use those, even though some of them would be more appropriate.
-DCMAKE_STAGING_PREFIX=/. On Windows hosts replace / with the current drive name, e.g. C:.
This is only useful when cross-compiling, to disable the effects of CMAKE_FIND_ROOT_PATH in the toolchain file, which otherwise limits dependency search to that path.
This also messes up the installation path that would otherwise be taken from CMAKE_INSTALL_PREFIX, the fix is explained below.
Only on Windows hosts:
-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF - otherwise CMake tends to look for dependencies in the PATH and parent directories, which is annoying. This is hardcoded to only happen on Windows hosts, which is nonsense and was reported here.
We don't want to set this unconditionally, because it has a side effect of requiring all your toolchain executables to be in the same directory, which is annoying in general, but IMO tolerable on Windows.
It also prevents CMake from searching for executables in PATH, so we also need...
-DCMAKE_PROGRAM_PATH= - set this to the contents of PATH, with the original separator replaced with the CMake path separator. At least on MSYS2 the separators are the same, so no modifications are needed.
-DCMAKE_MAKE_PROGRAM=ninja -GNinja - here CMAKE_MAKE_PROGRAM is strictly necessary on Windows hosts because of CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF, and doesn't hurt on other platforms. -G... is to make sure CMake doesn't pick a different generator that doesn't match CMAKE_MAKE_PROGRAM. You can use any other generator+program if you wish.
Then build with cmake --build <build_dir> -j<num_threads> as usual.
Install with cmake --install <build_dir> --prefix <prefix>. We need to explicitly set prefix because of CMAKE_STAGING_PREFIX=/.

How to find .pc files for pkg-config via Conan and CMake

How can I make pkg-config find both dependencies installed via Conan AND dependencies that are not in Conan?
My target package is built using CMake and finds its dependencies using pkg-config with pkg_check_modules(). One of the dependencies (glib-2.0) is installed via Conan, another (libsecret-1) isn't, as there's no package.
In my conanfile I'm configuring the pkg-config_installer as a build requirement (self.build_requires("pkg-config_installer/0.29.2#bincrafters/stable"). When building the package, CMake correctly invokes this pkg-config.
As a result, pkg-config finds glib just fine, but it cannot find libsecret. I assume it finds .pc files for dependencies installed via Conan, but doesn't find libsecret-1.pc, which is located in /usr/lib/pkgconfig/ on my system.
I tried telling Conan's CMake tool to use this path: tools.PkgConfig("libsecret-1").variables["pcfiledir"] tells me where it is and the CMake tool's configure method has a pkg_config_paths parameter. Unfortunately, this changes nothing.
The following steps made it work for me:
set the PKG_CONFIG_PATH environment variable to the pcfiledir found by tools.PkgConfig
do not to pass any pkg_config_paths to tools.CMake.configure(), it doesn't handle absolute paths well and conflicts with the environment variable
add the system-wide installed lib (secret-1 in my case) to cpp_info.system_libs in the package_info step
Thanks #uilianries for the helpful comment!

CMake "find_package" command on a package that was not installed is unexpectedly successful

I am following chapter-02/recipe-06 in "CMake Cookbook". This particular example requires the Eigen C++ libraries.
I attempted to build the example and got the error that Eigen was not found.
CMake Error at CMakeLists.txt:9 (find_package):
Could not find a package configuration file provided by "Eigen3" (requested
version 3.3) with any of the following names:
Eigen3Config.cmake
eigen3-config.cmake
Add the installation prefix of "Eigen3" to CMAKE_PREFIX_PATH or set
"Eigen3_DIR" to a directory containing one of the above files. If "Eigen3"
provides a separate development package or SDK, be sure it has been
installed.
This was expected because the library was not installed on my system.
I then downloaded the ".zip" file for the Eigen libraries and unzipped it to an arbitrary location outside of my project. I created a "build" folder in the Eigen directory and ran cmake .. in the "build" folder. (I only ran cmake - I did NOT build or install the package.)
After running CMake on the Eigen build directory, I went back to the example code for "recipe-06" and it was magically able to find the Eigen library and built successfully even though Eigen was never built or installed.
Somehow just running CMake in the Eigen project made CMake aware of the Eigen libraries location. After doing this, any projects that do find_package to find Eigen3 somehow get the ${Eigen3_DIR} variable defined and are able to find it.
Looking at the CMake documentation for find_package I don't see any explanation of why this works. Eigen is not in any of the typical locations that find_package searches. According to the documentation it looks like it should NOT be found.
Even more interesting - it doesn't matter where I put Eigen on my system. I can put it literally anywhere and it will still find it.
According to everything I see in the documentation it should not be found... but it is found. So the question is how? Why does this work?
Additional info: I am using CMake version 3.13.3
There are 2 "origins" of XXXConfig.cmake files, used internally by find_package() call.
Usually, XXXConfig.cmake file is produced when the project is installed, and the file contains information about installed libraries and headers.
But CMake provides also an export() command, which allows to export build tree.
export(PACKAGE <name>)
Store the current build directory in the CMake user package registry for package <name>. The find_package command may consider the directory while searching for package <name>.
Eigen's CMakeLists.txt uses export() command, so the project becomes detectable with find_package just after running cmake for Eigen.

How to use cmake to check if some libraries exists before build our sources?

Usually, open source packages will have cmake to check if some headers or libraries exists or not, I wish my own project has this same functionality.
So I wish to know if cmake provides some command to check if some ".so"/".a"/".h" files exists in the current linux system or not, if not cmake will give me some hint to install them?
How does cmake support this?
Usually one would use the find_package(ABC REQUIRED) and then refer to it in your project. This will ensure that the dependent library is installed and cmake will fail if it is not.
You can find lot's of example on how this works in your cmake installation, for example C:\Program Files\CMake\share\cmake-3.13\Modules\FindZLIB.cmake will search for the zlib library by looking in the file system for normal places where this library would be installed and if it finds it will set these variables accordingly:
# ZLIB_INCLUDE_DIRS - where to find zlib.h, etc.
# ZLIB_LIBRARIES - List of libraries when using zlib.
# ZLIB_FOUND - True if zlib found.
To achieve this header files are found using the cmake command find_path, and libraries (static and shared) are found using find_library.
To search for arbitrary library you can use find_library() command. Same task for headers is accomplished by find_file(). You can also search for executables with find_program().
As #Damian said in his naswer, many libraries provide "config" files, like FindBoost.cmake. Such libraries can be found by calling find_package(Boost) command. This command would locate and load config file and set corresponding variables.
You need to provide -config.cmake files to tell other projects where your libraries and headers are. Here, you will found what are you looking for.

CMake CEGUI / GTK2 Configuration Error

I am trying to build and use CEGUI (Crazy Eddie's GUI) as a library for Ogre. I am using CMake, but during the configuring step for the dependencies, I got the following error:
Some or all of the gtk libraries were not found. (missing: GTK2_GTK_LIBRARY GTK2_GTK_INCLUDE_DIR GTK2_GDK_INCLUDE_DIR GTK2_GDKCONFIG_INCLUDE_DIR GTK2_GDK_LIBRARY GTK2_GLIB_INCLUDE_DIR GTK2_GLIBCONFIG_INCLUDE_DIR GTK2_GLIB_LIBRARY)
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
Boost_INCLUDE_DIR (ADVANCED)
used as include directory in directory C:/Cegui/cegui-0.8.3/cegui/src/RendererModules/Ogre
CEGUI 0.8.3
cegui-deps-0.8.x-src.zip
Make sure that you have GTK2 installed on your machine (as far as I can tell, it is not part of the CEGUI dependency download archive).
Ensure that CMake can find the library and all it needs. From having a look at the official CMake FindGKT2 script (and I couldn't find a custom one for CEGUI, so the official one is most likely used), the following locations are checked:
/usr/local/lib64
/usr/local/lib
/usr/lib64
/usr/lib
/opt/gnome/include [and /lib]
/opt/openwin/include [and /lib]
/sw/include [and /lib]
/opt/local/include [and /lib]
/usr/pkg/lib
/usr/pkg/include/glib
$ENV{GTKMM_BASEPATH}/include [and /lib]
[HKEY_CURRENT_USER\SOFTWARE\gtkmm\2.4;Path]/include
[HKEY_CURRENT_USER\SOFTWARE\gtkmm\2.4;Path]/lib
[HKEY_LOCAL_MACHINE\SOFTWARE\gtkmm\2.4;Path]/include
[HKEY_LOCAL_MACHINE\SOFTWARE\gtkmm\2.4;Path]/lib
So if you are on windows, setting the environment variable GTKMM_BASEPATH will probably be the easiest way. Alternatively, you can also directly enter the paths to your GTK2 installation in the advanced CEGUI view.