How to get package name for use in CMake? - cmake

I have a couple of packages that I require as dependencies for a CMake build of my code. I got them through apt-get and they work.
The specific packages are;
mingw-w64
mingw-w64-i686-dev
I do realize that some people may want to build these dependencies from source, and I'm afraid the name for the apt-get package might not be the same name for the installed source package. I was just wondering, what package name do I put in my CMakeLists.txt file in the find_package(XXX REQUIRED) directive for either or both of these scenarios?

find_package(<package>) has two modes, Module and Config.
In Config mode (which will be used first) looks for a file called <package>-config.cmake / <package>Config.cmake in CMAKE_PREFIX_PATH.
In Module mode, CMake looks for a file calle Find<package>.cmake.
So, if your package is called mingw-w64, than there has to be one of the files mentioned above, e.g. mingw-w64Config.cmake.
The special architecture package mingw-w64-i686-dev is provided for 32bit machines. You will install that package on a 32bit machine and the package would be still called mingw-w64.
PS: Keep in mind that not all packages provide cmake files. If that's the case, you have to write your own Findmingw-w64.cmake file. Have a look here for inspiration.

Related

How can I manage the installation directory with CMake when cross-compiling?

I am cross-compiling a C library using CMake and a toolchain file. My toolchain file sets CMAKE_SYSROOT to the appropriate value so compilation works with no issues. However, when installing, the library does not install to the directory pointed to by CMAKE_SYSROOT. I can achieve that effect by running make install DESTDIR=xxx though.
I understand that there are two separate concepts here:
The cross-compilation toolchain, which consists of binaries that can be run on my local architecture
The CMAKE_SYSROOT which is the root directory of a target-architecture filesystems, containing header files and libraries, passed to e.g. gcc through the --sysroot flag.
I have two questions:
Is it a good idea to conflate the sysroot where my cross-compilation toolchain lives, with the sysroot where all my cross-compiled libraries will be installed? It feels to me like it should be the same, but am not sure, and to CMake it appears they are distinct concepts. Update: answered in the comments below, these are indeed distinct concepts.
What is the modern CMake way to specify the installation directory when cross-compiling like described above? Update: I believe this should be the same as CMAKE_SYSROOT, and I feel CMake should offer a way to only define this once somewhere.
Thanks!
There is no interference between sysroot and install directory (prefix).
Sysroot is given by CMAKE_SYSROOT variable and denotes prefix for tools used during build process.
Install directory(prefix) is given by CMAKE_INSTALL_PREFIX variable and denotes the path, where the project will be used upon installation. E.g. with install prefix /usr/local the project's executable foo expects to be run as /usr/local/bin/foo.
Note, that with default installation procedure, CMake installs files to the host machine. For install files onto the target machine, this procedure is needed to be adjusted. Parameter DESTDIR=xxx for make install is a way for install files directly to the target machine. Another way is to create a package (e.g. with CPack) on host, and install that package on target machine.
Note, that in the above paragraph it is irrelevant, whether cross-compilation took a place or not: it is possible to build the project on one machine and install it to the other, but similar one, without any cross-compilation.

cmake: difference between "make install" and "make package"

I'm using CMake to generate my makefiles. My deployable target is an RPM, and that's all working well. Per the file system guidelines, my RPM installs to
/opt/mytool
/bin - executables
/lib64 - libraries
/etc/opt/mytool - configuration files
The RPM gets built by CPack using make package
During development testing, I don't want to install an RPM. It requires elevated privileges and limits any given machine to one (developer) version at a time. Before I got all the RPM stuff working, I was able to "make install" and create a simple install tree like this:
install
/opt/mytool
bin
lib64
However, the introduction of the config files to a different location has gummed up the works. I'd like this to be extended to include
install
/etc/opt/mytool
but I can live without it. Unfortunately, when I try make install I get this error:
Install the project...
-- Install configuration: "Debug"
CMake Error at cmake_install.cmake:49 (file):
file cannot create directory: /etc/opt/mytool. Maybe need administrative
privileges.
The offending part of the CMakeLists.txt file is
install(FILES ${PROJECT_SOURCE_DIR}/../Config/mytool.cfg
DESTINATION /etc/opt/mytool
)
I've looked at CMake rpm installing a file in /etc/init.d, but my RPM builds just fine (and I'm using CMake 3)
What is the difference between make install and make package (I can infer that the latter is running CPack, and it works just fine)? How can I create a development install tree
The difference between the two build targets is that package creates an RPM file in your case while install copies the resources given to the install() command to the location provided to the DESTINATION parameter:
DESTINATION
Specify the directory on disk to which a file will be
installed. If a full path (with a leading slash or drive letter) is
given it is used directly. If a relative path is given it is
interpreted relative to the value of the CMAKE_INSTALL_PREFIX
variable. The prefix can be relocated at install time using the
DESTDIR mechanism explained in the CMAKE_INSTALL_PREFIX variable
documentation.
You specified to copy files to /etc/opt/mytool for which you obviously have no write permissions and encounter the cited error.
You have two options to resolve this, the second one is clearly preferred, because it allows every developer to provide their own, system-local setting, where to temporarily install dev files:
set a DESTINATION path for which you have write permissions
set a relative path and call cmake with an additional argument to specify where your development install tree is:
cmake -H<source path> -B<build path> -DCMAKE_INSTALL_PREFIX=<install path>

