Make Rodos installable with CMake
This MR adds install rules to the CMakeLists files of Rodos for those users who, for whatever reason, do not want to add Rodos as a submodule/folder. The installation procedure is customizable to hopefully cover the most common scenarios. I will first explain the intended usage and then some implementation details.
Intended usage
As an example the following instructions show how to install and use Rodos when targeting a host machine suitable for the linux-x86
port and when cross-compiling with the discovery_f429
toolchain file.
Install Rodos for the host machine
Runnning
cmake --toolchain cmake/port/linux-x86.cmake -S . -B build
cmake --build build
sudo cmake --install build
in the Rodos root directory configures, builds and installs Rodos to the default install location on the host machine. On Linux this means that the header files are found in /usr/local/include/rodos
and the path to the static library is /urs/local/lib/rodos/librodos.a
. The CMakeLists.txt
of the user application only needs to add the following two lines:
find_package(rodos REQUIRED 0.1.0)
target_link_libraries(<target> PRIVATE rodos::rodos)
The version number (0.1.0
) is optional.
Install Rodos for cross-compilation targets
In this case we usually create a folder for the target environment and we want to install Rodos (and all other libraries) there. We do this by specifying an install prefix.
cmake --toolchain cmake/port/discovery_f429.cmake -S . -B build
cmake --build build
sudo cmake --install build --prefix <prefix>
The header files are now in <prefix>/include/rodos
and the path to the library is <prefix>/lib/rodos/librodos.a
. The install prefix could, e.g., be /usr/local/stm32
. The CMakeLists.txt
of the application looks exactly the same as before but we must tell CMake that the find_*()
commands should search in a different directory now so we specify the CMAKE_FIND_ROOT_PATH
.
cmake --toolchain <prefix>/src/rodos/cmake/port/discovery_f429.cmake -DCMAKE_FIND_ROOT_PATH=<prefix> -S . -B build
To install different versions of Rodos even in the same target environment (= with the same install prefix) the option USE_PORT_SUFFIX
can be used.
cmake --toolchain cmake/port/discovery_f429.cmake -DUSE_PORT_SUFFIX=ON -S . -B build
cmake --build build
sudo cmake --install build --prefix <prefix>
It appends the name of the toolchain file (without the extension) to the name of the installed package. This means that the path to the Rodos library is now <prefix>/lib/rodos_discovery_f429/librodos.a
. The location of the header files does not change allowing them to be shared between different installations. The find_package()
call in the CMakeLists.txt
of the application must now exactly match with the port of the rodos library that should be used.
find_package(rodos_discovery_f429 REQUIRED 0.1.0)
# or, e.g.,
# find_package(rodos_linux-x86 REQUIRED 0.1.0)
target_link_libraries(<target> PRIVATE rodos::rodos)
Uninstalling
Unfortunately there is no built-in support for uninstalling targets with CMake so this whole thing is a bit of a hack. There are two custom build targets to uninstall Rodos: uninstall
and uninstall-all
. The first one uses install_manifest.txt
which is automatically generated by make, located in the build folder and contains a list of all installed files. Running
cmake --build build --target uninstall
deletes all the files in that list. Directories created by the installation are, however, not deleted. Running
cmake --build build --target uninstall-all
deletes the folders <prefix>/lib/rodos[_<port_suffix>]
, <prefix>/include/rodos
and <prefix>/src/rodos
and everything therein (rm -r
).
Whichever target was chosen for uninstalling remember that the header files are shared between Rodos ports with the same install prefix. If multiple ports were installed with the same prefix and one is uninstalled, the other ports have to be installed again to get the header files back. This is not nice but It Works™.
Implementation details
Most of the implementation is in new files, but I also changed some existing CMake code. Since at first I did not consider creating an MR there are some "unnecessary" changes due to personal preference and style in this implementation. I am happy to adapt or even revert those. The only change of existing code that is really necessary is that the target include directories must be explicitly specified only for the BUILD_INTERFACE
since full paths are used for these and they are different in the build and install tree. The rest is optional although two more changes would be particularly nice to have/keep:
-
The
directories_to_include
set in some of the ports are now relative to the root directory. This makes specifying the include directories in the install tree much easier. -
The library target was renamed from
rodos
torodos_rodos
and the aliasrodos::rodos
was added. I know that this is a breaking change but I did this because it is a best practice for CMake. The double colon prevents CMake from interpreting an incorrectly spelled target name as a library name that could be linked with-l<library_name>
. Thus typos are found easier and earlier. Since the exported target is also calledrodos::rodos
the user does not need to care if Rodos is added viafind_package()
oradd_subdirectory()
. They can always writetarget_link_libraries(<target> PRIVATE rodos::rodos)
.I can revert the target name but maybe an additional alias called
rodos
is enough for backwards compatibility.