Add plugin support to Python bindings.
PiperOrigin-RevId: 480675078 Change-Id: I2967654b6662efced8ae62cae9b03c6c8e65c67c
This commit is contained in:
committed by
Copybara-Service
parent
23e4c03efc
commit
95fe2fbc40
@@ -143,6 +143,16 @@ jobs:
|
|||||||
- name: Install MuJoCo
|
- name: Install MuJoCo
|
||||||
working-directory: build
|
working-directory: build
|
||||||
run: cmake --install .
|
run: cmake --install .
|
||||||
|
- name: Copy plugins (POSIX)
|
||||||
|
if: ${{ runner.os != 'Windows' }}
|
||||||
|
working-directory: build
|
||||||
|
run: mkdir -p ${{ matrix.tmpdir }}/mujoco_install/plugin &&
|
||||||
|
cp lib/libcable.* ${{ matrix.tmpdir }}/mujoco_install/plugin
|
||||||
|
- name: Copy plugins (Windows)
|
||||||
|
if: ${{ runner.os == 'Windows' }}
|
||||||
|
working-directory: build
|
||||||
|
run: mkdir -p ${{ matrix.tmpdir }}/mujoco_install/plugin &&
|
||||||
|
cp bin/Release/cable.dll ${{ matrix.tmpdir }}/mujoco_install/plugin
|
||||||
- name: Configure samples
|
- name: Configure samples
|
||||||
working-directory: sample
|
working-directory: sample
|
||||||
run: >
|
run: >
|
||||||
@@ -180,6 +190,7 @@ jobs:
|
|||||||
run: >
|
run: >
|
||||||
source ${{ matrix.tmpdir }}/venv/bin/activate &&
|
source ${{ matrix.tmpdir }}/venv/bin/activate &&
|
||||||
MUJOCO_PATH="${{ matrix.tmpdir }}/mujoco_install"
|
MUJOCO_PATH="${{ matrix.tmpdir }}/mujoco_install"
|
||||||
|
MUJOCO_PLUGIN_PATH="${{ matrix.tmpdir }}/mujoco_install/plugin"
|
||||||
MUJOCO_CMAKE_ARGS="-DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF ${{ matrix.cmake_args }}"
|
MUJOCO_CMAKE_ARGS="-DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=OFF ${{ matrix.cmake_args }}"
|
||||||
pip wheel -v --no-deps mujoco-*.tar.gz
|
pip wheel -v --no-deps mujoco-*.tar.gz
|
||||||
- name: Install Python bindings
|
- name: Install Python bindings
|
||||||
|
|||||||
@@ -26,4 +26,16 @@ add_library(cable SHARED)
|
|||||||
target_sources(cable PRIVATE ${MUJOCO_ELASTICITY_SRCS})
|
target_sources(cable PRIVATE ${MUJOCO_ELASTICITY_SRCS})
|
||||||
target_include_directories(cable PRIVATE ${MUJOCO_ELASTICITY_INCLUDE})
|
target_include_directories(cable PRIVATE ${MUJOCO_ELASTICITY_INCLUDE})
|
||||||
target_link_libraries(cable PRIVATE mujoco)
|
target_link_libraries(cable PRIVATE mujoco)
|
||||||
|
target_compile_options(
|
||||||
|
cable
|
||||||
|
PRIVATE ${AVX_COMPILE_OPTIONS}
|
||||||
|
${MUJOCO_MACOS_COMPILE_OPTIONS}
|
||||||
|
${EXTRA_COMPILE_OPTIONS}
|
||||||
|
${MUJOCO_CXX_FLAGS}
|
||||||
|
)
|
||||||
|
target_link_options(
|
||||||
|
cable
|
||||||
|
PRIVATE
|
||||||
|
${MUJOCO_MACOS_LINK_OPTIONS}
|
||||||
|
${EXTRA_LINK_OPTIONS}
|
||||||
|
)
|
||||||
|
|||||||
@@ -54,5 +54,15 @@ if _MUJOCO_GL not in ('disable', 'disabled', 'off', 'false', '0'):
|
|||||||
from mujoco.glfw import GLContext
|
from mujoco.glfw import GLContext
|
||||||
|
|
||||||
HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include/mujoco')
|
HEADERS_DIR = os.path.join(os.path.dirname(__file__), 'include/mujoco')
|
||||||
|
PLUGINS_DIR = os.path.join(os.path.dirname(__file__), 'plugin')
|
||||||
|
|
||||||
|
PLUGIN_HANDLES = []
|
||||||
|
|
||||||
|
def _load_all_bundled_plugins():
|
||||||
|
for directory, _, filenames in os.walk(PLUGINS_DIR):
|
||||||
|
for filename in filenames:
|
||||||
|
PLUGIN_HANDLES.append(ctypes.CDLL(os.path.join(directory, filename)))
|
||||||
|
|
||||||
|
_load_all_bundled_plugins()
|
||||||
|
|
||||||
__version__ = mj_versionString() # pylint: disable=undefined-variable
|
__version__ = mj_versionString() # pylint: disable=undefined-variable
|
||||||
|
|||||||
@@ -69,6 +69,14 @@ TEST_XML_SENSOR = r"""
|
|||||||
</mujoco>
|
</mujoco>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
TEST_XML_PLUGIN = r"""
|
||||||
|
<mujoco model="test">
|
||||||
|
<extension>
|
||||||
|
<required plugin="mujoco.elasticity.cable"/>
|
||||||
|
</extension>
|
||||||
|
</mujoco>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def temporary_callback(setter, callback):
|
def temporary_callback(setter, callback):
|
||||||
@@ -1111,5 +1119,8 @@ Euler integrator, semi-implicit in velocity.
|
|||||||
self.fail("Attribute '{}' differs from expected value: {}".format(
|
self.fail("Attribute '{}' differs from expected value: {}".format(
|
||||||
name, str(e)))
|
name, str(e)))
|
||||||
|
|
||||||
|
def test_load_plugin(self):
|
||||||
|
mujoco.MjModel.from_xml_string(TEST_XML_PLUGIN)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
absltest.main()
|
absltest.main()
|
||||||
|
|||||||
+31
-2
@@ -35,6 +35,7 @@ __version__ = '2.2.2'
|
|||||||
MUJOCO_CMAKE = 'MUJOCO_CMAKE'
|
MUJOCO_CMAKE = 'MUJOCO_CMAKE'
|
||||||
MUJOCO_CMAKE_ARGS = 'MUJOCO_CMAKE_ARGS'
|
MUJOCO_CMAKE_ARGS = 'MUJOCO_CMAKE_ARGS'
|
||||||
MUJOCO_PATH = 'MUJOCO_PATH'
|
MUJOCO_PATH = 'MUJOCO_PATH'
|
||||||
|
MUJOCO_PLUGIN_PATH = 'MUJOCO_PLUGIN_PATH'
|
||||||
|
|
||||||
EXT_PREFIX = 'mujoco.'
|
EXT_PREFIX = 'mujoco.'
|
||||||
|
|
||||||
@@ -70,6 +71,15 @@ def get_external_lib_patterns():
|
|||||||
return ['libmujoco.so.*']
|
return ['libmujoco.so.*']
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_lib_patterns():
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
return ['*.dll']
|
||||||
|
elif platform.system() == 'Darwin':
|
||||||
|
return ['lib*.dylib']
|
||||||
|
else:
|
||||||
|
return ['lib*']
|
||||||
|
|
||||||
|
|
||||||
def start_and_end(iterable):
|
def start_and_end(iterable):
|
||||||
it = iter(iterable)
|
it = iter(iterable)
|
||||||
while True:
|
while True:
|
||||||
@@ -140,6 +150,7 @@ class BuildCMakeExtension(build_ext.build_ext):
|
|||||||
self._is_apple = (platform.system() == 'Darwin')
|
self._is_apple = (platform.system() == 'Darwin')
|
||||||
(self._mujoco_library_path,
|
(self._mujoco_library_path,
|
||||||
self._mujoco_include_path,
|
self._mujoco_include_path,
|
||||||
|
self._mujoco_plugins_path,
|
||||||
self._mujoco_framework_path) = self._find_mujoco()
|
self._mujoco_framework_path) = self._find_mujoco()
|
||||||
self._configure_cmake()
|
self._configure_cmake()
|
||||||
for ext in self.extensions:
|
for ext in self.extensions:
|
||||||
@@ -148,23 +159,30 @@ class BuildCMakeExtension(build_ext.build_ext):
|
|||||||
self.build_extension(ext)
|
self.build_extension(ext)
|
||||||
self._copy_external_libraries()
|
self._copy_external_libraries()
|
||||||
self._copy_mujoco_headers()
|
self._copy_mujoco_headers()
|
||||||
|
self._copy_plugin_libraries()
|
||||||
|
|
||||||
def _find_mujoco(self):
|
def _find_mujoco(self):
|
||||||
if MUJOCO_PATH not in os.environ:
|
if MUJOCO_PATH not in os.environ:
|
||||||
raise RuntimeError(f'{MUJOCO_PATH} environment variable is not set')
|
raise RuntimeError(
|
||||||
|
f'{MUJOCO_PATH} environment variable is not set')
|
||||||
|
if MUJOCO_PLUGIN_PATH not in os.environ:
|
||||||
|
raise RuntimeError(
|
||||||
|
f'{MUJOCO_PLUGIN_PATH} environment variable is not set')
|
||||||
library_path = None
|
library_path = None
|
||||||
include_path = None
|
include_path = None
|
||||||
|
plugin_path = os.environ['MUJOCO_PLUGIN_PATH']
|
||||||
for directory, subdirs, filenames in os.walk(os.environ['MUJOCO_PATH']):
|
for directory, subdirs, filenames in os.walk(os.environ['MUJOCO_PATH']):
|
||||||
if self._is_apple and 'mujoco.framework' in subdirs:
|
if self._is_apple and 'mujoco.framework' in subdirs:
|
||||||
return (os.path.join(directory, 'mujoco.framework/Versions/A'),
|
return (os.path.join(directory, 'mujoco.framework/Versions/A'),
|
||||||
os.path.join(directory, 'mujoco.framework/Headers'),
|
os.path.join(directory, 'mujoco.framework/Headers'),
|
||||||
|
plugin_path,
|
||||||
directory)
|
directory)
|
||||||
if fnmatch.filter(filenames, get_mujoco_lib_pattern()):
|
if fnmatch.filter(filenames, get_mujoco_lib_pattern()):
|
||||||
library_path = directory
|
library_path = directory
|
||||||
if os.path.exists(os.path.join(directory, 'mujoco/mujoco.h')):
|
if os.path.exists(os.path.join(directory, 'mujoco/mujoco.h')):
|
||||||
include_path = directory
|
include_path = directory
|
||||||
if library_path and include_path:
|
if library_path and include_path:
|
||||||
return library_path, include_path, None
|
return library_path, include_path, plugin_path, None
|
||||||
raise RuntimeError('Cannot find MuJoCo library and/or include paths')
|
raise RuntimeError('Cannot find MuJoCo library and/or include paths')
|
||||||
|
|
||||||
def _copy_external_libraries(self):
|
def _copy_external_libraries(self):
|
||||||
@@ -175,6 +193,17 @@ class BuildCMakeExtension(build_ext.build_ext):
|
|||||||
shutil.copyfile(os.path.join(directory, filename),
|
shutil.copyfile(os.path.join(directory, filename),
|
||||||
os.path.join(dst, filename))
|
os.path.join(dst, filename))
|
||||||
|
|
||||||
|
def _copy_plugin_libraries(self):
|
||||||
|
dst = os.path.join(
|
||||||
|
os.path.dirname(self.get_ext_fullpath(self.extensions[0].name)),
|
||||||
|
'plugin')
|
||||||
|
os.makedirs(dst)
|
||||||
|
for directory, _, filenames in os.walk(self._mujoco_plugins_path):
|
||||||
|
for pattern in get_plugin_lib_patterns():
|
||||||
|
for filename in fnmatch.filter(filenames, pattern):
|
||||||
|
shutil.copyfile(os.path.join(directory, filename),
|
||||||
|
os.path.join(dst, filename))
|
||||||
|
|
||||||
def _copy_mujoco_headers(self):
|
def _copy_mujoco_headers(self):
|
||||||
dst = os.path.join(
|
dst = os.path.join(
|
||||||
os.path.dirname(self.get_ext_fullpath(self.extensions[0].name)),
|
os.path.dirname(self.get_ext_fullpath(self.extensions[0].name)),
|
||||||
|
|||||||
Reference in New Issue
Block a user