Skip to content

Commit

Permalink
Merge pull request opensim-org#1574 from opensim-org/python_standalone
Browse files Browse the repository at this point in the history
Allow making a standalone Python package
  • Loading branch information
chrisdembia authored Mar 22, 2017
2 parents 399c8d5 + a75edbd commit 51f991d
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 21 deletions.
26 changes: 13 additions & 13 deletions Bindings/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@
# Find python.
# ============

# PythonInterp is supposed to come before PythonLibs.
find_package(PythonInterp 2.7 REQUIRED)
find_package(PythonLibs 2.7 REQUIRED)

# We may need to update the python install dir to include the python version,
# now that we know it. We replace the token "VERSION" with the actual python
# version.
string(REPLACE "VERSION" "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}"
OPENSIM_INSTALL_PYTHONDIR "${OPENSIM_INSTALL_PYTHONDIR}")

# Location of the opensim python package in the build directory, for testing.
if(MSVC OR XCODE)
# Multi-configuration generators like MSVC and XCODE use one build tree for
Expand Down Expand Up @@ -160,11 +150,21 @@ macro(OpenSimAddPythonModule)
endif()

if(${OPENSIM_USE_INSTALL_RPATH})
# TODO @loader_path only makes sense on macOS, so we need to revisit
# for Linux (use $ORIGIN).
# We always set a relative RPATH but only use an absolute RPATH if the
# python package is not standalone, as the libraries are not copied
# into the python package.
# TODO consider using a relative path from the python package directory
# to the OpenSim library directory.
set(run_path_list "\@loader_path/")
if(NOT OPENSIM_PYTHON_STANDALONE)
list(APPEND run_path_list
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
# Use APPEND to include the BTK RPATH, set in CMAKE_INSTALL_RPATH.
# TODO test that NOT using APPEND causes BTK to not be found.
set_property(TARGET ${_libname} APPEND PROPERTY
INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
)
INSTALL_RPATH "${run_path_list}")
endif()

