# Where can a project install its CMake modules

**URL:** https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304
**Category:** Code
**Created:** [November 13, 2025, 1:43pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304 "2025-11-13T13:43:55Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)
#### Post date: [November 13, 2025, 1:43pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/1 "2025-11-13T13:43:56Z")

</div>

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?

---

<div class="post-metadata">

### Author: ![retif](https://discourse.cmake.org/user_avatar/discourse.cmake.org/retif/32/1776_2.png) [@retif](https://discourse.cmake.org/u/retif)
#### Post date: [November 13, 2025, 3:20pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/2 "2025-11-13T15:20:37Z")

</div>

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:

```sh
├── 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.

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [November 13, 2025, 3:40pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/3 "2025-11-13T15:40:41Z")

</div>

I’d just make a package. If you want users to then include things piece-by-piece, offer a variable for where they live:

```cmake
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.

---

<div class="post-metadata">

### Author: ![starball](https://discourse.cmake.org/user_avatar/discourse.cmake.org/starball/32/3437_2.png) [@starball](https://discourse.cmake.org/u/starball)
#### Post date: [November 19, 2025, 5:04am UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/4 "2025-11-19T05:04:51Z")

</div>

Related?: [Where should I install C++ module interfaces units?](https://stackoverflow.com/q/78064048/11107541)

---

<div class="post-metadata">

### Author: ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)
#### Post date: [November 19, 2025, 12:10pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/5 "2025-11-19T12:10:08Z")

</div>

@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.

---

<div class="post-metadata">

### Author: ![anon74639460](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/da6949/32.png) [@anon74639460](https://discourse.cmake.org/u/anon74639460)
#### Post date: [November 20, 2025, 9:26am UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/6 "2025-11-20T09:26:16Z")

</div>

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.

> <https://github.com/RolandHughes/ls-cs/blob/master/build-LsCs-deb.sh>

Adding insult to injury, the original CopperSpice library had generated hard coded paths inside their own cmake files that weren’t RPM compatible.

> <https://github.com/RolandHughes/ls-cs/blob/master/LsCs.spec.in>

For Debian and RPM based distros scroll down to line 98 in this file

> <https://github.com/RolandHughes/ls-cs/blob/master/CMakeLists.txt>

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

- Arm8
- Arm8/include
- Arm8/lib/cmake

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.

> **[4 Bit MCUs, Still Alive and Kicking?](https://www.embeddedrelated.com/showthread/comp.arch.embedded/276253-1.php)**
>
> I'm not sure which group it was in, but someone who designs toys talked about the extremes they would go to for cost reduction, removing...

---

<div class="post-metadata">

### Author: ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)
#### Post date: [November 20, 2025, 3:51pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/7 "2025-11-20T15:51:35Z")

</div>

@anon74639460

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.

---

<div class="post-metadata">

### Author: ![anon74639460](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/da6949/32.png) [@anon74639460](https://discourse.cmake.org/u/anon74639460)
#### Post date: [November 20, 2025, 4:19pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/8 "2025-11-20T16:19:51Z")

</div>

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:

- YourCoolLibrary which requires a hack to CMAKE\_MODULE\_PATH
- YourCoolSerialLibrary because his application communicates with medical devices, another hack to CMAKE\_MODULE\_PATH
- YourCoolDatabaseLibrary because he needs to use YourCoolRelationalDatabase, another hack to CMAKE\_MODULE\_PATH
- YourCoolXMLLibrary because it has to transfer some data to disparate systems another hack to CMAKE\_MODULE\_PATH
- YourCoolEncryptionLibrary because XML is visciously unsafe in the open and so is libssl, another hack to CMAKE\_MODULE\_PATH

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:

1. Text editor
2. Build in batch
3. Test on target

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.

> <https://github.com/RolandHughes/ls-cs/blob/master/deb_build.etc/control.in>

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.

---

<div class="post-metadata">

### Author: ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)
#### Post date: [November 22, 2025, 6:45pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/9 "2025-11-22T18:45:22Z")

</div>

@anon74639460

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.

---

<div class="post-metadata">

### Author: ![anon74639460](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/da6949/32.png) [@anon74639460](https://discourse.cmake.org/u/anon74639460)
#### Post date: [November 22, 2025, 7:07pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/10 "2025-11-22T19:07:51Z")

</div>

Take a very close look at [LsCs](https://github.com/RolandHughes/ls-cs). 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.

> <https://github.com/RolandHughes/ls-cs/blob/master/cmake/LsCsDeploy.cmake>

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.

> [@Including a .cmake file](https://discourse.cmake.org/t/including-a-cmake-file/7034/6):
>
> Dear Craig: THanks for your quick reaction. I was specifically confused about chapter 34.2 (13th edition), where the example includes the line: list(APPEND CMAKE\_MODULE\_PATH ${CMAKE\_CURRENT\_LIST\_DIR}/cmake) and then loads a module with include(dependencies.cmake). Since that is the only module loaded in the example, I concluded that it would reside in the cmake subdirectory (since otherwise above line would be superfluous). Anyhow, your response clarifies- thanks!

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.

---

<div class="post-metadata">

### Author: ![leha-bot](https://discourse.cmake.org/user_avatar/discourse.cmake.org/leha-bot/32/921_2.png) [@leha-bot](https://discourse.cmake.org/u/leha-bot)
#### Post date: [July 13, 2026, 8:15am UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/11 "2026-07-13T08:15:36Z")

</div>

There is a similar issue about this thread: [https://gitlab.kitware.com/cmake/cmake/-/work\_items/27898](https://gitlab.kitware.com/cmake/cmake/-/work_items/27898)

---

<div class="post-metadata">

### Author: ![vito.gamberini](https://discourse.cmake.org/user_avatar/discourse.cmake.org/vito.gamberini/32/4376_2.png) [@vito.gamberini](https://discourse.cmake.org/u/vito.gamberini)
#### Post date: [July 13, 2026, 2:23pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/12 "2026-07-13T14:23:22Z")

</div>

No, that’s about C++ modules. This thread is about CMake modules. Completely different things.

---

<div class="post-metadata">

### Author: ![petk](https://discourse.cmake.org/user_avatar/discourse.cmake.org/petk/32/4555_2.png) [@petk](https://discourse.cmake.org/u/petk)
#### Post date: [July 13, 2026, 7:05pm UTC](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304/13 "2026-07-13T19:05:55Z")

</div>

Yes, this topic is about CMake utility and find modules (\*.cmake files).

For the sake of completeness, I’m also linking another blocker here because CMake projects can’t really use such CMake modules yet future-wise (for CPS installations):

> [@Where can a project install its CMake modules when using CPS](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules-when-using-cps/15515):
>
> This is a follow-up question to [Where can a project install its CMake modules](https://discourse.cmake.org/t/where-can-a-project-install-its-cmake-modules/15304) To briefly describe the issue again: Main project provides CMake modules and configuration that extensions (built as separate projects) need to use. When using package config file(s) this works ok I think and projects then need to find the main package and adjust the CMAKE\_MODULE\_PATH to have access to main project’s CMake modules. What about when a project installs CPS? Where and how could this be then resolved? Is…

(CPS currently doesn’t provide any data placeholders to get some path on the system).
