Skip to content

Commit 2faaf73

Browse files
authored
Simplifying some of the install criterion (#306)
* better compiler support * trying to clean up some stuff * closer to master * closer to master * build but dont activate at install time * print license key warning
1 parent be3e56d commit 2faaf73

File tree

4 files changed

+77
-24
lines changed

4 files changed

+77
-24
lines changed

mujoco_py/__init__.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/usr/bin/env python
2+
import os
13
from mujoco_py.builder import cymj, ignore_mujoco_warnings, functions, MujocoException
24
from mujoco_py.generated import const
35
from mujoco_py.mjrenderpool import MjRenderPool
@@ -27,4 +29,10 @@
2729
'ignore_mujoco_warnings', 'const', "functions",
2830
"__version__", "get_version"]
2931

30-
mujoco_py.builder.activate()
32+
33+
# Print out a warning if we can't find the key.
34+
# this is nicer than failing activation, which we can not do in python.
35+
# The mujoco library exits the process forcibly, in a way we can't try/catch.
36+
mujoco_py.builder.find_key()
37+
if not os.environ.get('MUJOCO_PY_SKIP_ACTIVATE'):
38+
mujoco_py.builder.activate()

mujoco_py/builder.py

+53-19
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ def load_cython_ext(mjpro_path):
8888

8989
with LockFile(lockpath):
9090
mod = None
91+
force_rebuild = os.environ.get('MUJOCO_PY_FORCE_REBUILD')
92+
if force_rebuild:
93+
# Try to remove the old file, ignore errors if it doesn't exist
94+
print("Removing old mujoco_py cext", cext_so_path)
95+
try:
96+
os.remove(cext_so_path)
97+
except OSError:
98+
pass
9199
if exists(cext_so_path):
92100
try:
93101
mod = load_dynamic_ext('cymj', cext_so_path)
@@ -98,6 +106,7 @@ def load_cython_ext(mjpro_path):
98106
mod = load_dynamic_ext('cymj', cext_so_path)
99107
return mod
100108

109+
101110
def _ensure_set_env_var(var_name, lib_path):
102111
paths = os.environ.get(var_name, "").split(":")
103112
paths = [os.path.abspath(path) for path in paths]
@@ -108,6 +117,7 @@ def _ensure_set_env_var(var_name, lib_path):
108117
"export %s=$%s:%s" % (var_name, os.environ.get(var_name, ""),
109118
var_name, var_name, lib_path))
110119

120+
111121
def load_dynamic_ext(name, path):
112122
''' Load compiled shared object and return as python module. '''
113123
loader = ExtensionFileLoader(name, path)
@@ -236,9 +246,8 @@ def _build_impl(self):
236246

237247
def get_so_file_path(self):
238248
dir_path = abspath(dirname(__file__))
239-
240249
python_version = str(sys.version_info.major) + str(sys.version_info.minor)
241-
return join(dir_path, "generated", "cymj_%s.so" % self.version)
250+
return join(dir_path, "generated", "cymj_{}_{}.so".format(self.version, python_version))
242251

243252

244253
class WindowsExtensionBuilder(MujocoExtensionBuilder):
@@ -259,7 +268,6 @@ def __init__(self, mjpro_path):
259268
self.extension.libraries.extend(['glewosmesa', 'OSMesa', 'GL'])
260269
self.extension.runtime_library_dirs = [join(mjpro_path, 'bin')]
261270

262-
263271
def _build_impl(self):
264272
so_file_path = super()._build_impl()
265273
# Removes absolute paths to libraries. Allows for dynamic loading.
@@ -298,22 +306,27 @@ def __init__(self, mjpro_path):
298306
self.extension.runtime_library_dirs = [join(mjpro_path, 'bin')]
299307

