| |
| '''Generate simConst.py from simConst.h distributed from CoppeliaSim |
| |
| $ ./generate_simConst.py > ../pyrep/backend/simConst.py |
| ''' |
|
|
| import contextlib |
| import importlib |
| import os |
| import os.path as osp |
| import re |
| import shlex |
| import shutil |
| import subprocess |
| import sys |
| import tempfile |
|
|
| try: |
| import CppHeaderParser |
| except ImportError: |
| print('Please run following:\n\tpip install CppHeaderParser', |
| file=sys.stderr) |
| sys.exit(1) |
|
|
|
|
| def get_coppeliasim_root(): |
| if 'COPPELIASIM_ROOT' not in os.environ: |
| raise RuntimeError('Please set env COPPELIASIM_ROOT') |
| return os.environ['COPPELIASIM_ROOT'] |
|
|
|
|
| def import_as(filename, module): |
| spec = importlib.util.spec_from_file_location( |
| module, filename |
| ) |
| module = importlib.util.module_from_spec(spec) |
| spec.loader.exec_module(module) |
| return module |
|
|
|
|
| def generate_simConst_py(): |
| header_file = osp.join( |
| get_coppeliasim_root(), 'programming/include/simConst.h' |
| ) |
| with contextlib.redirect_stdout(sys.stderr): |
| header = CppHeaderParser.CppHeader(header_file) |
|
|
| assert header.classes == {} |
| assert header.functions == [] |
| assert header.global_enums == {} |
|
|
| names = [] |
|
|
| for define in header.defines: |
| m = re.match('^(.*)/\*.*\*/', define) |
| if m: |
| define = m.groups()[0] |
|
|
| splits = define.split() |
| if len(splits) == 2: |
| name, _ = splits |
| if name in ['SIM_PROGRAM_VERSION']: |
| continue |
| names.append(name) |
|
|
| for enum in header.enums: |
| assert enum['namespace'] == '' |
| for value in enum['values']: |
| names.append(value['name']) |
| names.append('') |
|
|
| out_dir = tempfile.mkdtemp() |
|
|
| cpp_file = osp.join(out_dir, 'generate_simConst_py.cpp') |
| with open(cpp_file, 'w') as f: |
| f.write('#include <iostream>\n') |
| f.write('#include <simConst.h>\n') |
| f.write('int main() {\n') |
| for name in names: |
| if name: |
| f.write( |
| f'\tstd::cout << "{name} = " << {name} << std::endl;\n' |
| ) |
| else: |
| f.write('\tstd::cout << std::endl;\n') |
| f.write('}\n') |
|
|
| out_file = osp.join(out_dir, 'generate_simConst_py') |
| cmd = f'g++ {cpp_file} -o {out_file} -I{osp.dirname(header_file)}' |
| subprocess.check_call(shlex.split(cmd)) |
|
|
| cmd = osp.join(out_dir, 'generate_simConst_py') |
| code = subprocess.check_output(cmd).strip().decode() |
|
|
| shutil.rmtree(out_dir) |
|
|
| return code |
|
|
|
|
| def merge_simConst_py(code): |
| official_file = osp.join( |
| get_coppeliasim_root(), |
| 'programming/remoteApiBindings/python/python/simConst.py') |
| official = import_as(official_file, 'official') |
|
|
| out_dir = tempfile.mkdtemp() |
|
|
| generated_file = osp.join(out_dir, 'simConst_generated.py') |
| with open(generated_file, 'w') as f: |
| f.write(code) |
| generated = import_as(generated_file, 'generated') |
|
|
| name_and_value = [] |
| for name in dir(official): |
| if re.match('__.*__', name): |
| continue |
| if name in dir(generated): |
| value_official = getattr(official, name) |
| value_generated = getattr(generated, name) |
| if value_official != value_generated: |
| print(f"WARNING: The values of var '{name}' is not equal: " |
| f'official={value_official}, ' |
| f'generated={value_generated}', file=sys.stderr) |
| else: |
| name_and_value.append((name, getattr(official, name))) |
|
|
| code = ('# This file is automatically generated by ' |
| f'{osp.basename(__file__)} from simConst.h\n\n' + code) |
| code += ('\n\n# Followings are copied from official simConst.py ' |
| '(so possibly deprecated in C++ API)') |
| for name, value in name_and_value: |
| code += f'\n{name} = {value}' |
| code += '\n' |
|
|
| return code |
|
|
|
|
| def main(): |
| code = generate_simConst_py() |
| code = merge_simConst_py(code) |
| print(code, end='') |
|
|
|
|
| if __name__ == '__main__': |
| main() |
|
|