CMake get list of tried package when find_package fails

I have a cmake project and I want to obtain information when a find_package fails.
My setup is this: I have a project that compiles a few libraries and export the targets. The package is exported to the CMake package registry. Then, I have another project that depends on it.
The thing is, the library project has dependencies too. To make the importing package aware, we are using find_dependency in the config file.
When find_package(libs REQUIRED) fails because of missing dependencies, I would like to extract the path of the package it tried. I would use that information to maybe update the list of prefix path in order to find the missing dependencies next time, but I only want to do that if the reason of the failed import is missing dependencies.
Is there any way to obtain these information in a failed find package?
From the CMake documentation for find_package:
All configuration files which have been considered by CMake while searching for an installation of the package with an appropriate version are stored in the cmake variable <PackageName>_CONSIDERED_CONFIGS, the associated versions in <PackageName>_CONSIDERED_VERSIONS.
So using <PackageName>_CONSIDERED_CONFIGS and <PackageName>_CONSIDERED_VERSIONS can tell what packages CMake has found.

CMake: how to install only shared libraries found via find_library?

I've got several third-party libs, some them shared, some static, I need to install the shared ones.
Currently I'm doing find_library's, have a list of all the needed libs and pass it to install(FILES ...).
But this way both .a and .so libs are installed.
With install(TARGETS ...) there is a separation on RUNTIME, ARCHIVE etc.
But I do not want to create a dummy target for each of the libs.
I also do not want to separate libs into shared and static (there is another separation already).
Is there a nicer way for me to filter for shared libs only than just to regex the filename? Maybe libraries are treated as something 'more' than just filepaths after find_library so I somehow can get library type from them?
Let's see what is going on.
You install some libraries via you package manager (yum/dnf/apt-get/sth else).
You build your app.
You distribute your app.
If so, you should not ask cmake to install those libs, because if someone else would like to install same thirdparty libs via another rpm package, it would create conflict (and one package would have to be removed) - it's mess.
The place which manage library dependecies is package manager - create rpm package which would have:
Requires: all_your_dynamic_libs
BuildRequires: all_your_static_libs
If point 1 is rather - You install some libraries by make && make install then you should firstly create rpm package for that.
It is kind of a pain to create all this additional work, but trust me, you DO NOT want to create all-in-one package.

What is the CMake install time?

A quote from the official documentation:
"Specify rules to run at install time."
What exactly is install time?
The problem for me: I am on Linux, software is installed from packages that are just dependencies and data. There is no CMake that can do anything here. So installation time of software is out of scope from CMake. So what exactly do they mean?
Building a CMake project can roughly be divided into three phases:
Configure time. This includes everything that happens while running cmake itself. This phase is concerned with inspecting certain properties of the host system and generating the specific build files for that platform under the selected configuration.
Build time. This includes everything that happens while actually building your project from the files generated by CMake (like, when running cmake --build or make). This is where all of the actual compilation and linking happens, so at the end of the build phase, you have a usable binary.
Install time. This includes everything that happens when running the INSTALL target generated by CMake (like, when running cmake --build --target install or make install). This takes care of copying the binaries that were generated into the build tree to a different directory. Note that the build tree contains a lot of stuff that is no longer needed once the build is completed if you are only interested in running the binary. Examples include all intermediate build artifacts, like the build files generated during the configure phase or the intermediate object files created during the build phase. Furthermore, the install phase might include additional steps to ensure that the binaries produced during the build are portable. For instance, on Linux systems you might want to remove the build directory from the shared library search path in the binary and replace it with a portable equivalent. So the install phase might do more than just copy all the important files to a new directory. It could also include additional steps that change the binaries to make them more portable.
Note that the last phase is optional. If you do not want to support calling make install but prefer another deployment mechanism, you simply don't use the install command in your CMake script and no INSTALL target will be generated.
I'd like to expand the answer, which ComicSansMS gave you, a little bit.
As he mentioned - CMake generates an extra target called install for the make tool (when you use a Makefile-based generator).
It may look weird for you as a package system is used for Linux. However the install target is still useful or even necessary:
When you develop your application you may need to install (move binaries and possibly some include files) to a certain location so some of your projects may see each other. For example, you may develop a library and a set of non-related applications which use it. Then this library must be installed somewhere to be visible. It doesn't mean you need to put it to the /usr directory; you may use your /home.
The process of Linux package preparation requires an install step. For example, the RPM packaging system does three main steps when the rpm package file is being built: the project is configured, then is compiled and linked and finally is being installed to a certain location. All files from this location are being packed to the rpm file.