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