File size: 4,083 Bytes
cf8614b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python
'''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()