300308
def _build_impl(self):
301-
# Prefer GCC 6 for now since GCC 7 may behave differently.
302-
c_compilers = ['/usr/local/bin/gcc-6', '/usr/local/bin/gcc-7']
303-
available_c_compiler = None
304-
for c_compiler in c_compilers:
305-
if distutils.spawn.find_executable(c_compiler) is not None:
306-
available_c_compiler = c_compiler
307-
break
308-
if available_c_compiler is None:
309-
raise RuntimeError(
310-
'Could not find GCC 6 or GCC 7 executable.\n\n'
311-
'HINT: On OS X, install GCC 6 with '
312-
'`brew install gcc --without-multilib`.')
313-
os.environ['CC'] = available_c_compiler
314-
315-
so_file_path = super()._build_impl()
316-
del os.environ['CC']
309+
if not os.environ.get('CC'):
310+
# Known-working versions of GCC on mac
311+
c_compilers = ['/usr/local/bin/gcc-6',
312+
'/usr/local/bin/gcc-7',
313+
'/usr/local/bin/gcc-8']
314+
available_c_compiler = None
315+
for c_compiler in c_compilers:
316+
if distutils.spawn.find_executable(c_compiler) is not None:
317+
available_c_compiler = c_compiler
318+
break
319+
if available_c_compiler is None:
320+
raise RuntimeError(
321+
'Could not find GCC executable.\n\n'
322+
'HINT: On OS X, install GCC with '
323+
'`brew install gcc`.')
324+
os.environ['CC'] = available_c_compiler
325+
326+
so_file_path = super()._build_impl()
327+
del os.environ['CC']
328+
else: # User-directed c compiler
329+
so_file_path = super()._build_impl()
317330
return manually_link_libraries(self.mjpro_path, so_file_path)
318331

319332

@@ -469,9 +482,30 @@ def build_callback_fn(function_string, userdata_names=[]):
469482
build_fn_cleanup(name)
470483
return module.lib.__fun
471484

485+
486+
MISSING_KEY_MESSAGE = '''
487+
You appear to be missing a License Key for mujoco. We expected to find the
488+
file here: {}
489+
490+
You can get licenses at this page:
491+
492+
https://www.roboti.us/license.html
493+
494+
If python tries to activate an invalid license, the process will exit.
495+
'''
496+
497+
498+
def find_key():
499+
''' Try to find the key file, if missing, print out a big message '''
500+
if exists(key_path):
501+
return
502+
print(MISSING_KEY_MESSAGE.format(key_path), file=sys.stderr)
503+
504+
472505
def activate():
473506
functions.mj_activate(key_path)
474507

508+
475509
mjpro_path, key_path = discover_mujoco()
476510
cymj = load_cython_ext(mjpro_path)
477511

mujoco_py/version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
__all__ = ['__version__', 'get_version']
22

3-
version_info = (1, 50, 1, 59)
3+
version_info = (1, 50, 1, 61)
44
# format:
55
# ('mujoco_major', 'mujoco_minor', 'mujoco_py_major', 'mujoco_py_minor')
66

setup.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/usr/bin/env python3
2-
import importlib
3-
from distutils.command.build import build as DistutilsBuild
4-
from os.path import abspath, join, dirname, realpath
2+
import os
3+
from os.path import join, dirname, realpath
54
from setuptools import find_packages, setup
5+
from distutils.command.build import build as DistutilsBuild
6+
67

78
with open(join("mujoco_py", "version.py")) as version_file:
89
exec(version_file.read())
@@ -19,6 +20,15 @@ def read_requirements_file(filename):
1920
for p in packages:
2021
assert p == 'mujoco_py' or p.startswith('mujoco_py.')
2122

23+
24+
class Build(DistutilsBuild):
25+
def run(self):
26+
os.environ['MUJOCO_PY_FORCE_REBUILD'] = 'True'
27+
os.environ['MUJOCO_PY_SKIP_ACTIVATE'] = 'True'
28+
import mujoco_py # noqa: force build
29+
DistutilsBuild.run(self)
30+
31+
2232
setup(
2333
name='mujoco-py',
2434
version=__version__, # noqa
@@ -27,6 +37,7 @@ def read_requirements_file(filename):
2737
url='https://github.com/openai/mujoco-py',
2838
packages=packages,
2939
include_package_data=True,
40+
cmdclass={'build': Build},
3041
package_dir={'mujoco_py': 'mujoco_py'},
3142
package_data={'mujoco_py': ['generated/*.so']},
3243
install_requires=read_requirements_file('requirements.txt'),

0 commit comments

Comments
 (0)