# Get the final install prefix at install-time

**URL:** <https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357>\
**Category:** Code\
**Created:** [December 12, 2020, 2:01pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357 "2020-12-12T14:01:10Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)\
**Post date:** [December 12, 2020, 2:01pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/1 "2020-12-12T14:01:10Z")

</div>

Hi,  
I’m working on a C library project that provides some examples.  
The examples are contained in a self contained subproject, and can be built from both the top library project (as normal executable targets) or installed as a component.

When installed, the subproject itself gets copied, not the binaries. It can detect it’s not a subproject anymore, and switches to `find_package()` (config mode) to find the library.

I’d like to make things fancier, and dynamically add the library install prefix to the installed `find_package()`'s `PATHS`, so that no matter where the library project is installed, if the examples component is enabled, they’ll be able to find the library config file.

Now, I know that in this case, the `CMAKE_INSTALL_PREFIX` variable, and `$<INSTALL_PREFIX` gen exp, are of no use here. Configuration and generation phases are already over when it’s time to install.

Since the install target depends on `ALL`, what would be needed is a build time command with access to build time-only data. That’s not possible.

Maybe a `install(CODE`/`SCRIPT`?  
For example, the `cmake --install <dir>` cli command let’s the user specify a base install dir. Is that path stored somewhere an install script can read?

---

<div class="post-metadata">

**Author:** ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)\
**Post date:** [December 12, 2020, 9:50pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/2 "2020-12-12T21:50:50Z")

</div>

I took some time to test everything out, `CMAKE_INSTALL_PREFIX` was correctly set to the final value in “install script mode” (`install(CODE`).  
Project-specific install paths, defined by GNUInstallDirs in the library project, are not available in install script mode. That’s understandable, so I put them directly in the script with variable interpolation.

The complete snippet looks like this

```auto
# include(GNUInstallDirs) in root CMakeLists.txt
set(examples_install_dir "${CMAKE_INSTALL_DATADIR}/VTExamples")
string(JOIN "\n" install_script
       "set(examples_install_dir \"${examples_install_dir}\")"
       "set(module_path \"${CMAKE_CURRENT_LIST_DIR}/installed.cmake.in\")"
       [[
set(visualt_install_path ${CMAKE_INSTALL_PREFIX})
set(configured_module_output "${visualt_install_path}/${examples_install_dir}/cmake/interface.cmake")
message(STATUS "Installing: ${configured_module_output}")
message(STATUS "VisualT: installed examples will include \"${visualt_install_path}\" as a package search path")
configure_file(${module_path}
               ${configured_module_output}
               @ONLY)
]])
install(CODE "${install_script}"
        COMPONENT VisualT_examples
        EXCLUDE_FROM_ALL)

```

The `installed.cmake.in` module gets installed as `interface.cmake` where it’s `included` by the installed examples subproject.

Where can I find a more complete description of what’s available in “install script mode”?  
And main differences between standard script mode and install script mode.  
For example, I don’t expect `CMAKE_INSTALL_PREFIX` to be defined in script mode… I don’t know.

I also noticed that the output gets breaks when installing in windows, using windows-style paths.

```auto
PS D:\Users\Nemo\OneDrive-shared\c\VisualT\cmake-build-debug-win> cmake --install . --component VisualT_examples --prefix "D:\Users\Nemo\Desktop\VisualT" --config Debug
-- Installing: D:\Users\Nemo\Desktop\VisualT/share/VTExamples

```

The installation process still works, but my `visualt_install_path` replaced with `configure_file` comes out incorrect. I fixed with a `file(TO_CMAKE_PATH ${visualt_install_path} visualt_install_path)` before the file configuration.

---

<div class="post-metadata">

**Author:** ![hex](https://discourse.cmake.org/user_avatar/discourse.cmake.org/hex/32/363_2.png) [@hex](https://discourse.cmake.org/u/hex)\
**Post date:** [December 14, 2020, 7:55pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/3 "2020-12-14T19:55:12Z")

</div>

@Artemis Your examples are a separate CMake project that you add with `External_Project_Add`? Is this intended or can you change this? You can have separate component installs for example as full installation or minimal installation. Would this be a cleaner solution?

The installation prefix is set at configure time, why can you not use this? When you find an installation i think you typically find it in your project or on common places like those used with `GNUInstallDirs`. So by “no matter where” you mean you want to accept a user input after the project has been build?

---

<div class="post-metadata">

**Author:** ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)\
**Post date:** [December 14, 2020, 8:49pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/4 "2020-12-14T20:49:02Z")

</div>

