cmake: package config for installing arbitrary file dependencies for a target - cmake

I am creating a cmake package config file (a Foo-config.cmake) for a pre-existing .dll not created by cmake.
The annoying thing is that the .dll depends on some data files.
When a user consumes my package in his own cmake project, I want the INSTALL target to install both the .dll and data files to his specified install location. I don't want him to have to write extra install() rules to do that.
Is it good practice to write the install() rules directly in my Foo-config.cmake? Or is there a better way to do this, maybe with set_target_properties()? I just couldn't find the appropriate property for associating arbitrary file dependencies to a target.
In an alternate universe where this .dll didn't already exist and I had to create it myself using cmake, would I need to create a custom Foo-config.cmake, or is there something in cmake that can automatically generate it for me to achieve the same thing?
FWIW the .dll is an internal legacy library and is normally built by Visual Studio and uploaded in a .zip file to our internal artifactory. I want us to migrate away from manually pulling down .zip files from artifactory and manually integrating the files into Visual Studio projects.

I've since found that there are a couple different ways to do this:
In the config file, simply create one or more variables for the files/dirs you want to install. Then install those using install(FILES) and/or install(DIRECTORY). More info: https://stackoverflow.com/a/46361538/189341
Use file(GET_RUNTIME_DEPENDENCIES). More info:
https://discourse.cmake.org/t/installing-a-pre-built-module-and-its-various-dependencies/5227
How to use cmake file( GET_RUNTIME_DEPENDENCIES in an install statement?

Is it good practice to write the install() rules directly in my Foo-config.cmake?
No.
From 480 *-config.cmake and *Config.cmake files on my system none calls install().
Or is there a better way to do this, maybe with set_target_properties()?
No.
In an alternate universe where this .dll didn't already exist and I had to create it myself using cmake, would I need to create a custom Foo-config.cmake
No. This is unrelated to if you create a .dll or not. If .dll exists, there is no need to create Foo-config.cmake anyway. It is your choice that you want to (or make users to) use find_package.
is there something in cmake that can automatically generate it for me
No.
If you don't intent to support find_package features - VERSION OPTIONAL_COMPONENTS PATHS HINTS CONFIGS etc. - then just go with include(). find_package is just include() with some extra options.
If you want to have install() in your find_package, then just protect it with a variable, like if (FOO_DO_INSTALL) install(....) endif().

Related

Install files using symbolic links with CMAKE

I have converted my project to use cmake. During development I'd like to be able to install the product not the normal way, but let (notably) the installed data files be symbolic links to the source tree.
The project is SWI-Prolog which provides functionality to directly navigate and edit source files. If I use this to extend and fix the system libraries however I'm editing the installed copy that I then need to copy back to the sources before I can commit.
I know I can override functions in cmake, but in this case we are dealing with cmake code that is generated.

Optional in-tree builds for dependencies

I have an existing codebase where a number of third-party dependencies were added as Git submodules, and their directories are directly referenced inside CMakeLists.txt, as in include_directories(../external/foo).
Some of the dependencies are large projects, like FFmpeg, and I'd rather just use the version I installed to my system with a package manager. But the maintainer of the codebase wants to be able to continue using the in-tree dependencies.
I thought a compromise would be to configure CMake to permit both, either using an installed package, or using the in-tree submodules. I think find_package can be used to find the installed package, but is there a good way to implement this behavior that isn't too hacky?
You can add an option to your cmake file that allows the user to switch between the internal FFMpeg or the system one. option(INTREE_FFMPEG "Use the intree ffmpeg" ON). The option can be set either via the cmake-gui or as a command line switch.

Where to install FindLib.cmake

I'm creating a library (called fmi2) which I intend to install on my local machine (via a package manager) and then link to with a bunch of other libraries.
I'll be providing a Findfmi2.cmake file so that I can call find_package(fmi2) from my other libraries, but where should this file be conventionally installed?
Here are some choices I've considered and their problems:
/usr/share/cmake-3.8/Modules/Findfmi2.cmake
Advantage: find_package(fmi2) will just work
Disadvantage: Only works for one version of cmake
/usr/share/cmake/Modules/Findfmi2.cmake
Advantage: Should work for any version of cmake
Disadvantage: This is not a default folder. We would need to add set(CMAKE_MODULES_PATH /usr/share/cmake/Modules) and this kills any portability.
${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findfmi2.cmake
Advantage: Portable, just need to add set(CMAKE_MODULES_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
Disadvantage: Not system-wide. Need to manually add this file to each library that uses it. This duplicates files in my framework.
You are authoring content in CMake. You don't need a FindModule. That is designed to find external non-CMake outputs.
This Stackoverflow post from ruslo should help you understand the difference between find_package() module mode and config mode. It also answers your question about paths for FindModules, i.e. they are copied into your CMake project, not discovered system-wide, unless they are part of the official FindModules bundled with CMake in the "Modules" directory.
Modern CMake documentation now finally contains good examples to create a config mode package: cmake-packages
If you want explicit full examples, though using slightly older syntax for the config.cmake files, ruslo has more on Github.

FindGLM.cmake not in glm 0.9.7, is it a deprecated way to find libraries in CMAKE?

So looking through the newest release of GLM 0.9.7, I dont see a FindGLM.cmake file anywhere, used to easily include GLM in CMAKE. I could always use an old version of it found online but the following commit had me stumped:
https://github.com/g-truc/glm/commit/62a7daddcf082f754000fc5e42d7bcdf93c895f7
Commit message is "Removed obsolete FindGLM". So, did the developer just dump it or are there in fact a new way to find libraries in CMAKE?
Yes, CMake Find modules (FindXyz.cmake files) are deprecated in favour of Package Config files (usually named XyzConfig.cmake). The original philosophy is that Find modules are shipped and maintained by CMake, while Package Config files are shipped and maintained by the package they are intended to find.
CMake's find_package command actually has two modes: Module mode (legacy, using Find modules) and Config mode (preferred, using Package Config files).
For the client consuming the package, little should change (unless more customisation is desired, which is offered by the Config mode of find_package).
Notice that the very commit to which you linked not only drops FindGLM.cmake, but also adds a glmConfig.cmake file.

How to add custom content to a CMake project?

We recently started switching over from using plain visual studio projects to using proper CMake files. Previously we would have the "Content" folder in the solution root folder to allow our executables to access content from it using a relative path like "../Tiles/tileset1.png".
How could we make sure CMake copies the files correctly, or in some other way makes sure that our executables are able to find the content folder while debugging from Visual Studio without manually setting the working directory?
I can think of a few different options:
Have CMake put all your executables in the same folder, as described in this question. Then you can use ../Tiles or ../../Tiles or whatever as you've been doing. Note, however, that you might want to consider setting this on a per-target basis instead of globally, e.g., using:
set_target_properties(
my_target
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/bin
)
Setting CMAKE_RUNTIME_OUTPUT_DIRECTORY works fine, but some people consider it to be the 'old' way of doing it. (Depending on your needs, you might also want to set LIBRARY_OUTPUT_DIRECTORY, and possibly ARCHIVE_OUTPUT_DIRECTORY.)
Use an environmental variable (e.g., CONTENT_ROOT or some-such) to locate the resources. Hard-code a default that makes sense for production, but let developers override it for their particular work flow.
Look into cross-platform resource libaries (something like Qt's QRC files, but perhaps not tied to Qt).
Try the CMake modules listed in this FAQ answer to change Visual Studio's working/debugging directory.
Actually, a combination of 1 and 2 is probably your best bet...