Skip to content

Commit

Permalink
WIP Resources can be found in install tree based on libdrake.so location
Browse files Browse the repository at this point in the history
When an executable depends on `libdrake.so`, it can find the resources in the
install tree based on the location of `libdrake.so`. The implementation to
find `libdrake.so` is platform specific (MacOS and Linux). In both cases, it
finds the location of the library loaded in the process. It extracts its
directory and appends its with the relative path to the resource files.
This should limit the necessity of programmatically add path to the candidate
directory in which the sentinel file is searched.
  • Loading branch information
Francois Budin committed Nov 22, 2017
1 parent 8caca84 commit 6c1d6ce
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 47 deletions.
11 changes: 0 additions & 11 deletions drake/bindings/python/pydrake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,3 @@
# the data has also been installed).
path = dirname(__file__)
version = ".".join(python_version_tuple()[:2])
# In the install tree. pydrake Python module is in
# `lib/python2.7/site-packages/pydrake/` whereas the data is installed in
# `share/drake`. From the current file location, the data is 4 directories
# up. If pydrake is not in the expected directory, `path` is not added to the
# resource search path.
if path.endswith("lib/python" + version + "/site-packages/pydrake"):
common.AddResourceSearchPath(
realpath(join(path,
pardir, pardir, pardir, pardir,
"share/drake"))
)
1 change: 1 addition & 0 deletions drake/common/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ drake_cc_library(
data = [
DRAKE_RESOURCE_SENTINEL,
],
linkopts = ["-ldl"], # for libdrake.so path on linux
deps = [
":essential",
"@spruce",
Expand Down
125 changes: 123 additions & 2 deletions drake/common/find_resource.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@
#include <utility>
#include <vector>

#ifdef __APPLE__
#include <dlfcn.h>

#include <mach-o/dyld.h>
#include <mach-o/dyld_images.h>
#else // Not __APPLE__
#include <libgen.h>
#include <string.h>

#include <link.h>
#endif

#include <spruce.hh>

#include "drake/common/drake_throw.h"
Expand Down Expand Up @@ -174,6 +186,112 @@ std::vector<string>& GetMutableResourceSearchPaths() {
static never_destroyed<std::vector<string>> search_paths;
return search_paths.access();
}

#ifdef __APPLE__

// This code has been adapted from:
// https://stackoverflow.com/questions/4309117/determining-programmatically-what-modules-are-loaded-in-another-process-os-x/23229148#23229148

// Reads memory from MacOS specific structures into an `unsigned char*`.
unsigned char * readProcessMemory(mach_vm_address_t addr,
mach_msg_type_number_t* size) {
mach_msg_type_number_t dataCnt =
reinterpret_cast<mach_msg_type_number_t>(*size);
vm_offset_t readMem;

kern_return_t kr = vm_read(mach_task_self(), addr, *size,
&readMem, &dataCnt);
if (kr) {
return NULL;
}
return ( reinterpret_cast<unsigned char *>(readMem));
}

// Gets the list of all the dynamic libraries that have been loaded. Finds
// `libdrake.so` in the list, and returns its directory path appended
// with relative directory to find resource files in drake install tree.
// This function is specific to MacOS
optional<string> resource_path_from_libdrake() {
optional<string> binary_dirname;
struct task_dyld_info dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
// Getinformation from current process.
if (task_info(mach_task_self(), TASK_DYLD_INFO,
reinterpret_cast<task_info_t>(&dyld_info), &count) == KERN_SUCCESS) {
// Recover list of dynamic libraries.
mach_msg_type_number_t size = sizeof(struct dyld_all_image_infos);
uint8_t* data =
readProcessMemory(dyld_info.all_image_info_addr, &size);
if (!data) {
return binary_dirname;
}
struct dyld_all_image_infos* infos =
reinterpret_cast<struct dyld_all_image_infos *>(data);

// Recover number of dynamic libraries in list.
mach_msg_type_number_t size2 =
sizeof(struct dyld_image_info) * infos->infoArrayCount;
uint8_t* info_addr = readProcessMemory(
reinterpret_cast<mach_vm_address_t>(infos->infoArray), &size2);
if (!info_addr) {
return binary_dirname;
}
struct dyld_image_info* info =
reinterpret_cast<struct dyld_image_info*>(info_addr);

// Loop over the dynamic libraries until `libdrake.so` is found.
for (uint32_t i=0; i < infos->infoArrayCount; i++) {
const char * pos_slash = strrchr(info[i].imageFilePath, '/');
if (!strcmp(pos_slash + 1, "libdrake.so")) {
binary_dirname = string(info[i].imageFilePath,
pos_slash - info[i].imageFilePath) + "/../share/drake";
break;
}
}
}
return binary_dirname;
}
#else // Not __APPLE__

// This code has been adapted from:
// http://syprog.blogspot.ru/2011/12/listing-loaded-shared-objects-in-linux.html

// Chained list of shared objects
struct lmap {
void* base_address; // Base address of the shared object
char* path; // Absolute file name (path) of the shared object
void* not_needed; // Pointer to the dynamic section of the SO
struct lmap *next, *prev; // chain of loaded objects
};

// Content of that dlopen is saved in this structure.
struct something {
void* pointers[3];
struct something* ptr;
};

// Gets the list of all the shared objects that have been loaded. Finds
// `libdrake.so` in the list, and returns its directory path appended
// with relative directory to find resource files in drake install tree.
// This function is specific to Linux.
optional<string> resource_path_from_libdrake() {
optional<string> binary_dirname;
struct lmap* pl;
void* ph = dlopen(NULL, RTLD_NOW);
struct something* p = reinterpret_cast<struct something*>(ph);
p = p->ptr;
pl = reinterpret_cast<struct lmap*>(p->ptr);
// Loop over loaded shared objects until `libdrake.so` is found.
while (NULL != pl) {
if (!strcmp(basename(pl->path), "libdrake.so")) {
binary_dirname = string(dirname(pl->path)) + "/../share/drake";
break;
}
pl = pl->next;
}
return binary_dirname;
}
#endif
} // namespace

std::vector<string> GetResourceSearchPaths() {
Expand Down Expand Up @@ -217,8 +335,11 @@ Result FindResource(string resource_path) {
spruce::path candidate_dir(search_path);
candidate_dirs.emplace_back(check_candidate_dir(candidate_dir));
}

// (3) Search in cwd (and its parent, grandparent, etc.) to find Drake's
// (3) Find where `librake.so` is, and add search path that corresponds to
// resource folder in install tree based on `libdrake.so` location.
static optional<string> from_libdrake = resource_path_from_libdrake();
candidate_dirs.emplace_back(from_libdrake);
// (4) Search in cwd (and its parent, grandparent, etc.) to find Drake's
// resource-root sentinel file.
candidate_dirs.emplace_back(find_sentinel_dir());

Expand Down
44 changes: 12 additions & 32 deletions drake/examples/kuka_iiwa_arm/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -76,25 +76,24 @@ drake_cc_library(

drake_cc_binary(
name = "iiwa_controller",
srcs = ["iiwa_controller.cc"],
srcs = ["iiwa_controller.cc"] + ["//tools/install/libdrake:libdrake.so"],
data = [
":models",
"//drake/manipulation/models/iiwa_description:models",
],
deps = [
":iiwa_common",
":lcm_plan_interpolator",
"//drake/common:text_logging_gflags",
"//drake/lcm",
"//drake/systems/lcm",
"//drake/systems/lcm:lcm_driven_loop",
"//tools/install/libdrake:drake_shared_library",
"@com_github_gflags_gflags//:gflags",
],
)

drake_cc_binary(
name = "iiwa_wsg_simulation",
srcs = ["iiwa_wsg_simulation.cc"],
srcs = ["iiwa_wsg_simulation.cc"] + [
"//tools/install/libdrake:libdrake.so",
],
add_test_rule = 1,
data = [
":models",
Expand All @@ -108,27 +107,16 @@ drake_cc_binary(
":iiwa_common",
":iiwa_lcm",
":oracular_state_estimator",
"//drake/common:text_logging_gflags",
"//drake/examples/kuka_iiwa_arm/iiwa_world:iiwa_wsg_diagram_factory",
"//drake/lcm",
"//drake/manipulation/schunk_wsg:schunk_wsg_constants",
"//drake/manipulation/schunk_wsg:schunk_wsg_controller",
"//drake/manipulation/schunk_wsg:schunk_wsg_lcm",
"//drake/manipulation/util:world_sim_tree_builder",
"//drake/multibody/rigid_body_plant",
"//drake/systems/analysis",
"//drake/systems/controllers:inverse_dynamics_controller",
"//drake/systems/controllers:pid_controller",
"//drake/systems/primitives:constant_vector_source",
"//drake/systems/primitives:matrix_gain",
"//drake/util:lcm_util",
"//drake/lcmtypes:schunk", # lcm header files
"//tools/install/libdrake:drake_shared_library",
"@com_github_gflags_gflags//:gflags",
],
)

drake_cc_binary(
name = "kuka_simulation",
srcs = ["kuka_simulation.cc"],
srcs = ["kuka_simulation.cc"] + ["//tools/install/libdrake:libdrake.so"],
add_test_rule = 1,
data = [
":models",
Expand All @@ -140,31 +128,23 @@ drake_cc_binary(
deps = [
":iiwa_common",
":iiwa_lcm",
"//drake/common:find_resource",
"//drake/common:text_logging_gflags",
"//drake/lcm",
"//drake/manipulation/util:sim_diagram_builder",
"//drake/manipulation/util:world_sim_tree_builder",
"//drake/multibody/rigid_body_plant",
"//drake/multibody/rigid_body_plant:frame_visualizer",
"//drake/systems/analysis:simulator",
"//drake/systems/controllers:inverse_dynamics_controller",
"//drake/systems/primitives:constant_vector_source",
"//drake/lcmtypes:viewer", # lcm header files
"//tools/install/libdrake:drake_shared_library",
"@com_github_gflags_gflags//:gflags",
],
)

drake_cc_binary(
name = "kuka_plan_runner",
srcs = ["kuka_plan_runner.cc"],
srcs = ["kuka_plan_runner.cc"] + ["//tools/install/libdrake:libdrake.so"],
data = [
":models",
"//drake/manipulation/models/iiwa_description:models",
],
deps = [
":iiwa_common",
":iiwa_lcm",
"//drake/common:find_resource",
"//tools/install/libdrake:drake_shared_library",
"@lcmtypes_bot2_core",
"@lcmtypes_robotlocomotion",
],
Expand Down
2 changes: 1 addition & 1 deletion drake/examples/kuka_iiwa_arm/kuka_plan_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,6 @@ int do_main() {
} // namespace drake


int main() {
int main(int argc, char* argv[]) {
return drake::examples::kuka_iiwa_arm::do_main();
}
5 changes: 4 additions & 1 deletion tools/install/libdrake/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ cc_library(
cc_library(
name = "drake_shared_library",
hdrs = [":libdrake_headers"],
visibility = ["//drake/bindings:__pkg__"],
visibility = [
"//drake/bindings:__pkg__",
"//drake/examples:__subpackages__",
],
deps = [
":gurobi_deps",
":mosek_deps",
Expand Down

0 comments on commit 6c1d6ce

Please sign in to comment.