diff --git a/drake/bindings/pydrake/__init__.py b/drake/bindings/pydrake/__init__.py index 66d325c23e2c..aa5408e80f76 100644 --- a/drake/bindings/pydrake/__init__.py +++ b/drake/bindings/pydrake/__init__.py @@ -9,20 +9,3 @@ from . import rbtree from .pydrake_path import getDrakePath - -# Adding searchable path as inferred by pydrake. This assumes that the python -# module has not been moved outside of the installation directory (in which -# 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")) - ) diff --git a/drake/bindings/pydrake/pydrake_path.py b/drake/bindings/pydrake/pydrake_path.py index 2f2d86565e64..b021c7e5bdb0 100644 --- a/drake/bindings/pydrake/pydrake_path.py +++ b/drake/bindings/pydrake/pydrake_path.py @@ -3,4 +3,4 @@ def getDrakePath(): - return pydrake.common.GetDrakePath() + return os.path.abspath(pydrake.common.GetDrakePath()) diff --git a/drake/common/BUILD.bazel b/drake/common/BUILD.bazel index a7054b48de0d..fcf607003e96 100644 --- a/drake/common/BUILD.bazel +++ b/drake/common/BUILD.bazel @@ -230,11 +230,22 @@ DRAKE_RESOURCE_SENTINEL = "//drake:.drake-find_resource-sentinel" drake_cc_library( name = "find_resource", - srcs = ["find_resource.cc"], - hdrs = ["find_resource.h"], + srcs = [ + "find_loaded_library.cc", + "find_resource.cc", + ], + hdrs = [ + "find_loaded_library.h", + "find_resource.h", + ], data = [ DRAKE_RESOURCE_SENTINEL, ], + # for libdrake.so path on linux + linkopts = select({ + "//tools/cc_toolchain:linux": ["-ldl"], + "//conditions:default": [], + }), deps = [ ":essential", "@spruce", diff --git a/drake/common/find_loaded_library.cc b/drake/common/find_loaded_library.cc new file mode 100644 index 000000000000..c8a5dfce1fb9 --- /dev/null +++ b/drake/common/find_loaded_library.cc @@ -0,0 +1,124 @@ +#include "drake/common/find_loaded_library.h" + +#ifdef __APPLE__ +#include + +#include +#include +#else // Not __APPLE__ +#include +#include + +#include +#endif + +using std::string; + +namespace drake { + +#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(*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(readMem)); +} + +// Gets the list of all the dynamic libraries that have been loaded. Finds +// `library_name` 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 loaded_library_path(const std::string &library_name) { + optional 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(&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(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(infos->infoArray), &size2); + if (!info_addr) { + return binary_dirname; + } + struct dyld_image_info* info = + reinterpret_cast(info_addr); + + // Loop over the dynamic libraries until `library_name` is found. + for (uint32_t i=0; i < infos->infoArrayCount; i++) { + const char * pos_slash = strrchr(info[i].imageFilePath, '/'); + if (!strcmp(pos_slash + 1, library_name.c_str())) { + binary_dirname = string(info[i].imageFilePath, + pos_slash - info[i].imageFilePath); + 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 +// `library_name` 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 loaded_library_path(const std::string &library_name) { + optional binary_dirname; + struct lmap* pl; + void* ph = dlopen(NULL, RTLD_NOW); + struct something* p = reinterpret_cast(ph); + p = p->ptr; + pl = reinterpret_cast(p->ptr); + // Loop over loaded shared objects until `library_name` is found. + while (NULL != pl) { + if (!strcmp(basename(pl->path), library_name.c_str())) { + binary_dirname = string(dirname(pl->path)); + break; + } + pl = pl->next; + } + return binary_dirname; +} +#endif +} // namespace drake diff --git a/drake/common/find_loaded_library.h b/drake/common/find_loaded_library.h new file mode 100644 index 000000000000..71db241bc57d --- /dev/null +++ b/drake/common/find_loaded_library.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +#include "drake/common/drake_optional.h" + +namespace drake { + + +optional loaded_library_path(const std::string &library_name); + + +} // namespace drake diff --git a/drake/common/find_resource.cc b/drake/common/find_resource.cc index dd5aa3a8799d..69040f3f7583 100644 --- a/drake/common/find_resource.cc +++ b/drake/common/find_resource.cc @@ -4,9 +4,22 @@ #include #include +#ifdef __APPLE__ +#include + +#include +#include +#else // Not __APPLE__ +#include +#include + +#include +#endif + #include #include "drake/common/drake_throw.h" +#include "drake/common/find_loaded_library.h" #include "drake/common/never_destroyed.h" using std::string; @@ -106,6 +119,14 @@ optional getenv_optional(const char* const name) { return nullopt; } +optional resource_path_from_libdrake() { + optional libdrake_dir = loaded_library_path("libdrake.so"); + if (libdrake_dir) { + libdrake_dir = libdrake_dir.value() + "/../share/drake"; + } + return libdrake_dir; +} + bool is_relative_path(const string& path) { // TODO(jwnimmer-tri) Prevent .. escape? return !path.empty() && (path[0] != '/'); @@ -217,8 +238,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 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()); diff --git a/drake/examples/kuka_iiwa_arm/BUILD.bazel b/drake/examples/kuka_iiwa_arm/BUILD.bazel index 5e53a13d0dab..4af3256b1581 100644 --- a/drake/examples/kuka_iiwa_arm/BUILD.bazel +++ b/drake/examples/kuka_iiwa_arm/BUILD.bazel @@ -5,6 +5,7 @@ load( "drake_cc_library", "drake_cc_binary", "drake_cc_googletest", + "drake_example_cc_binary", ) load("//tools/install:install_data.bzl", "install", "install_data") load("//tools/lint:lint.bzl", "add_lint_tests") @@ -74,7 +75,7 @@ drake_cc_library( ], ) -drake_cc_binary( +drake_example_cc_binary( name = "iiwa_controller", srcs = ["iiwa_controller.cc"], data = [ @@ -84,15 +85,11 @@ drake_cc_binary( deps = [ ":iiwa_common", ":lcm_plan_interpolator", - "//drake/common:text_logging_gflags", - "//drake/lcm", - "//drake/systems/lcm", - "//drake/systems/lcm:lcm_driven_loop", "@com_github_gflags_gflags//:gflags", ], ) -drake_cc_binary( +drake_example_cc_binary( name = "iiwa_wsg_simulation", srcs = ["iiwa_wsg_simulation.cc"], add_test_rule = 1, @@ -108,25 +105,12 @@ 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", "@com_github_gflags_gflags//:gflags", ], ) -drake_cc_binary( +drake_example_cc_binary( name = "kuka_simulation", srcs = ["kuka_simulation.cc"], add_test_rule = 1, @@ -140,23 +124,13 @@ 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", "@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", @@ -164,7 +138,7 @@ drake_cc_binary( deps = [ ":iiwa_common", ":iiwa_lcm", - "//drake/common:find_resource", + "//tools/install/libdrake:drake_shared_library", "@lcmtypes_bot2_core", "@lcmtypes_robotlocomotion", ], diff --git a/tools/drake.bzl b/tools/drake.bzl index 669879907550..e90c5bb3f0dc 100644 --- a/tools/drake.bzl +++ b/tools/drake.bzl @@ -8,4 +8,5 @@ load( "drake_cc_googletest", "drake_cc_library", "drake_cc_test", + "drake_example_cc_binary", ) diff --git a/tools/install/libdrake/BUILD.bazel b/tools/install/libdrake/BUILD.bazel index 10d8b2775376..68019711f759 100644 --- a/tools/install/libdrake/BUILD.bazel +++ b/tools/install/libdrake/BUILD.bazel @@ -105,7 +105,10 @@ cc_library( cc_library( name = "drake_shared_library", hdrs = [":libdrake_headers"], - visibility = ["//drake/bindings/pydrake:__pkg__"], + visibility = [ + "//drake/bindings:__subpackages__", + "//drake/examples:__subpackages__", + ], deps = [ ":gurobi_deps", ":mosek_deps", diff --git a/tools/skylark/drake_cc.bzl b/tools/skylark/drake_cc.bzl index e50d67f9d8a4..39b15deaa3ef 100644 --- a/tools/skylark/drake_cc.bzl +++ b/tools/skylark/drake_cc.bzl @@ -496,3 +496,38 @@ def drake_cc_googletest( name = name, deps = deps, **kwargs) + +def drake_example_cc_binary( + name, + srcs = [], + data = [], + deps = [], + copts = [], + gcc_copts = [], + linkstatic = 1, + testonly = 0, + add_test_rule = 0, + test_rule_args = [], + test_rule_data = [], + test_rule_size = None, + test_rule_flaky = 0, + **kwargs): + """Creates a rule to declare a C++ binary. + """ + drake_cc_binary( + name = name, + srcs = srcs + + ["//tools/install/libdrake:libdrake.so", + "//drake/lcmtypes:drake_lcmtypes_headers"], + data = data, + deps = deps + ["//tools/install/libdrake:drake_shared_library"], + copts = copts, + gcc_copts = gcc_copts, + linkstatic = linkstatic, + testonly = testonly, + add_test_rule = add_test_rule, + test_rule_args = test_rule_args, + test_rule_data = test_rule_data, + test_rule_size = test_rule_size, + test_rule_flaky = test_rule_flaky, + **kwargs)