If some project provides its own CMake modules, where would be the best place to install them on the system so other projects can simply use them via include() and find_package()?
Does CMake have any such additional path out of the box somehow?
If some project provides its own CMake modules, where would be the best place to install them on the system so other projects can simply use them via include() and find_package()?
Does CMake have any such additional path out of the box somehow?
I’d also be curios to know what is the best/common practice for this.
In our project we have our own CMake modules too, and we have been installing them into ${CMAKE_INSTALL_PREFIX}/share/OurPackage/modules/ as a part of a relocatable package, so the resulting folder structure is this:
├── debug
│ └── lib
│ └── [ ... debug binaries ... ]
├── include
│ └── our-package
│ └── [ ... public headers ... ]
├── lib
│ └── [ ... release binaries ... ]
└── share
└── OurPackage
├── modules # here are the modules
│ ├── some.cmake
│ ├── thing.cmake
│ └── another.cmake
├── OurPackageConfig.cmake
├── OurPackageConfigVersion.cmake
├── OurPackageTargets-debug.cmake
├── OurPackageTargets-release.cmake
└── OurPackageTargets.cmake
And then of course our users aside from providing path to our package in CMAKE_PREFIX_PATH (or in OurPackage_DIR) also need to add path to our modules (/path/to/our/package/prefix/share/OurPackage/modules) into their project’s CMAKE_MODULE_PATH.
Not sure if this is how it should be done, but it seems to be working fine so far.
I’d just make a package. If you want users to then include things piece-by-piece, offer a variable for where they live:
find_package(YourCoolPackage)
list(INSERT CMAKE_MODULE_PATH 0
${YourCoolPackage_CMAKE_MODULE_PATH})
include(YourCoolPackage_API)
Then you provide a YourCoolPackageConfig.cmake in its normal search locations (<prefix>/share/cmake/YourCoolPackage-1.0/YourCoolPackageConfig.cmake).
If piece-by-piece isn’t necessary, just include() the API bits in the package itself.
@starball Not quite. I was interested here about CMake utility and find modules only (*.cmake files such as GNUInstallDirs.cmake etc but those that are customly created by the project). C modules are sort of like libraries and a separate context, yes.
I know you have accepted an answer, but it is not cool. The answer is exactly how Linux distros became train wrecks. I had to go down this road several years ago.
Adding insult to injury, the original CopperSpice library had generated hard coded paths inside their own cmake files that weren’t RPM compatible.
For Debian and RPM based distros scroll down to line 98 in this file
When you are building a .deb package you are building and installing into a “Debian tree” to mimic the package. Basically doing a BUILDROOT.
With RPM you are doing RPMBUILD. Before the introduction of RPMBUILD, RPM packaging was the realm of black magic requiring blood sacrifice.
We can skip over the, now failed, experiment of lib64 in Debian trees. You can read up on it at line 43 in build-LsCs-deb.sh. The deadliest two words in all of IT are “for now.” As the home hobbyist computers moved from 16 to 32-bit far too many “for now” decisions were made. They were compounded when distros had to straddle both 32-bit and 64-bit home hobbyist chips. Then came ARM, Texas Instruments, and 32,767 other chip vendors for embedded systems and specialty devices like phones. A new set of “for now” decisions got made that weren’t really any smarter than the original “for now” decisions. In order to cross compile you have to have full library and cmake files underneath a distro specific taget architecture tree.
Before you think “I don’t have to worry about that”
If YourCoolLibrary is any good, it won’t be out there a month before whine about it not supporting Raspberry Pi.
Most/many/some of the distros have started rooting under architecture. I’m working from memory here in the wee hours of the morning and don’t want to go down the research rabbit hole.
Conceptually think
You generally don’t find share under the tree for cross compilation but you will always find include and lib. Header files can be different based on architecture. Many embedded processors don’t have the features you take for granted on your desktop. Let us also not forget that in the world of embedded development we can still have 4-bit CPU. They were very popular in television remote controls.
I see. If I understand correctly, what you’re describing is definitely an issue. But I would consider this a separate issue here (trying to separate concerns). Those hard-coded paths are a concern of how to create a relocatable software as a whole. So paths there work no matter the installation prefix selected at the installation phase (or in this case the packaging phase). CMake modules should ideally be completely relocatable. And mostly those paths can be generated at the module usage time later on. I think that putting custom project related CMake modules together with the config files is the way to go. Not ideal but it does work actually. User of the module then needs to only configure their CMAKE_MODULE_PATH after finding the package and has the custom modules available.
Feel free to do what you want. I spent about a year messaging back and forth with the people who put together the distros. Under whatever the install-root is, and whatever unfortunate name /lib may have you have MyCoolProject with the library files and /lib/cmake/MyCoolProject with all of the Cmake files. Everything else is viewed as non-standard path.
Again, this is a case of “for now” thinking.
Consider this:
Hapless Joe decides to write a be-all-end-all C++ application. He needs:
This becomes a real problem for the adoption of YourCoolLibrary. CMAKE_MODULE_PATH hacks become a maintenance nightmare. I mean, maybe in an IDE with training wheels like Visual Studio this doesn’t seem like a big deal, but I’ve been in IT 40+ years. Every production environment for every OS I’ve ever worked on, IBM Mainframe, DEC Midrange, OS/2, GUI-DOS (windows before NT), and the past decade or so creating software for medical devices as well as applications to control them, it’s all the same:
Please consider this:
Hapless Fred also creates YourCoolLibrary. Both of you install in non-standard locations. Package name is different but some/all of the object library files and cmake files have same name.
Neither Debian nor RPM package managers will stop that install from happening. If Hapless Joe installs it because he needs something it claims to have, and hey, the package name is different.
Now, in the Utopian world, where developers follow the distro install location standards, both Debian and RPM package managers will stop the install. One package cannot overwrite any part of another package.
Package becomes part of the .deb name, but it does not control directory names because Debian packages are mostly a zip file.
Finding out the distro default locations for things was a PITA. I humbly humbly humbly suggest you thieve the code from that packaging and follow it. Installation into non-standard locations opens YourCoolLibrary up to serious collisions and conflicts.
Just my 0.002 cents. Feel free to do what you wish.
I’d much prefer to avoid the CMAKE_MODULE_PATH change indeed and have something built-in that enables something like this. Also for the future where CPS-only ways will be used. But creating a larger project with extensions that should be buildable on their own using the “cmake” command leaves me no choice. There is too much repetitive code to write in every extension’s CMakeLists.txt file otherwise. Using such CMake modules helps big time to make the extension configurable in a relatively simple way. Otherwise, yes I totally agree that this shouldn’t be a practice to build some general library that requires using external CMake modules for its usage. For that there are other approaches - pkg-config, and the upcoming CPS.
Take a very close look at LsCs. It is a fork of CopperSpice which is a fork of Qt 4.8-ish. It dynamically configures what it builds based on what the system has. Lots of plugins. You probably also want to take a close look at the cmake directory. Probably this file in particular.
All of your “repetitive code” can go into “functions”, or at least most of it can. That which cannot can just be in a .cmake stub file that the other cmake files includes.
Every tragedy in IT will be repeated at least 3 different times on at least 3 different platforms if you live long enough.
During the days interpreted BASIC on PDP-11 and MAI BASIC/4 machines we were notorious for %INCLUDE of entire programs or just a range of line numbers from them. (God forbid somebody renumber the source!) Even more notorious, because it was billed as a safety feature, was writing programs that immediately exited. To get them to actually do anything you had to CHAIN to a specific line number.
Enter interpreted languages on PCs. Once again, it is the Wild Wild West!
If only the scripted languages had line numbers so we could play our cruelest games!
If you refactor your entire project around the concept of
“Write it once”
cutting anything replicated out into a common includable .cmake file, things should get cleaner for you.