The rpath library is used to automate the retrieval of runtime resources required by some code, like text files, folders or images, but also path to runtime libraries and executable. The basic idea is to avoid boring the user with the fastidious task of passing absolute path using for instance program arguments. Each component (library, application, test) is then able to define which file it needs and, depending on where the component lies in filesystem, the path to the resource is automatically deduced.
Declaring runtime resources for a component
Let suppose the component my-component needs to resolve path to a folder named my_component_files containing log files. First thing to do is to declare the runtime resources it needs:
PID_Component(my-component RUNTIME_RESOURCES my_component_files)The folder my_component_files must be in the share/resources folder of the package defining my-component.
That’s it, anytime my-component is used, the rpath library will be able to find the path to my_component_files in the filesystem.
Resolving path to runtime resources
Of course most of time the component itself wants to use the runtime resources internally. To do so it needs to use the rpath library.let’s change a bit the description to tell it to use the rpath library:
PID_Component( my-component
DEPEND pid/rpath
RUNTIME_RESOURCES my_component_files)And in the source code of the component:
#include <pid/rpath.h>
...
void my_func(){
std::string path_to_folder = PID_PATH("my_component_files");
std::string path_to_file = PID_PATH("my_component_files/configuration.yaml");
...
}To use the rpath lirbary we include its global header pid/rpath.h. The we can use the PID_PATH macro provided by the library to find the path to the runtime resource.
In the previous example:
- first we get the path to the folder
my_component_files. - second we get the path to a specific file
configuration.yamlinto the folder.
If the path used are unknown (because either you do not have created them in project share/resources folder or you did not declare them as runtime resources of the component) the system will generate an exception. So for instance, the file configuration.yaml must have been writen by user in the share/resources/my_component_files folder of the containing package.
Sometimes, you may want to create files or folders (basically log files), so we need a way to say to the system to create the path even if not existing, withotu generating an exception. This is achieved this way:
#include <pid/rpath.h>
...
void my_func(){
...
std::string path_to_file_to_create = PID_PATH("+my_component_files/logs.txt");
}This way the system will only check that the file may exist: it checks if the resource has been declared as a direct runtime resource by the component my-component or that it is contained in a folder that is a runtime resource of this component (which is the case in the example). In this case the system does not check for the existence of the finally targetted resource in the filesystem.
Using runtime resources
The PID_PATH macro gives you the absolute path to the targetted runtime resources, nothing more. This is garanteed to work properly wherever your code is installed in a pid workspace. This way in the end you do not have to bother anymore to find what path must be given to your code.
If your code has been installed in a system folder or a user defined folder outside of a pid workspace (using the wrokspace install command), then rpath library will not be able to resolve path automatically. To achieve this, your can set the environment variable RUNTIME_RESOURCE_PATH to the path to the root install folder (by default the value of CMAKE_INSTALL_PREFIX of the workspace which default on linux to something like /usr/local).
What your code will do from these resolved path is then up to you.
Remark on unsupported systems
Unix systems are supported (including macosx) but some of them have limited support, like Windows. When working with such systems there is no automatic configuration of path resolution mechnism, you must do this configuration by hand. To do this, you must call the PID_EXE macro at the really beginning of your executable entry point (i.e. the main function):
...
int main(int argc, char* argv[]){
PID_EXE(argv[0]);//do not forget to do that call on Windows !!
//from here PID_PATH will work as usual...
...
}Resolving path to modules and executables
If your code need to find path to executable component like dll or exe then, instead of declaring a runtime resource in CMake you just specify the dependency with the component:
PID_Component( my-component
DEPEND pid/rpath
other-package/exe
other-package/dll)Then in your code:
#include <pid/rpath.h>
...
void my_func(){
std::string path_to_exe = PID_PATH("#<other-package>exe");
std::string path_to_exe = PID_PATH("@<other-package>dll");
...
}Resolving the path use a specific syntax:
#or@modifiers are used to find respectively applications or modules.<>delimiters contain the name of the package that defines the component, in the exampleother-package.