mkdoc.py (11986:c12e4625ab56) mkdoc.py (12391:ceeca8b41e4b)
1#!/usr/bin/env python3
2#
3# Syntax: mkdoc.py [-I<path> ..] [.. a list of header files ..]
4#
5# Extract documentation from C++ header files to use it in Python bindings
6#
7
8import os

--- 42 unchanged lines hidden (view full) ---

51}
52
53CPP_OPERATORS = OrderedDict(
54 sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0])))
55
56job_count = cpu_count()
57job_semaphore = Semaphore(job_count)
58
1#!/usr/bin/env python3
2#
3# Syntax: mkdoc.py [-I<path> ..] [.. a list of header files ..]
4#
5# Extract documentation from C++ header files to use it in Python bindings
6#
7
8import os

--- 42 unchanged lines hidden (view full) ---

51}
52
53CPP_OPERATORS = OrderedDict(
54 sorted(CPP_OPERATORS.items(), key=lambda t: -len(t[0])))
55
56job_count = cpu_count()
57job_semaphore = Semaphore(job_count)
58
59registered_names = dict()
59output = []
60
60
61
62def d(s):
63 return s.decode('utf8')
64
65
66def sanitize_name(name):
61def d(s):
62 return s.decode('utf8')
63
64
65def sanitize_name(name):
67 global registered_names
68 name = re.sub(r'type-parameter-0-([0-9]+)', r'T\1', name)
69 for k, v in CPP_OPERATORS.items():
70 name = name.replace('operator%s' % k, 'operator_%s' % v)
71 name = re.sub('<.*>', '', name)
72 name = ''.join([ch if ch.isalnum() else '_' for ch in name])
73 name = re.sub('_$', '', re.sub('_+', '_', name))
66 name = re.sub(r'type-parameter-0-([0-9]+)', r'T\1', name)
67 for k, v in CPP_OPERATORS.items():
68 name = name.replace('operator%s' % k, 'operator_%s' % v)
69 name = re.sub('<.*>', '', name)
70 name = ''.join([ch if ch.isalnum() else '_' for ch in name])
71 name = re.sub('_$', '', re.sub('_+', '_', name))
74 if name in registered_names:
75 registered_names[name] += 1
76 name += '_' + str(registered_names[name])
77 else:
78 registered_names[name] = 1
79 return '__doc_' + name
80
81
82def process_comment(comment):
83 result = ''
84
85 # Remove C++ comment syntax
86 leading_spaces = float('inf')

--- 97 unchanged lines hidden (view full) ---

184 wrapper.subsequent_indent = ' ' * 4
185 else:
186 if len(wrapped) > 0:
187 result += wrapped + '\n\n'
188 wrapper.initial_indent = wrapper.subsequent_indent = ''
189 return result.rstrip().lstrip('\n')
190
191
72 return '__doc_' + name
73
74
75def process_comment(comment):
76 result = ''
77
78 # Remove C++ comment syntax
79 leading_spaces = float('inf')

--- 97 unchanged lines hidden (view full) ---