Hi @hex !  
The subproject containing the examples is included with a simple `add_subdirectory()`.  
It’s root `CMakeLists.txt` includes a module called `interface.cmake`.  
This module contains the code that defines the installation.  
When installing the examples subproject, the entire project source dir is copied. A new module called `interface.cmake` is installed in place of the old one. This new module contains the code that imports the installed library. This setup lets me write the example-specific cmake and completely ignore if the subproject is being used through the main library project or standalone, with the library installed.  
That said, the `CMAKE_INSTALL_PREFIX` is indeed set at configure time, but that’s just a default chosen by `GNUInstallDirs` or cmake itself. The actual install path can be specified, for example, in the `cmake --install` cli command. When you run that cli command, the configuration, generation and building phases are already done. I was wondering if it is visible at least to an install script.  
Turned out it is, and everything works. The question now is:

* * *

#### Where can I find a complete documentation of what’s available to cmake code ran in install script mode? And in standard script mode (cmake -P)? And a comparison between the two?

Also, as a side note:

> [@Artemis](#):
>
> I also noticed that the output breaks when installing in windows, using windows-style paths.
> 
> ```auto
> PS D:\Users\Nemo\OneDrive-shared\c\VisualT\cmake-build-debug-win> cmake --install . --component VisualT_examples --prefix "D:\Users\Nemo\Desktop\VisualT" --config Debug
> -- Installing: D:\Users\Nemo\Desktop\VisualT/share/VTExamples
> 
> ```
> 
> The installation process still works, but my `visualt_install_path` replaced with `configure_file` comes out incorrect. I fixed with a `file(TO_CMAKE_PATH ${visualt_install_path} visualt_install_path)` before the file configuration.

---

<div class="post-metadata">

**Author:** ![McMartin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mcmartin/32/150_2.png) [@McMartin](https://discourse.cmake.org/u/McMartin)\
**Post date:** [December 14, 2020, 8:56pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/5 "2020-12-14T20:56:19Z")

</div>

You can run this script to list all available commands and variables:

```cmake
message(STATUS " ***All commands***")
get_cmake_property(all_commands COMMANDS)
foreach(command IN LISTS all_commands)
  message(STATUS "${command}")
endforeach()
message(STATUS " ********************")

message(STATUS " ***All variables***")
get_cmake_property(all_variables VARIABLES)
foreach(variable IN LISTS all_variables)
  message(STATUS "${variable}")
endforeach()
message(STATUS " *********************")

```

---

<div class="post-metadata">

**Author:** ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)\
**Post date:** [December 14, 2020, 9:28pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/6 "2020-12-14T21:28:29Z")

</div>

Oh!, very interesting, and that excludes automatically undefined variables like `PROJECT_SOURCE_DIR`, ecc, and unavailable commands, like `install()`in install script mode?

---

<div class="post-metadata">

**Author:** ![McMartin](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mcmartin/32/150_2.png) [@McMartin](https://discourse.cmake.org/u/McMartin)\
**Post date:** [December 15, 2020, 7:56am UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/7 "2020-12-15T07:56:03Z")

</div>

When running the first half of the script I shared previously, you’ll see that `install` is listed as one of the commands. That’s because all commands that are [“available only in CMake projects”](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#project-commands) are actually always defined, even in script mode. This allows CMake to fail with the following error message when calling them

```java
  <command> command is not scriptable

```

instead of the generic

```java
  Unknown CMake command "<command>".

```

The easiest way to know which commands are really available in script mode is to look at the documentation here: [https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#scripting-commands](https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html#scripting-commands)

---

<div class="post-metadata">

**Author:** ![Artemis](https://discourse.cmake.org/user_avatar/discourse.cmake.org/artemis/32/616_2.png) [@Artemis](https://discourse.cmake.org/u/Artemis)\
**Post date:** [December 15, 2020, 2:00pm UTC](https://discourse.cmake.org/t/get-the-final-install-prefix-at-install-time/2357/8 "2020-12-15T14:00:57Z")

</div>

That’s exactly what I was looking for 🙂  
It doesn’t appear in a “script mode” search, so I missed it. Maybe it could be useful to add a “see also” link in the [CMake language/scripts section](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html?highlight=script%20mode#scripts). Variables’ script mode behaviour is independently documented instead, but they link to each other so it’s fine.

I think there are still some related key information not mentioned by the docs.  
For example, as I mentioned before, I had no idea of what `CMAKE_INSTALL_PREFIX` could contain in install script mode. I had to take some time to make experiments. I was surprised that it contained system-specific directory separator. I was confused because cmake wasn’t having problems, and I didn’t know you could throw windows-style paths to commands without them breaking. And even if they don’t, using the variable to configure a file (see above) _causes_ errors.

`CMAKE_INSTALL_PREFIX` is just one example I came across, I would like to have a place to learn the nuances of install script mode in advance.
