1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2021-2023 Huawei Device Co., Ltd. 5# 6# HDF is dual licensed: you can use it either under the terms of 7# the GPL, or the BSD license, at your option. 8# See the LICENSE file in the root of this repository for complete details. 9 10import argparse 11import json 12import os 13import re 14import sys 15 16 17class TokenType(object): 18 UNKNOWN = 0 19 COMMENT = 1 20 PACKAGE = 2 21 IMPORT = 3 22 INTERFACE = 4 23 CALLBACK = 5 24 ID = 6 25 END_OF_FILE = 7 26 27 28class Token(object): 29 def __init__(self, file_name, token_type, value): 30 self.token_type = token_type 31 self.value = value 32 self.row = 1 33 self.col = 1 34 self.file_name = file_name 35 36 def clean(self): 37 self.token_type = TokenType.UNKNOWN 38 self.value = "" 39 self.row = 1 40 self.col = 1 41 42 def dump(self): 43 return "<{}:{}:{}: {},'{}'>".format(self.file_name, self.row, self.col, 44 self.token_type, self.value) 45 46 def info(self): 47 return "{}:{}:{}".format(self.file_name, self.row, self.col) 48 49 50class Char(object): 51 def __init__(self, is_eof, char): 52 self.is_eof = is_eof 53 self.char = char 54 55 def dump(self): 56 return "{%s, %s}" % (self.is_eof, self.char) 57 58 59class Lexer(object): 60 _key_words = { 61 "package": TokenType.PACKAGE, 62 "import": TokenType.IMPORT, 63 "interface": TokenType.INTERFACE, 64 "callback": TokenType.CALLBACK, 65 } 66 67 def __init__(self, idl_file_path): 68 self.have_peek = False 69 with open(idl_file_path, 'r') as idl_file: 70 file_info = idl_file.read() 71 self.data = file_info 72 self.data_len = len(self.data) 73 self.read_index = 0 74 self.cur_token = Token(os.path.basename(idl_file_path), 75 TokenType.UNKNOWN, "") 76 self.cur_row = 1 77 self.cur_col = 1 78 79 def peek_char(self, peek_count=0): 80 index = self.read_index + peek_count 81 if index >= self.data_len: 82 return Char(True, '0') 83 return Char(False, self.data[index]) 84 85 def get_char(self): 86 if self.read_index >= self.data_len: 87 return Char(True, '0') 88 read_index = self.read_index 89 self.read_index += 1 90 if self.data[read_index] == '\n': 91 self.cur_row += 1 92 self.cur_col = 1 93 else: 94 self.cur_col += 1 95 return Char(False, self.data[read_index]) 96 97 def peek_token(self): 98 if not self.have_peek: 99 self.read_token() 100 self.have_peek = True 101 return self.cur_token 102 103 def get_token(self): 104 if not self.have_peek: 105 self.read_token() 106 self.have_peek = False 107 return self.cur_token 108 109 def read_token(self): 110 self.cur_token.clean() 111 while not self.peek_char().is_eof: 112 new_char = self.peek_char() 113 if new_char.char.isspace(): 114 self.get_char() 115 continue 116 self.cur_token.row = self.cur_row 117 self.cur_token.col = self.cur_col 118 if new_char.char.isalpha() or new_char.char == '_': 119 self.read_id() 120 return 121 if new_char.char == '/': 122 self.read_comment() 123 return 124 self.cur_token.value = new_char.char 125 self.cur_token.token_type = TokenType.UNKNOWN 126 self.get_char() 127 return 128 self.cur_token.token_type = TokenType.END_OF_FILE 129 130 def read_id(self): 131 token_value = [] 132 token_value.append(self.get_char().char) 133 while not self.peek_char().is_eof: 134 new_char = self.peek_char() 135 if new_char.char.isalpha() or new_char.char.isdigit( 136 ) or new_char.char == '_' or new_char.char == '.': 137 token_value.append(new_char.char) 138 self.get_char() 139 continue 140 break 141 key = "".join(token_value) 142 if key in self._key_words.keys(): 143 self.cur_token.token_type = self._key_words[key] 144 else: 145 self.cur_token.token_type = TokenType.ID 146 self.cur_token.value = key 147 148 def read_comment(self): 149 token_value = [] 150 token_value.append(self.get_char().char) 151 new_char = self.peek_char() 152 if not new_char.is_eof: 153 if new_char.char == '/': 154 self.read_line_comment(token_value) 155 return 156 elif new_char.char == '*': 157 self.read_block_comment(token_value) 158 return 159 self.cur_token.token_type = TokenType.UNKNOWN 160 self.cur_token.value = "".join(token_value) 161 162 def read_line_comment(self, token_value): 163 token_value.append(self.get_char().char) 164 while not self.peek_char().is_eof: 165 new_char = self.get_char() 166 if new_char.char == '\n': 167 break 168 token_value.append(new_char.char) 169 self.cur_token.token_type = TokenType.COMMENT 170 self.cur_token.value = "".join(token_value) 171 172 def read_block_comment(self, token_value): 173 # read * 174 token_value.append(self.get_char().char) 175 while not self.peek_char().is_eof: 176 new_char = self.get_char() 177 token_value.append(new_char.char) 178 if new_char.char == '*' and self.peek_char().char == '/': 179 token_value.append(self.get_char().char) 180 break 181 value = "".join(token_value) 182 if value.endswith("*/"): 183 self.cur_token.token_type = TokenType.COMMENT 184 else: 185 self.cur_token.token_type = TokenType.UNKNOWN 186 self.cur_token.value = value 187 188 189# module info of all idl 190class ModuleInfo(object): 191 package = "" 192 version = "" 193 include_dirs = set() 194 out_dir = "" 195 sources = [] 196 proxy_sources = [] 197 stub_sources = [] 198 proxy_deps = [] 199 stub_deps = [] 200 header_deps = [] 201 202 @staticmethod 203 def json_info(): 204 include_dirs_ret = sorted(list(ModuleInfo.include_dirs)) 205 ModuleInfo.sources.sort() 206 ModuleInfo.proxy_sources.sort() 207 ModuleInfo.stub_sources.sort() 208 209 result = { 210 "package": ModuleInfo.package, 211 "version": ModuleInfo.version, 212 "include_dirs": include_dirs_ret, 213 "out_dir": ModuleInfo.out_dir, 214 "sources": ModuleInfo.sources, 215 "proxy_sources": ModuleInfo.proxy_sources, 216 "stub_sources": ModuleInfo.stub_sources, 217 "proxy_deps": ModuleInfo.proxy_deps, 218 "stub_deps": ModuleInfo.stub_deps, 219 "header_deps": ModuleInfo.header_deps, 220 } 221 return json.dumps(result) 222 223 224class Option(object): 225 system = "full" 226 mode = "ipc" 227 language = "cpp" 228 gen_dir = "" 229 root_package = "" 230 root_path = "" 231 idl_sources = [] 232 imports = [] 233 234 @staticmethod 235 def load(opt_args): 236 Option.system = opt_args.system 237 Option.mode = opt_args.mode 238 Option.language = opt_args.language 239 240 if opt_args.out == "": 241 raise Exception( 242 "the gen_dir '{}' is empty, please check input".format( 243 opt_args.out)) 244 else: 245 Option.gen_dir = opt_args.out 246 247 map_result = opt_args.root.split(":") 248 if len(map_result) != 2: 249 raise Exception( 250 "the package path '{}' is valid, please check input".format( 251 opt_args.root)) 252 else: 253 Option.root_package = map_result[0] 254 Option.root_path = map_result[1] 255 256 if len(opt_args.file) == 0: 257 raise Exception("the idl sources is empty, please check input") 258 else: 259 Option.idl_sources = opt_args.file 260 261 if opt_args.imports is not None: 262 Option.imports = opt_args.imports 263 264 @staticmethod 265 def dump(): 266 result = { 267 "system": Option.system, 268 "kernel": Option.kernel, 269 "mode": Option.mode, 270 "language": Option.language, 271 "gen_dir": Option.gen_dir, 272 "root_package": Option.root_package, 273 "root_path": Option.root_path, 274 "idl_sources": Option.idl_sources 275 } 276 return json.dumps(result) 277 278 279class IdlType(object): 280 INTERFACE = 1 281 CALL_INTERFACE = 2 282 CALLBACK = 3 283 TYPES = 4 284 285 286# file detail of idl file 287class IdlDetail(object): 288 def __init__(self, path): 289 self.package = "" 290 self.idl_type = IdlType.TYPES 291 self.imports = [] 292 self.file_path = path 293 294 self.file_name = os.path.basename(self.file_path) 295 self.name = self.file_name.split('.')[0] 296 297 # package + file name, like 'ohos.hdi.foo.v1_0.IFoo' 298 def full_name(self): 299 return "{}.{}".format(self.package, self.name) 300 301 def dump(self): 302 result = { 303 "package": self.package, 304 "type": self.idl_type, 305 "imports": self.imports, 306 "path": self.file_path 307 } 308 return json.dumps(result) 309 310 311class IdlParser(object): 312 def parse(self, ): 313 all_idl_details = {} 314 if Option.language == "c": 315 self.parse_c_idl_files(all_idl_details) 316 self.parse_deps(all_idl_details) 317 self.parse_module_info(all_idl_details) 318 return 319 320 for idl_file in Option.idl_sources: 321 idl_detail = self.parse_one(idl_file) 322 all_idl_details[idl_detail.full_name()] = idl_detail 323 self.parse_deps(all_idl_details) 324 self.parse_module_info(all_idl_details) 325 326 def parse_one(self, file_path): 327 cur_idl_detail = IdlDetail(file_path) 328 lex = Lexer(file_path) 329 while lex.peek_token().token_type != TokenType.END_OF_FILE: 330 cur_token_type = lex.peek_token().token_type 331 if cur_token_type == TokenType.PACKAGE: 332 self.parse_package(lex, cur_idl_detail) 333 elif cur_token_type == TokenType.IMPORT: 334 self.parse_import(lex, cur_idl_detail) 335 elif cur_token_type == TokenType.CALLBACK: 336 cur_idl_detail.idl_type = IdlType.CALLBACK 337 lex.get_token() 338 elif cur_token_type == TokenType.INTERFACE: 339 self.parse_interface(lex, cur_idl_detail) 340 else: 341 lex.get_token() 342 return cur_idl_detail 343 344 def parse_c_idl_files(self, all_idl_details): 345 idl_sources_set = set() 346 idl_queue = [] 347 for idl_file in Option.idl_sources: 348 idl_queue.append(idl_file) 349 while len(idl_queue) > 0: 350 cur_idl_file = idl_queue.pop(0) 351 if cur_idl_file in idl_sources_set: 352 continue 353 idl_sources_set.add(cur_idl_file) 354 self.parse_c_idl_files_import(cur_idl_file, idl_queue) 355 for idl_file in idl_sources_set: 356 idl_detail = self.parse_one(idl_file) 357 all_idl_details[idl_detail.full_name()] = idl_detail 358 self.merged_idl_details(all_idl_details) 359 360 def parse_c_idl_files_import(self, file_path, idl_queue): 361 lex = Lexer(file_path) 362 while lex.peek_token().token_type != TokenType.END_OF_FILE: 363 cur_token_type = lex.peek_token().token_type 364 if cur_token_type == TokenType.IMPORT: 365 lex.get_token() 366 token = lex.peek_token() 367 if lex.peek_token().token_type != TokenType.ID: 368 raise Exception("{}: expected package name before '{}'".format( 369 token.info(), token.value)) 370 idl_queue.append( 371 CodeGen.get_package_path(token.value) + ".idl") 372 lex.get_token() 373 374 def merged_idl_details(self, all_idl_details): 375 merged_details = {} 376 source_idl_detail = self.parse_one(Option.idl_sources[0]) 377 for _, idl_detail in all_idl_details.items(): 378 idl_detail.package = source_idl_detail.package 379 idl_detail.version = source_idl_detail.version 380 for _, idl_detail in all_idl_details.items(): 381 if idl_detail.full_name() not in merged_details: 382 imports = [] 383 for import_name in idl_detail.imports: 384 import_idl = all_idl_details[import_name] 385 if import_idl.full_name() in imports: 386 continue 387 if import_idl.full_name() != idl_detail.full_name(): 388 imports.append(import_idl.full_name()) 389 idl_detail.imports = imports 390 merged_details[idl_detail.full_name()] = idl_detail 391 else: 392 for import_name in idl_detail.imports: 393 import_idl = all_idl_details[import_name] 394 merged_detail = merged_details[idl_detail.full_name()] 395 if import_idl.full_name() in merged_detail.imports: 396 continue 397 if import_idl.full_name() != idl_detail.full_name(): 398 merged_detail.imports.append(import_idl.full_name()) 399 all_idl_details.clear() 400 for key, value in merged_details.items(): 401 all_idl_details[key] = value 402 403 def parse_package(self, lex, cur_idl_detail): 404 lex.get_token() # package token 405 token = lex.peek_token() 406 if token.token_type != TokenType.ID: 407 raise Exception("{}: expected package name before '{}'".format( 408 token.info(), token.value)) 409 token = lex.get_token() 410 if not self.parse_version(token.value, cur_idl_detail): 411 raise Exception("{}: failed to parse package name '{}'".format( 412 token.info(), token.value)) 413 414 def parse_version(self, package_name, cur_idl_detail): 415 result = re.findall(r'\w+(?:\.\w+)*\.[V|v](\d+)_(\d+)', package_name) 416 if len(result) > 0: 417 cur_idl_detail.package = package_name 418 major_version = result[0][0] 419 minor_version = result[0][1] 420 cur_idl_detail.version = "{}.{}".format(major_version, minor_version) 421 return True 422 return False 423 424 def parse_import(self, lex, cur_idl_detail): 425 lex.get_token() # import token 426 if lex.peek_token().token_type != TokenType.ID: 427 token = lex.peek_token() 428 raise Exception("{}: expected package name before '{}'".format( 429 token.info(), token.value)) 430 cur_idl_detail.imports.append(lex.get_token().value) 431 432 def parse_interface(self, lex, cur_idl_detail): 433 lex.get_token() # interface token 434 if lex.peek_token().token_type != TokenType.ID: 435 token = lex.peek_token() 436 raise Exception("{}: expected interface name before '{}'".format( 437 token.info(), token.value)) 438 token = lex.get_token() 439 interface_name = token.value 440 if interface_name != cur_idl_detail.name: 441 raise Exception( 442 "{}: interface name '{}' does not match file name '{}'".format( 443 token.info(), interface_name, cur_idl_detail.file_name)) 444 if cur_idl_detail.idl_type != IdlType.CALLBACK: 445 cur_idl_detail.idl_type = IdlType.INTERFACE 446 447 def parse_deps(self, all_idl_details): 448 for detail_name, idl_detail in all_idl_details.items(): 449 self.query_and_update_idl_type(idl_detail, all_idl_details) 450 451 # update interface idl file type if the file import by other idl file 452 def query_and_update_idl_type(self, idl_detail, all_idl_details): 453 for other_name, other_detail in all_idl_details.items(): 454 if idl_detail.full_name() == other_name: 455 continue 456 if self.imported_by_other_idl(idl_detail, other_detail) and idl_detail.idl_type == IdlType.INTERFACE: 457 idl_detail.idl_type = IdlType.CALL_INTERFACE 458 break 459 460 def imported_by_other_idl(self, idl_detail, other_detail): 461 for import_name in other_detail.imports: 462 if idl_detail.full_name() == import_name: 463 return True 464 return False 465 466 def parse_module_info(self, all_idl_details): 467 generator = CodeGenFactory.create_code_generate() 468 if generator is None: 469 return 470 ModuleInfo.out_dir = Option.gen_dir 471 self.parse_sources(all_idl_details, generator) 472 ModuleInfo.proxy_deps, ModuleInfo.stub_deps, ModuleInfo.header_deps = CodeGen.get_lib_deps(Option.imports) 473 474 def parse_sources(self, all_idl_details, generator): 475 ModuleInfo.include_dirs.add(Option.gen_dir) 476 for idl_detail in all_idl_details.values(): 477 ModuleInfo.package = idl_detail.package 478 ModuleInfo.version = idl_detail.version 479 ModuleInfo.include_dirs.add( 480 generator.parse_include_dirs(idl_detail.package)) 481 482 sources, proxy_sources, sub_sources = generator.gen_code( 483 idl_detail) 484 ModuleInfo.sources.extend(sources) 485 ModuleInfo.proxy_sources.extend(proxy_sources) 486 ModuleInfo.stub_sources.extend(sub_sources) 487 488 489# generate code file info of hdi 490class CodeGen(object): 491 492 def gen_code(self, idl_detail): 493 idl_detail 494 return [], [], [] 495 496 # package is 'ohos.hdi.foo.v1_0' 497 # -r ohos.hdi:./interface 498 # sub_package is foo.v1_0 499 @staticmethod 500 def get_sub_package(package): 501 if package.startswith(Option.root_package): 502 root_package_len = len(Option.root_package) 503 return package[root_package_len + 1:] 504 return package 505 506 @staticmethod 507 def get_package_path(package): 508 package_path = "" 509 if package.startswith(Option.root_package): 510 root_package_len = len(Option.root_package) 511 sub_package = package[root_package_len:] 512 sub_package_path = sub_package.replace(".", os.sep) 513 package_path = "{}{}".format(Option.root_path, sub_package_path) 514 else: 515 raise Exception("find root package '{}' failed in '{}'".format( 516 Option.root_package, package)) 517 518 return package_path 519 520 @staticmethod 521 def get_version(package): 522 major_version = 0 523 minor_version = 0 524 result = re.findall(r'\w+(?:\.\w+)*\.[V|v](\d+)_(\d+)', package) 525 if len(result) > 0: 526 major_version = result[0][0] 527 minor_version = result[0][1] 528 return major_version, minor_version 529 530 # transalte package name to include directory 531 @staticmethod 532 def parse_include_dirs(package): 533 sub_package = CodeGen.get_sub_package(package) 534 last_point_index = sub_package.rfind('.') 535 package_without_version = sub_package[:last_point_index] 536 package_dir_without_version = package_without_version.replace( 537 '.', os.sep) 538 return os.path.join(Option.gen_dir, package_dir_without_version) 539 540 # translate package name to directory 541 @staticmethod 542 def get_source_file_dir(package): 543 sub_package = CodeGen.get_sub_package(package) 544 sub_package_dir = "{}{}".format(sub_package.replace('.', os.sep), 545 os.sep) 546 return os.path.join(Option.gen_dir, sub_package_dir) 547 548 # translate idl file name to c/c++ file name 549 @staticmethod 550 def translate_file_name(file_name): 551 under_line = '_' 552 result = [] 553 name_len = len(file_name) 554 for index in range(name_len): 555 cur_char = file_name[index] 556 if cur_char.isupper(): 557 if index > 1: 558 result.append(under_line) 559 result.append(cur_char.lower()) 560 else: 561 result.append(cur_char) 562 return "".join(result) 563 564 @staticmethod 565 def translate_proxy_name(base_name): 566 temp_name = "{}Proxy".format(base_name) 567 return CodeGen.translate_file_name(temp_name) 568 569 @staticmethod 570 def translate_stub_name(base_name): 571 temp_name = "{}Stub".format(base_name) 572 return CodeGen.translate_file_name(temp_name) 573 574 @staticmethod 575 def translate_service_name(base_name): 576 temp_name = "{}Service".format(base_name) 577 return CodeGen.translate_file_name(temp_name) 578 579 @staticmethod 580 def translate_driver_name(base_name): 581 temp_name = "{}Driver".format(base_name) 582 return CodeGen.translate_file_name(temp_name) 583 584 @staticmethod 585 def get_type_names(name): 586 base_name = CodeGen.translate_file_name(name) 587 return base_name 588 589 # translate idl file name to c/c++ file name 590 # for example, IFoo -> ifoo, foo_proxy, foo_stub, foo_service, foo_driver, foo 591 @staticmethod 592 def get_file_names(idl_detail): 593 interface_name = "" 594 proxy_name = "" 595 stub_name = "" 596 service_name = "" 597 driver_name = "" 598 types_name = "" 599 600 if idl_detail.idl_type == IdlType.TYPES: 601 types_name = CodeGen.get_type_names(idl_detail.name) 602 return interface_name, proxy_name, stub_name, service_name, driver_name, types_name 603 604 base_name = idl_detail.name[1:] if idl_detail.name.startswith( 605 "I") else idl_detail.name 606 interface_name = CodeGen.translate_file_name(idl_detail.name) 607 proxy_name = CodeGen.translate_proxy_name(base_name) 608 stub_name = CodeGen.translate_stub_name(base_name) 609 service_name = CodeGen.translate_service_name(base_name) 610 driver_name = CodeGen.translate_driver_name(base_name) 611 if idl_detail.idl_type == IdlType.INTERFACE: 612 driver_name = CodeGen.translate_driver_name(base_name) 613 return interface_name, proxy_name, stub_name, service_name, driver_name, types_name 614 615 @staticmethod 616 def header_file(file_dir, name): 617 return os.path.join(file_dir, "{}.h".format(name)) 618 619 @staticmethod 620 def c_source_file(file_dir, name): 621 return os.path.join(file_dir, "{}.c".format(name)) 622 623 @staticmethod 624 def cpp_source_file(file_dir, name): 625 return os.path.join(file_dir, "{}.cpp".format(name)) 626 627 @staticmethod 628 def get_import(imp): 629 package = "" 630 module_name = "" 631 imp_result = imp.split(":") 632 if len(imp_result) == 2: 633 package = imp_result[0] 634 module_name = imp_result[1] 635 return package, module_name 636 637 # get lib deps from imports 638 @staticmethod 639 def get_lib_deps(imports): 640 proxy_deps = [] 641 stub_deps = [] 642 header_deps = [] 643 for imps in imports: 644 package, module_name = CodeGen.get_import(imps) 645 package_path = CodeGen.get_package_path(package) 646 major_version, minor_version = CodeGen.get_version(package) 647 proxy_lib_name = "lib{}_proxy_{}.{}".format(module_name, major_version, minor_version) 648 stub_lib_name = "lib{}_stub_{}.{}".format(module_name, major_version, minor_version) 649 header_config = "{}_idl_headers_{}.{}".format(module_name, major_version, minor_version) 650 proxy_lib_dep = "{}:{}".format(package_path, proxy_lib_name) 651 stub_lib_dep = "{}:{}".format(package_path, stub_lib_name) 652 header_dep = "{}:{}".format(package_path, header_config) 653 proxy_deps.append(proxy_lib_dep) 654 stub_deps.append(stub_lib_dep) 655 header_deps.append(header_dep) 656 return proxy_deps, stub_deps, header_deps 657 658 659class LowCCodeGen(CodeGen): 660 def gen_code(self, idl_detail): 661 file_dir = self.get_source_file_dir(idl_detail.package) 662 sources = [] 663 interface_name, _, _, service_name, driver_name, types_name = self.get_file_names(idl_detail) 664 if idl_detail.idl_type == IdlType.TYPES: 665 header_file = self.header_file(file_dir, types_name) 666 sources.append(header_file) 667 if idl_detail.idl_type == IdlType.INTERFACE: 668 header_file = self.header_file(file_dir, interface_name) 669 service_header_file = self.header_file(file_dir, service_name) 670 service_source_file = self.c_source_file(file_dir, service_name) 671 driver_source_file = self.c_source_file(file_dir, driver_name) 672 sources.extend([header_file, service_header_file, service_source_file, driver_source_file]) 673 return sources, [], [] 674 675 676class LowCppCodeGen(CodeGen): 677 def gen_code(self, idl_detail): 678 file_dir = self.get_source_file_dir(idl_detail.package) 679 sources = [] 680 interface_name, _, _, service_name, driver_name, types_name = self.get_file_names(idl_detail) 681 if idl_detail.idl_type == IdlType.TYPES: 682 header_file = self.header_file(file_dir, types_name) 683 sources.append(header_file) 684 if idl_detail.idl_type == IdlType.INTERFACE: 685 header_file = self.header_file(file_dir, interface_name) 686 service_header_file = self.header_file(file_dir, service_name) 687 service_source_file = self.cpp_source_file(file_dir, service_name) 688 driver_source_file = self.cpp_source_file(file_dir, driver_name) 689 sources.extend([header_file, service_header_file, service_source_file, driver_source_file]) 690 return sources, [], [] 691 692 693# generate kernel c code file info of hdi 694class KernelCodeGen(CodeGen): 695 def gen_code(self, idl_detail): 696 file_dir = self.get_source_file_dir(idl_detail.package) 697 sources = [] 698 proxy_sources = [] 699 stub_sources = [] 700 interface_name, proxy_name, stub_name, service_name, driver_name, types_name = self.get_file_names( 701 idl_detail) 702 if idl_detail.idl_type == IdlType.TYPES: 703 header_file = self.header_file(file_dir, types_name) 704 source_file = self.c_source_file(file_dir, types_name) 705 sources.extend([header_file, source_file]) 706 proxy_sources.append(source_file) 707 stub_sources.append(source_file) 708 return sources, proxy_sources, stub_sources 709 710 if idl_detail.idl_type == IdlType.INTERFACE: 711 iface_header_file = self.header_file(file_dir, interface_name) 712 proxy_source_file = self.c_source_file(file_dir, proxy_name) 713 stub_header_file = self.header_file(file_dir, stub_name) 714 stub_source_file = self.c_source_file(file_dir, stub_name) 715 service_header_file = self.header_file(file_dir, service_name) 716 service_source_file = self.c_source_file(file_dir, service_name) 717 driver_source_file = self.c_source_file(file_dir, driver_name) 718 sources.extend([ 719 iface_header_file, proxy_source_file, stub_header_file, 720 stub_source_file, service_header_file, service_source_file, 721 driver_source_file 722 ]) 723 proxy_sources.append(proxy_source_file) 724 stub_sources.append(stub_source_file) 725 return sources, proxy_sources, stub_sources 726 727 728# generate passthrough c code file info of hdi 729class PassthroughCCodeGen(CodeGen): 730 731 def gen_code(self, idl_detail): 732 file_dir = self.get_source_file_dir(idl_detail.package) 733 sources = [] 734 proxy_sources = [] 735 stub_sources = [] 736 interface_name, proxy_name, _, service_name, _, types_name = self.get_file_names( 737 idl_detail) 738 739 iface_header_file = self.header_file(file_dir, interface_name) 740 proxy_source_file = self.c_source_file(file_dir, proxy_name) 741 service_header_file = self.header_file(file_dir, service_name) 742 service_source_file = self.c_source_file(file_dir, service_name) 743 types_header_file = self.header_file(file_dir, types_name) 744 745 if idl_detail.idl_type == IdlType.INTERFACE: 746 sources.extend( 747 [iface_header_file, proxy_source_file, service_source_file]) 748 proxy_sources.append(proxy_source_file) 749 elif idl_detail.idl_type == IdlType.CALL_INTERFACE: 750 sources.extend( 751 [iface_header_file, service_header_file, service_source_file]) 752 elif idl_detail.idl_type == IdlType.CALLBACK: 753 sources.extend( 754 [iface_header_file, service_header_file, service_source_file]) 755 else: 756 sources.append(types_header_file) 757 return sources, proxy_sources, stub_sources 758 759 760# generate passthrough cpp code file info of hdi 761class PassthroughCppCodeGen(CodeGen): 762 763 def gen_code(self, idl_detail): 764 file_dir = self.get_source_file_dir(idl_detail.package) 765 sources = [] 766 proxy_sources = [] 767 stub_sources = [] 768 interface_name, proxy_name, _, service_name, _, types_name = self.get_file_names( 769 idl_detail) 770 iface_header_file = self.header_file(file_dir, interface_name) 771 proxy_source_file = self.cpp_source_file(file_dir, proxy_name) 772 service_header_file = self.header_file(file_dir, service_name) 773 service_source_file = self.cpp_source_file(file_dir, service_name) 774 types_header_file = self.header_file(file_dir, types_name) 775 776 if idl_detail.idl_type == IdlType.INTERFACE: 777 sources.extend([ 778 iface_header_file, proxy_source_file, service_header_file, 779 service_source_file 780 ]) 781 proxy_sources.append(proxy_source_file) 782 elif idl_detail.idl_type == IdlType.CALL_INTERFACE: 783 sources.extend( 784 [iface_header_file, service_header_file, service_source_file]) 785 elif idl_detail.idl_type == IdlType.CALLBACK: 786 sources.extend( 787 [iface_header_file, service_header_file, service_source_file]) 788 else: 789 sources.append(types_header_file) 790 return sources, proxy_sources, stub_sources 791 792 793# generate ipc c code file information of hdi 794class IpcCCodeGen(CodeGen): 795 796 def gen_code(self, idl_detail): 797 file_dir = self.get_source_file_dir(idl_detail.package) 798 sources = [] 799 proxy_sources = [] 800 stub_sources = [] 801 interface_name, proxy_name, stub_name, service_name, driver_name, types_name = self.get_file_names( 802 idl_detail) 803 iface_header_file = self.header_file(file_dir, interface_name) 804 proxy_source_file = self.c_source_file(file_dir, proxy_name) 805 stub_header_file = self.header_file(file_dir, stub_name) 806 stub_source_file = self.c_source_file(file_dir, stub_name) 807 service_header_file = self.header_file(file_dir, service_name) 808 service_source_file = self.c_source_file(file_dir, service_name) 809 driver_source_file = self.c_source_file(file_dir, driver_name) 810 types_header_file = self.header_file(file_dir, types_name) 811 types_source_file = self.c_source_file(file_dir, types_name) 812 813 if idl_detail.idl_type == IdlType.INTERFACE: 814 sources.extend([ 815 iface_header_file, proxy_source_file, stub_header_file, 816 stub_source_file, service_source_file, driver_source_file 817 ]) 818 proxy_sources.append(proxy_source_file) 819 stub_sources.append(stub_source_file) 820 elif idl_detail.idl_type == IdlType.CALL_INTERFACE: 821 sources.extend([ 822 iface_header_file, proxy_source_file, stub_header_file, 823 stub_source_file, service_header_file, service_source_file 824 ]) 825 proxy_sources.append(proxy_source_file) 826 stub_sources.append(stub_source_file) 827 elif idl_detail.idl_type == IdlType.CALLBACK: 828 sources.extend([ 829 iface_header_file, proxy_source_file, stub_header_file, 830 stub_source_file, service_header_file, service_source_file 831 ]) 832 proxy_sources.append(stub_source_file) 833 stub_sources.append(proxy_source_file) 834 else: 835 sources.extend([types_header_file, types_source_file]) 836 proxy_sources.append(types_source_file) 837 stub_sources.append(types_source_file) 838 return sources, proxy_sources, stub_sources 839 840 841# generate ipc cpp code file information of hdi 842class IpcCppCodeGen(CodeGen): 843 844 def gen_code(self, idl_detail): 845 file_dir = self.get_source_file_dir(idl_detail.package) 846 sources = [] 847 proxy_sources = [] 848 stub_sources = [] 849 interface_name, proxy_name, stub_name, service_name, driver_name, types_name = self.get_file_names( 850 idl_detail) 851 iface_header_file = self.header_file(file_dir, interface_name) 852 proxy_header_file = self.header_file(file_dir, proxy_name) 853 proxy_source_file = self.cpp_source_file(file_dir, proxy_name) 854 stub_header_file = self.header_file(file_dir, stub_name) 855 stub_source_file = self.cpp_source_file(file_dir, stub_name) 856 service_header_file = self.header_file(file_dir, service_name) 857 service_source_file = self.cpp_source_file(file_dir, service_name) 858 driver_source_file = self.cpp_source_file(file_dir, driver_name) 859 types_header_file = self.header_file(file_dir, types_name) 860 types_source_file = self.cpp_source_file(file_dir, types_name) 861 862 if idl_detail.idl_type == IdlType.INTERFACE: 863 sources.extend([ 864 iface_header_file, proxy_header_file, proxy_source_file, 865 stub_header_file, stub_source_file, service_header_file, 866 service_source_file, driver_source_file 867 ]) 868 proxy_sources.append(proxy_source_file) 869 stub_sources.append(stub_source_file) 870 elif idl_detail.idl_type == IdlType.CALL_INTERFACE: 871 sources.extend([ 872 iface_header_file, proxy_header_file, proxy_source_file, 873 stub_header_file, stub_source_file, service_header_file, 874 service_source_file 875 ]) 876 proxy_sources.append(proxy_source_file) 877 stub_sources.append(stub_source_file) 878 elif idl_detail.idl_type == IdlType.CALLBACK: 879 sources.extend([ 880 iface_header_file, proxy_header_file, proxy_source_file, 881 stub_header_file, stub_source_file, service_header_file, 882 service_source_file 883 ]) 884 proxy_sources.append(stub_source_file) 885 stub_sources.append(proxy_source_file) 886 else: 887 sources.extend([types_header_file, types_source_file]) 888 proxy_sources.append(types_source_file) 889 stub_sources.append(types_source_file) 890 return sources, proxy_sources, stub_sources 891 892 893class CodeGenFactory(object): 894 action_config = { 895 "mini": { 896 "low": { 897 "c": LowCCodeGen(), 898 "cpp": LowCppCodeGen() 899 } 900 }, 901 "lite": { 902 "kernel": { 903 "c": KernelCodeGen() 904 }, 905 "passthrough": { 906 "c": PassthroughCCodeGen(), 907 "cpp": PassthroughCppCodeGen() 908 } 909 }, 910 "full": { 911 "kernel": { 912 "c": KernelCodeGen() 913 }, 914 "passthrough": { 915 "c": PassthroughCCodeGen(), 916 "cpp": PassthroughCppCodeGen() 917 }, 918 "ipc": { 919 "c": IpcCCodeGen(), 920 "cpp": IpcCppCodeGen() 921 } 922 } 923 } 924 925 @staticmethod 926 def create_code_generate(): 927 if Option.system not in CodeGenFactory.action_config: 928 raise Exception("the '{}' system is not supported".format( 929 Option.system)) 930 system_action = CodeGenFactory.action_config.get( 931 Option.system) 932 if Option.mode not in system_action: 933 raise Exception( 934 "the '{}' mode is not supported by '{}' system".format( 935 Option.mode, Option.system)) 936 mode_action = system_action.get(Option.mode) 937 if Option.language not in mode_action: 938 raise Exception( 939 "the '{}' language is not support by '{}' mode of '{}' system" 940 .format(Option.language, Option.mode, Option.system)) 941 return mode_action.get(Option.language) 942 943 944def check_python_version(): 945 if sys.version_info < (3, 0): 946 raise Exception("Please run with python version >= 3.0") 947 948 949if __name__ == "__main__": 950 check_python_version() 951 option_parser = argparse.ArgumentParser( 952 description="Tools for generating compilation infomation of idl files", 953 ) 954 955 option_parser.add_argument("-s", 956 "--system", 957 choices=["mini", "lite", "full"], 958 default="full", 959 help="system: mini, lite, full") 960 961 option_parser.add_argument( 962 "-m", 963 "--mode", 964 choices=["ipc", "passthrough", "kernel", "low"], 965 default="ipc", 966 help="generate code of ipc, passthrough or kernel mode") 967 968 option_parser.add_argument("-l", 969 "--language", 970 required=True, 971 choices=["c", "cpp"], 972 help="language of generating code") 973 974 option_parser.add_argument("-o", 975 "--out", 976 required=True, 977 default=".", 978 help="direstory of generate file") 979 980 option_parser.add_argument("-r", 981 "--root", 982 required=True, 983 help="mapping path: <root package>:<path>") 984 985 option_parser.add_argument("-f", 986 "--file", 987 required=True, 988 action="append", 989 help="the idl file") 990 991 option_parser.add_argument("--imports", 992 action="append", 993 help="the imports") 994 995 Option.load(option_parser.parse_args()) 996 idl_parser = IdlParser() 997 idl_parser.parse() 998 sys.stdout.write(ModuleInfo.json_info()) 999 sys.stdout.flush() 1000