robotology / yarp

YARP - Yet Another Robot Platform
http://www.yarp.it
Other
531 stars 195 forks source link

path.d folder should NOT be searched using ResourceFinder #522

Open drdanz opened 9 years ago

drdanz commented 9 years ago

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

drdanz commented 9 years ago

Also the path.d folder should be used ONLY if yarp is installed, not from the build directory

drdanz commented 9 years ago

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;
    }
}
drdanz commented 8 years ago

The code above:

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

francesco-romano commented 8 years ago

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
drdanz commented 8 years ago

@francesco-romano Awesome, thanks! just for information, is there a difference between #include and #import on macOS?

francesco-romano commented 8 years ago

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

drdanz commented 8 years ago

No problem, I updated the gist above, it should now work both for linux and macos...

traversaro commented 7 years ago

cc @diegoferigo is probably also interested in this.

drdanz commented 6 years ago

It would be nice if we could get this in YARP 3.0

traversaro commented 10 months ago

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 .