Open drdanz opened 9 years ago
Also the path.d folder should be used ONLY if yarp is installed, not from the build directory
Locating the position of the libYARP_OS library could be a way to locate the path.d folder without hard coding the path inside.
This small test detects the path of the linked libYARP_OS.so
library on linux and uses it to generate the name path.d of the directory. Original example taken from here.
I don't know yet if it could be adapted for windows and mac, perhaps using ACE.
CMAKE_LIBRARY_DIR
and CMAKE_INSTALL_DATADIR
are relative paths and could be exported from CMake.
In this way the executable will not contain hard coded paths and can be relocated without issues.
This will not avoid that the path.d folder is located in the build directory, but I think we can live with that.
#include <yarp/os/Network.h>
#include <link.h>
#include <string>
#define CMAKE_LIBRARY_DIR "lib"
#define CMAKE_INSTALL_DATADIR "share"
#define PATH_D "/yarp/config/path.d"
int main(int argc, char *argv[])
{
yarp::os::Network yarp;
struct unknown_struct
{
void* pointers[3];
struct unknown_struct* ptr;
};
void* handle = dlopen(NULL, RTLD_NOW);
unknown_struct* p = reinterpret_cast<unknown_struct*>(handle)->ptr;
link_map* map = reinterpret_cast<link_map*>(p->ptr);
while (map) {
std::string name = map->l_name;
size_t pos = name.find(CMAKE_LIBRARY_DIR "/libYARP_OS.so");
// do something with |map| like with handle, returned by |dlopen()|.
if (pos != std::string::npos) {
std::string path = name.substr(0, pos);
std::string path_d = path + CMAKE_INSTALL_DATADIR + PATH_D;
std::cout << path_d << std::endl;
break;
}
map = map->l_next;
}
}
The code above:
.so
to .dylib
is enough?)I copied the code in a gist and added a CMakeLists.txt so that it is easier to test: https://gist.github.com/drdanz/d5fb1d85ffdb9122692c36715e2b3e53
Regarding macOS
this stack overflow issue can help solving the problem on macOS.
I adapted the code for our limited use.
The following code
#include <mach-o/dyld.h>
#include <string>
#include <iostream>
#define CMAKE_LIBRARY_DIR "lib"
#define CMAKE_INSTALL_DATADIR "share"
#define PATH_D "/yarp/config/path.d"
int main(int argc, char *argv[])
{
for (uint32_t count = 0; count < _dyld_image_count(); ++count) {
std::string name = _dyld_get_image_name(count);
size_t pos = name.find(CMAKE_LIBRARY_DIR "/libYARP_OS.");
// do something with |map| like with handle, returned by |dlopen()|.
if (pos != std::string::npos) {
std::string path = name.substr(0, pos);
std::string path_d = path + CMAKE_INSTALL_DATADIR + PATH_D;
std::cout << path_d << std::endl;
break;
}
}
}
Outputs:
/Users/makaveli/Projects/src/local/share/yarp/config/path.d
@francesco-romano Awesome, thanks! just for information, is there a difference between #include
and #import
on macOS?
@drdanz ops sorry. I modified the snippet.
Yes, #import
is like #include
but it checks that the file is included only once. Of course is something related to Objective C extensions, and it is probably not portable.
No problem, I updated the gist above, it should now work both for linux and macos...
cc @diegoferigo is probably also interested in this.
It would be nice if we could get this in YARP 3.0
A variant of what was proposed here that work on Linux, macOS and Windows natively is implemented in reloc-cpp. The trick there is to use dladdr
on Linux/macOS and GetModuleFileNameA
on Windows to get the location of the shared library. The related C++ code is in https://github.com/ami-iit/reloc-cpp/blob/57cb7fadbda5282eb4931329ddda6a6fa458916c/RelocCPPGenerate.cmake#L128-L156 .
Resource finder looks for the path.d folder using the YARP_DATA_DIRS variable that, if not set, uses the XDG_DATA_DIRS variable, that defaults in /usr/local/share/:/usr/share/. This means that if the user has a folder in /usr/local/share/yarp/path.d from some old installation and YARP and iCub are installed using the packages (therefore in /usr), YARP will see the wrong path.d folder and therefore will not be able to locate iCub files.
The right behaviour is to use only the path.d folder in the executable prefix (in this case /usr/share/yarp/path.d
CC @mbrunettini