11# Copyright (c) 2024 - 2025 Kevin G. Schlosser
2+
3+ import os
4+ import sys
5+ import subprocess
6+
7+
8+ SCRIPT_PATH = os .path .dirname (os .path .abspath (__file__ ))
9+ PROJECT_PATH = os .path .abspath (os .path .join (SCRIPT_PATH , '..' ))
10+
11+ while 'lib' not in os .listdir (PROJECT_PATH ):
12+ PROJECT_PATH = os .path .abspath (os .path .join (PROJECT_PATH , '..' ))
13+
14+ PYCPARSER_PATH = os .path .join (PROJECT_PATH , 'lib' , 'pycparser' )
15+ FAKE_LIB_C_PATH = os .path .join (SCRIPT_PATH , 'fake_libc' )
16+
17+ sys .path .insert (0 , os .path .abspath (PYCPARSER_PATH ))
18+
19+
20+ if __name__ == '__main__' :
21+
22+ sys .path .append (os .path .abspath (os .path .join (SCRIPT_PATH , '..' )))
23+
24+ import api_gen
25+
26+ import argparse
27+
28+ # Argument parsing
29+ argParser = argparse .ArgumentParser ()
30+
31+ argParser .add_argument (
32+ '-I' ,
33+ '--include' ,
34+ dest = 'include' ,
35+ help = 'Preprocesor include path' ,
36+ metavar = '<Include Path>' ,
37+ action = 'append' ,
38+ default = []
39+ )
40+ argParser .add_argument (
41+ '-D' ,
42+ '--define' ,
43+ dest = 'define' ,
44+ help = 'Define preprocessor macro' ,
45+ metavar = '<Macro Name>' ,
46+ action = 'append' ,
47+ default = []
48+ )
49+ argParser .add_argument (
50+ '--metadata' ,
51+ dest = 'metadata' ,
52+ help = 'Optional file to emit metadata (introspection)' ,
53+ metavar = '<MetaData File Name>' ,
54+ action = 'store' ,
55+ default = None
56+
57+ )
58+ argParser .add_argument (
59+ '--output' ,
60+ dest = 'output' ,
61+ help = 'Output file path' ,
62+ metavar = '<Output path>' ,
63+ action = 'store' ,
64+ default = None
65+ )
66+ argParser .add_argument (
67+ '--debug' ,
68+ dest = 'debug' ,
69+ help = 'enable debugging output' ,
70+ action = 'store_true' ,
71+ default = False
72+ )
73+ argParser .add_argument (
74+ '--header_file' ,
75+ dest = 'header' ,
76+ action = 'store' ,
77+ default = None
78+ )
79+
80+ args , unknownargs = argParser .parse_known_args ()
81+
82+ if args .output is None :
83+ output = os .path .join (SCRIPT_PATH , 'output.pp' )
84+ else :
85+ output = args .output
86+
87+ if args .header is None :
88+ header = os .path .join (PROJECT_PATH , 'lib' , 'lvgl' , 'lvgl.h' )
89+ else :
90+ header = args .header
91+
92+ parser = api_gen .__main__ (
93+ header , output , args .include ,
94+ args .define , * unknownargs ,
95+ debug = args .debug
96+ )
97+
98+ from api_gen import templates
99+
100+ print (templates .module (
101+ header ,
102+ parser .enum_definitions ,
103+ parser .struct_definitions ,
104+ parser .union_definitions ,
105+ parser .function_definitions ,
106+ parser .variable_definitions ,
107+ parser .module_decls
108+ ))
109+
110+ from api_gen .json_reader import converters
111+ import json
112+
113+ print ()
114+ print (json .dumps (converters .mp_to_c , indent = 4 ))
115+ print ()
116+ print ()
117+ print (json .dumps (converters .c_to_mp , indent = 4 ))
118+
119+ sys .exit ()
120+
121+
122+ from . import patch_pycparser # NOQA
123+
124+ from . import pp_to_json
125+ from . import json_reader
126+
127+
128+ def get_preprocessor_output (output , input_header , includes_ , defines , * addl_args ):
129+ # this block of code is used to handle the generation of the preprocessor
130+ # output. Since pycparser has the ability to call the compiler internally
131+ # there is no need to do it from cmake. Data doesn't need to be going in
132+ # and out of cmake like that when it can all be done in a single location.
133+ # it makes things easier.
134+
135+ # when compiling under Windows we want to set up a build system that
136+ # points to all the right things to allow pycparser to work correctly
137+ # when generating the preprocessor output. I have not yet fully determined
138+ # the best way to handle the pyMSVC dependency as it is not needed for
139+ # folks running any other OS except Windows.
140+
141+ pp_file = output .rsplit ('.' , 1 )[0 ] + '.pp'
142+
143+ if sys .platform .startswith ('win' ):
144+ try :
145+ import pyMSVC # NOQA
146+ except ImportError :
147+ sys .stderr .write (
148+ '\n The pyMSVC library is missing, '
149+ 'please run "pip install pyMSVC" to install it.\n '
150+ )
151+ sys .stderr .flush ()
152+ sys .exit (- 500 )
153+
154+ env = pyMSVC .setup_environment () # NOQA
155+ cpp_cmd = ['cl' , '/std:c11' , '/nologo' , '/P' ]
156+ output_pp = f'/Fi"{ pp_file } "'
157+ include_path_env_key = 'INCLUDE'
158+
159+ else :
160+ include_path_env_key = 'C_INCLUDE_PATH'
161+ cpp_cmd = [
162+ 'gcc' , '-std=c11' , '-E' , '-Wno-incompatible-pointer-types' ,
163+ ]
164+ output_pp = f' >> "{ pp_file } "'
165+
166+ if include_path_env_key not in os .environ :
167+ os .environ [include_path_env_key ] = ''
168+
169+ os .environ [include_path_env_key ] = (
170+ f'{ FAKE_LIB_C_PATH } { os .pathsep } { os .environ [include_path_env_key ]} '
171+ )
172+
173+ if 'PATH' not in os .environ :
174+ os .environ ['PATH' ] = ''
175+
176+ os .environ ['PATH' ] = (
177+ f'{ FAKE_LIB_C_PATH } { os .pathsep } { os .environ ["PATH" ]} '
178+ )
179+
180+ cpp_cmd .extend ([f'-D{ define } ' for define in defines ])
181+ cpp_cmd .extend (['-DPYCPARSER' , '-E' , f'-I{ FAKE_LIB_C_PATH } ' ])
182+ cpp_cmd .extend ([f'-I{ include } ' for include in includes_ ])
183+ cpp_cmd .append (f'"{ input_header } "' )
184+
185+ if sys .platform .startswith ('win' ):
186+ cpp_cmd .insert (len (cpp_cmd ) - 2 , output_pp )
187+ else :
188+ cpp_cmd .append (output_pp )
189+
190+ cpp_cmd .extend (list (addl_args ))
191+
192+ cpp_cmd = ' ' .join (cpp_cmd )
193+
194+ p = subprocess .Popen (
195+ cpp_cmd ,
196+ stdout = subprocess .PIPE ,
197+ stderr = subprocess .PIPE ,
198+ env = os .environ ,
199+ shell = True
200+ )
201+ out , err_ = p .communicate ()
202+ exit_code = p .returncode
203+
204+ if not os .path .exists (pp_file ):
205+ sys .stdout .write (out .decode ('utf-8' ).strip () + '\n ' )
206+ sys .stdout .write ('EXIT CODE: ' + str (exit_code ) + '\n ' )
207+ sys .stderr .write (err_ .decode ('utf-8' ).strip () + '\n ' )
208+ sys .stdout .flush ()
209+ sys .stderr .flush ()
210+
211+ raise RuntimeError ('Unknown Failure' )
212+
213+ return pp_file
214+
215+
216+ def __main__ (input_header , output_file , includes , defines , * compiler_options , debug = False ):
217+ pp_file = get_preprocessor_output (output_file , input_header , includes ,
218+ defines , * compiler_options )
219+
220+
221+ from pycparser .c_generator import CGenerator
222+ generator = CGenerator ()
223+
224+ with open (r'C:\Users\drsch\PycharmProjects\lvgl_micropython\gen\api_gen\lvgl.pp' , 'r' ) as f :
225+ data = f .read ()
226+
227+ print (generator .visit (data ))
228+ raise RuntimeError
229+
230+ json_data = pp_to_json .JSONGenerator .parse (input_header , f .read (), False )
231+ return json_reader .CGenerator .parse (json_data )
232+
0 commit comments