1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00
lvgl/scripts/gen_json/gen_json.py

334 lines
10 KiB
Python

import os
import sys
import argparse
import shutil
import tempfile
import json
import subprocess
base_path = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, base_path)
project_path = os.path.abspath(os.path.join(base_path, '..', '..'))
docs_path = os.path.join(project_path, 'docs')
sys.path.insert(0, docs_path)
import create_fake_lib_c # NOQA
import pycparser_monkeypatch # NOQA
import pycparser # NOQA
DEVELOP = False
temp_directory = tempfile.mkdtemp(suffix='.lvgl_json')
def run(output_path, lvgl_config_path, output_to_stdout, target_header, filter_private, no_docstrings, *compiler_args):
pycparser_monkeypatch.FILTER_PRIVATE = filter_private
lvgl_path = project_path
lvgl_src_path = os.path.join(lvgl_path, 'src')
temp_lvgl = os.path.join(temp_directory, 'lvgl')
target_header_base_name = (
os.path.splitext(os.path.split(target_header)[-1])[0]
)
try:
os.mkdir(temp_lvgl)
shutil.copytree(lvgl_src_path, os.path.join(temp_lvgl, 'src'))
shutil.copyfile(os.path.join(lvgl_path, 'lvgl.h'), os.path.join(temp_lvgl, 'lvgl.h'))
pp_file = os.path.join(temp_directory, target_header_base_name + '.pp')
if lvgl_config_path is None:
lvgl_config_path = os.path.join(lvgl_path, 'lv_conf_template.h')
with open(lvgl_config_path, 'rb') as f:
data = f.read().decode('utf-8').split('\n')
for i, line in enumerate(data):
if line.startswith('#if 0'):
data[i] = '#if 1'
else:
for item in (
'LV_USE_LOG',
'LV_USE_OBJ_ID',
'LV_USE_OBJ_ID_BUILTIN',
'LV_USE_FLOAT',
'LV_USE_BIDI',
'LV_USE_LODEPNG',
'LV_USE_LIBPNG',
'LV_USE_BMP',
'LV_USE_TJPGD',
'LV_USE_LIBJPEG_TURBO',
'LV_USE_GIF',
'LV_BIN_DECODER_RAM_LOAD',
'LV_USE_RLE',
'LV_USE_QRCODE',
'LV_USE_BARCODE',
'LV_USE_TINY_TTF',
'LV_USE_GRIDNAV',
'LV_USE_FRAGMENT',
'LV_USE_IMGFONT',
'LV_USE_SNAPSHOT',
'LV_USE_FREETYPE'
):
if line.startswith(f'#define {item} '):
data[i] = f'#define {item} 1'
break
with open(os.path.join(temp_directory, 'lv_conf.h'), 'wb') as f:
f.write('\n'.join(data).encode('utf-8'))
else:
src = lvgl_config_path
dst = os.path.join(temp_directory, 'lv_conf.h')
shutil.copyfile(src, dst)
include_dirs = [temp_directory, project_path]
if sys.platform.startswith('win'):
import get_sdl2
try:
import pyMSVC # NOQA
except ImportError:
sys.stderr.write(
'\nThe pyMSVC library is missing, '
'please run "pip install pyMSVC" to install it.\n'
)
sys.stderr.flush()
sys.exit(-500)
env = pyMSVC.setup_environment() # NOQA
cpp_cmd = ['cl', '/std:c11', '/nologo', '/P']
output_pp = f'/Fi"{pp_file}"'
sdl2_include, _ = get_sdl2.get_sdl2(temp_directory)
include_dirs.append(sdl2_include)
include_path_env_key = 'INCLUDE'
elif sys.platform.startswith('darwin'):
include_path_env_key = 'C_INCLUDE_PATH'
cpp_cmd = [
'clang', '-std=c11', '-E', '-DINT32_MIN=0x80000000',
]
output_pp = f' >> "{pp_file}"'
else:
include_path_env_key = 'C_INCLUDE_PATH'
cpp_cmd = [
'gcc', '-std=c11', '-E', '-Wno-incompatible-pointer-types',
]
output_pp = f' >> "{pp_file}"'
fake_libc_path = create_fake_lib_c.run(temp_directory)
if include_path_env_key not in os.environ:
os.environ[include_path_env_key] = ''
os.environ[include_path_env_key] = (
f'{fake_libc_path}{os.pathsep}{os.environ[include_path_env_key]}'
)
if 'PATH' not in os.environ:
os.environ['PATH'] = ''
os.environ['PATH'] = (
f'{fake_libc_path}{os.pathsep}{os.environ["PATH"]}'
)
cpp_cmd.extend(compiler_args)
cpp_cmd.extend([
'-DLV_LVGL_H_INCLUDE_SIMPLE',
'-DLV_CONF_INCLUDE_SIMPLE',
'-DLV_USE_DEV_VERSION'
])
cpp_cmd.extend(['-DPYCPARSER', f'"-I{fake_libc_path}"'])
cpp_cmd.extend([f'"-I{item}"' for item in include_dirs])
cpp_cmd.append(f'"{target_header}"')
if sys.platform.startswith('win'):
cpp_cmd.insert(len(cpp_cmd) - 2, output_pp)
else:
cpp_cmd.append(output_pp)
cpp_cmd = ' '.join(cpp_cmd)
p = subprocess.Popen(
cpp_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=os.environ,
shell=True
)
out, err = p.communicate()
exit_code = p.returncode
if not os.path.exists(pp_file):
sys.stdout.write(out.decode('utf-8').strip() + '\n')
sys.stdout.write('EXIT CODE: ' + str(exit_code) + '\n')
sys.stderr.write(err.decode('utf-8').strip() + '\n')
sys.stdout.flush()
sys.stderr.flush()
raise RuntimeError('Unknown Failure')
with open(pp_file, 'r') as f:
pp_data = f.read()
cparser = pycparser.CParser()
ast = cparser.parse(pp_data, target_header)
ast.setup_docs(no_docstrings, temp_directory)
if not output_to_stdout and output_path is None:
if not DEVELOP:
shutil.rmtree(temp_directory)
return ast
elif output_to_stdout:
# stdout.reset()
print(json.dumps(ast.to_dict(), indent=4))
else:
if not os.path.exists(output_path):
os.makedirs(output_path)
output_path = os.path.join(output_path, target_header_base_name + '.json')
with open(output_path, 'w') as f:
f.write(json.dumps(ast.to_dict(), indent=4))
except Exception as err:
try:
print(cpp_cmd) # NOQA
print()
except: # NOQA
pass
for key, value in os.environ.items():
print(key + ':', value)
print()
import traceback
traceback.print_exc()
print()
exceptions = [
ArithmeticError,
AssertionError,
AttributeError,
EOFError,
FloatingPointError,
GeneratorExit,
ImportError,
IndentationError,
IndexError,
KeyError,
KeyboardInterrupt,
LookupError,
MemoryError,
NameError,
NotImplementedError,
OverflowError,
ReferenceError,
RuntimeError,
StopIteration,
SyntaxError,
TabError,
SystemExit,
TypeError,
UnboundLocalError,
UnicodeError,
UnicodeEncodeError,
UnicodeDecodeError,
UnicodeTranslateError,
ValueError,
ZeroDivisionError,
SystemError
]
if isinstance(err, OSError):
error = err.errno
else:
if type(err) in exceptions:
error = ~exceptions.index(type(err))
else:
error = -100
else:
error = 0
if DEVELOP:
print('temporary file path:', temp_directory)
else:
shutil.rmtree(temp_directory)
sys.exit(error)
if __name__ == '__main__':
parser = argparse.ArgumentParser('-')
parser.add_argument(
'--output-path',
dest='output_path',
help=(
'output directory for JSON file. If one is not '
'supplied then it will be output stdout'
),
action='store',
default=None
)
parser.add_argument(
'--lvgl-config',
dest='lv_conf',
help=(
'path to lv_conf.h (including file name), if this is not set then '
'a config file will be generated that has everything turned on.'
),
action='store',
default=None
)
parser.add_argument(
'--develop',
dest='develop',
help='this option leaves the temporary folder in place.',
action='store_true',
)
parser.add_argument(
"--target-header",
dest="target_header",
help=(
"path to a custom header file. When using this to supply a custom"
"header file you MUST insure that any LVGL includes are done so "
"they are relitive to the LVGL repository root folder.\n\n"
'#include "src/lvgl_private.h"\n\n'
"If you have includes to header files that are not LVGL then you "
"will need to add the include locations for those header files "
"when running this script. It is done using the same manner that "
"is used when calling a C compiler\n\n"
"You need to provide the absolute path to the header file when "
"using this feature."
),
action="store",
default=os.path.join(temp_directory, "lvgl", "lvgl.h")
)
parser.add_argument(
'--filter-private',
dest='filter_private',
help='Internal Use',
action='store_true',
)
parser.add_argument(
'--no-docstrings',
dest='no_docstrings',
help='Internal Use',
action='store_true',
)
args, extra_args = parser.parse_known_args()
DEVELOP = args.develop
run(args.output_path, args.lv_conf, args.output_path is None, args.target_header, args.filter_private, args.no_docstrings, *extra_args)