# Copy files into the build tree python package.
Expand Down
4 changes: 3 additions & 1 deletion Bindings/Python/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
url='http://opensim.stanford.edu/',
license='Apache 2.0',
packages=['opensim'],
package_data={'opensim': ['_*.*']},
# The last 3 entries are for if OPENSIM_PYTHON_STANDALONE is ON.
# The asterisk after the extension is to handle version numbers on Linux.
package_data={'opensim': ['_*.*', '*.dylib', '*.dll', '*.so*']},
include_package_data=True,
classifiers=[
'Intended Audience :: Science/Research',
Expand Down
48 changes: 42 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,20 @@ for both OpenSim and Simbody. To make a distributable installation on macOS,
this should be set to ON to avoid using absolute paths for RPATHs to Simbody
libraries." ON)

option(OPENSIM_PYTHON_STANDALONE "Make the Python package standalone, meaning
the OpenSim (and Simbody and BTK) shared libraries it depends on are copied
into the package. If you are building OpenSim on the same machine on which you
plan to use it, you can leave this OFF. If you are distributing OpenSim to
other computers, you should turn this ON. If macOS, this option affects how
RPATH is set for the SWIG-generated shared libraries. This variable has no
effect if BUILD_PYTHON_WRAPPING is OFF." OFF)
# There are many potential ways to distribute the python bindings; here's how
# you might want to set the above option for different ways of distributing:
# simtk.org GUI distribution, macOS: ON (since no env. vars are set)
# simtk.org GUI distrubution, Windows: OFF (PATH is set)
# pypi: ON (there is no way to install the C++ libraries otherwise)
# debian, homebrew, conda: OFF (can have a separate C++ library package)

option(BUILD_API_ONLY "Build/install only headers, libraries,
wrapping, tests; not applications (opensim, ik, rra, etc.)." OFF)

Expand Down Expand Up @@ -431,6 +445,21 @@ if(${BUILD_JAVA_WRAPPING})
endif()
endif()

if(${BUILD_PYTHON_WRAPPING})
# PythonInterp is supposed to come before PythonLibs.
find_package(PythonInterp 2.7 REQUIRED)
find_package(PythonLibs 2.7 REQUIRED)

# We update the python install dir to include the python version,
# now that we know it. We replace the token "VERSION" with the actual python
# version.
string(REPLACE "VERSION" "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}"
OPENSIM_INSTALL_PYTHONDIR "${OPENSIM_INSTALL_PYTHONDIR}")
# This must be done before adding the OpenSim libraries, since
# OPENSIM_INSTALL_PYTHONDIR is used in OpenSimAddLibrary (in
# OpenSimMacros.cmake).
endif()

if(WIN32)
add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
endif()
Expand Down Expand Up @@ -461,7 +490,7 @@ endif()


## RPATH
# If it is necesasry to not put RPATHS in the installed binaries, set
# If it is necessary to not put RPATHS in the installed binaries, set
# set CMAKE_SKIP_INSTALL_RPATH to OFF.
if(APPLE)
# CMake 2.8.12 introduced the ability to set RPATH for shared libraries
Expand Down Expand Up @@ -526,6 +555,10 @@ if(WITH_BTK)
include(${BTK_USE_FILE})
add_definitions(-DWITH_BTK)
CopyDependencyDLLsForWin(BTK ${BTK_INSTALL_PREFIX})
if(BUILD_PYTHON_WRAPPING AND OPENSIM_PYTHON_STANDALONE)
OpenSimInstallDependencyLibraries(BTK "${BTK_INSTALL_PREFIX}"
"${BTK_LIBRARY_DIRS}" "${OPENSIM_INSTALL_PYTHONDIR}/opensim")
endif()
# TODO this should be handled separately between macOS and Linux.
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${BTK_LIBRARY_DIRS}")
endif()
Expand Down Expand Up @@ -624,12 +657,11 @@ if(${OPENSIM_COPY_SIMBODY})
# is only needed for programmers goes in sdk/lib.
# TODO use SimbodyConfig.cmake variables instead of these globs.
if(WIN32)
file(GLOB SIMBODY_BIN_FILES
${Simbody_BIN_DIR}/*.dll
${Simbody_BIN_DIR}/*.exe)
file(GLOB SIMBODY_ARCHIVE_FILES
${Simbody_LIB_DIR}/*.lib)
file(GLOB SIMBODY_BIN_FILES ${Simbody_BIN_DIR}/*.dll
${Simbody_BIN_DIR}/*.exe)
file(GLOB SIMBODY_ARCHIVE_FILES ${Simbody_LIB_DIR}/*.lib)
else()
# TODO simbody-visualizer executable probably isn't even there.
file(GLOB SIMBODY_BIN_FILES
${Simbody_BIN_DIR}/simbody*) # executables only (e.g., visualizer).
# If the LIB_DIR is some common place for libraries (e.g., /usr/lib/),
Expand Down Expand Up @@ -690,6 +722,10 @@ if(${OPENSIM_COPY_SIMBODY})
endforeach()
endif()
endif()
if(BUILD_PYTHON_WRAPPING AND OPENSIM_PYTHON_STANDALONE)
OpenSimInstallDependencyLibraries(SimTK "${Simbody_BIN_DIR}"
"${Simbody_LIB_DIR}" "${OPENSIM_INSTALL_PYTHONDIR}/opensim")
endif()


# Other than Windows we can debug without debuggable SimTK libraries
Expand Down
1 change: 1 addition & 0 deletions OpenSim/Utilities/simmFileWriterDLL/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ file(GLOB INCLUDES *.h)
OpenSimAddLibrary(
KIT SimmFileWriter
AUTHORS "Peter_Loan"
EXCLUDEFROMPYTHON
LINKLIBS osimCommon osimSimulation osimActuators ${Simbody_LIBRARIES}
INCLUDES ${INCLUDES}
SOURCES ${SOURCES}
Expand Down
47 changes: 46 additions & 1 deletion cmake/OpenSimMacros.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include(CMakeParseArguments)
# argument. Otherwise, omit.
# LOWERINCLUDEDIRNAME: When installing the headers for this library, make the
# name of the library all lower-case (e.g., Lepton -> lepton).
# EXCLUDEFROMPYTHON: Do not install this library into the python package.
# KIT: Name of the library (e.g., Common).
# AUTHORS: A string listing authors of the library.
# LINKLIBS: List of libraries (targets) to link against.
Expand Down Expand Up @@ -33,7 +34,7 @@ function(OpenSimAddLibrary)
# Parse arguments.
# ----------------
# http://www.cmake.org/cmake/help/v2.8.9/cmake.html#module:CMakeParseArguments
set(options VENDORLIB LOWERINCLUDEDIRNAME)
set(options VENDORLIB LOWERINCLUDEDIRNAME EXCLUDEFROMPYTHON)
set(oneValueArgs KIT AUTHORS)
set(multiValueArgs LINKLIBS INCLUDES SOURCES TESTDIRS INCLUDEDIRS)
cmake_parse_arguments(
Expand Down Expand Up @@ -97,6 +98,16 @@ function(OpenSimAddLibrary)
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${OPENSIM_INSTALL_ARCHIVEDIR}")
if(BUILD_PYTHON_WRAPPING AND OPENSIM_PYTHON_STANDALONE
AND NOT OSIMADDLIB_EXCLUDEFROMPYTHON)
if (WIN32)
install(TARGETS ${OSIMADDLIB_LIBRARY_NAME}
RUNTIME DESTINATION "${OPENSIM_INSTALL_PYTHONDIR}/opensim")
else()
install(TARGETS ${OSIMADDLIB_LIBRARY_NAME}
LIBRARY DESTINATION "${OPENSIM_INSTALL_PYTHONDIR}/opensim")
endif()
endif()

# Install headers.
# ----------------
Expand Down Expand Up @@ -150,6 +161,8 @@ function(OpenSimAddLibrary)
# list(APPEND run_path_list
# "\@loader_path/${lib_dir_to_simbody_lib_dir}")
#endif()
# It is possible that on UNIX (APPLE and Linux), we will install
# Simbody and BTK beside OpenSim, rather than in their own directories.
# Use APPEND to include the BTK RPATH, set in CMAKE_INSTALL_RPATH.
set_property(TARGET ${OSIMADDLIB_LIBRARY_NAME} APPEND PROPERTY
INSTALL_RPATH "${run_path_list}"
Expand Down Expand Up @@ -304,6 +317,38 @@ function(OpenSimAddApplication)
endfunction()


# Function to install shared libraries (any platform) from a dependency install
# directory into the OpenSim installation. One use case is to install libraries
# into the python package.
# PREFIX: A common part of the library file names (e.g., 'SimTK' or 'BTK').
# This is to avoid copying unrelated files from a folder like /usr/lib.
# DEP_LIBS_DIR_WIN: Directory to search for the dependency's library, on
# Windows.
# DEP_LIBS_DIR_UNIX: Directory to search for the dependency's library, on
# UNIX (APPLE and Linux). Specify only the lib directory to avoid
# searching all of /usr/local (if the dependency is installed to a
# system location like this).
# OSIM_DESTINATION: Destination of the libraries within OpenSim's installation.
function(OpenSimInstallDependencyLibraries PREFIX DEP_LIBS_DIR_WIN
DEP_LIBS_DIR_UNIX OSIM_DESTINATION)
if(WIN32)
file(GLOB_RECURSE LIBS "${DEP_LIBS_DIR_WIN}/${PREFIX}*.dll")
else()
if(APPLE)
set(lib_ext "dylib")
else()
set(lib_ext "so*") # Trailing * for version #s.
endif()
file(GLOB_RECURSE LIBS "${DEP_LIBS_DIR_UNIX}/lib${PREFIX}*.${lib_ext}")
endif()
if(NOT LIBS)
message(FATAL_ERROR "Zero shared libraries found in directory "
"${DEP_INSTALL_DIR}.")
endif()
install(FILES ${LIBS} DESTINATION "${OSIM_DESTINATION}")
endfunction()


# Function to copy DLL files from dependency install directory into OpenSim
# build and install directories. This is a Windows specific function enabled
# only for Windows platform. Intention is to allow runtime loader to find all
Expand Down

0 comments on commit 51f991d

Please sign in to comment.