177 wrapper.subsequent_indent = ' ' * 4
178 else:
179 if len(wrapped) > 0:
180 result += wrapped + '\n\n'
181 wrapper.initial_indent = wrapper.subsequent_indent = ''
182 return result.rstrip().lstrip('\n')
183
184
192def extract(filename, node, prefix, output):
193 num_extracted = 0
185def extract(filename, node, prefix):
194 if not (node.location.file is None or
195 os.path.samefile(d(node.location.file.name), filename)):
196 return 0
197 if node.kind in RECURSE_LIST:
198 sub_prefix = prefix
199 if node.kind != CursorKind.TRANSLATION_UNIT:
200 if len(sub_prefix) > 0:
201 sub_prefix += '_'
202 sub_prefix += d(node.spelling)
203 for i in node.get_children():
186 if not (node.location.file is None or
187 os.path.samefile(d(node.location.file.name), filename)):
188 return 0
189 if node.kind in RECURSE_LIST:
190 sub_prefix = prefix
191 if node.kind != CursorKind.TRANSLATION_UNIT:
192 if len(sub_prefix) > 0:
193 sub_prefix += '_'
194 sub_prefix += d(node.spelling)
195 for i in node.get_children():
204 num_extracted += extract(filename, i, sub_prefix, output)
205 if num_extracted == 0:
206 return 0
196 extract(filename, i, sub_prefix)
207 if node.kind in PRINT_LIST:
208 comment = d(node.raw_comment) if node.raw_comment is not None else ''
209 comment = process_comment(comment)
210 sub_prefix = prefix
211 if len(sub_prefix) > 0:
212 sub_prefix += '_'
213 if len(node.spelling) > 0:
214 name = sanitize_name(sub_prefix + d(node.spelling))
197 if node.kind in PRINT_LIST:
198 comment = d(node.raw_comment) if node.raw_comment is not None else ''
199 comment = process_comment(comment)
200 sub_prefix = prefix
201 if len(sub_prefix) > 0:
202 sub_prefix += '_'
203 if len(node.spelling) > 0:
204 name = sanitize_name(sub_prefix + d(node.spelling))
215 output.append('\nstatic const char *%s =%sR"doc(%s)doc";' %
216 (name, '\n' if '\n' in comment else ' ', comment))
217 num_extracted += 1
218 return num_extracted
205 global output
206 output.append((name, filename, comment))
219
220
221class ExtractionThread(Thread):
207
208
209class ExtractionThread(Thread):
222 def __init__(self, filename, parameters, output):
210 def __init__(self, filename, parameters):
223 Thread.__init__(self)
224 self.filename = filename
225 self.parameters = parameters
211 Thread.__init__(self)
212 self.filename = filename
213 self.parameters = parameters
226 self.output = output
227 job_semaphore.acquire()
228
229 def run(self):
230 print('Processing "%s" ..' % self.filename, file=sys.stderr)
231 try:
232 index = cindex.Index(
233 cindex.conf.lib.clang_createIndex(False, True))
234 tu = index.parse(self.filename, self.parameters)
214 job_semaphore.acquire()
215
216 def run(self):
217 print('Processing "%s" ..' % self.filename, file=sys.stderr)
218 try:
219 index = cindex.Index(
220 cindex.conf.lib.clang_createIndex(False, True))
221 tu = index.parse(self.filename, self.parameters)
235 extract(self.filename, tu.cursor, '', self.output)
222 extract(self.filename, tu.cursor, '')
236 finally:
237 job_semaphore.release()
238
239if __name__ == '__main__':
240 parameters = ['-x', 'c++', '-std=c++11']
241 filenames = []
242
243 if platform.system() == 'Darwin':

--- 40 unchanged lines hidden (view full) ---

284#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__))
285
286#if defined(__GNUG__)
287#pragma GCC diagnostic push
288#pragma GCC diagnostic ignored "-Wunused-variable"
289#endif
290''')
291
223 finally:
224 job_semaphore.release()
225
226if __name__ == '__main__':
227 parameters = ['-x', 'c++', '-std=c++11']
228 filenames = []
229
230 if platform.system() == 'Darwin':

--- 40 unchanged lines hidden (view full) ---

271#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__))
272
273#if defined(__GNUG__)
274#pragma GCC diagnostic push
275#pragma GCC diagnostic ignored "-Wunused-variable"
276#endif
277''')
278
292 output = []
279 output.clear()
293 for filename in filenames:
280 for filename in filenames:
294 thr = ExtractionThread(filename, parameters, output)
281 thr = ExtractionThread(filename, parameters)
295 thr.start()
296
297 print('Waiting for jobs to finish ..', file=sys.stderr)
298 for i in range(job_count):
299 job_semaphore.acquire()
300
282 thr.start()
283
284 print('Waiting for jobs to finish ..', file=sys.stderr)
285 for i in range(job_count):
286 job_semaphore.acquire()
287
301 output.sort()
302 for l in output:
303 print(l)
288 name_ctr = 1
289 name_prev = None
290 for name, _, comment in list(sorted(output, key=lambda x: (x[0], x[1]))):
291 if name == name_prev:
292 name_ctr += 1
293 name = name + "_%i" % name_ctr
294 else:
295 name_prev = name
296 name_ctr = 1
297 print('\nstatic const char *%s =%sR"doc(%s)doc";' %
298 (name, '\n' if '\n' in comment else ' ', comment))
304
305 print('''
306#if defined(__GNUG__)
307#pragma GCC diagnostic pop
308#endif
309''')
299
300 print('''
301#if defined(__GNUG__)
302#pragma GCC diagnostic pop
303#endif
304''')