1#!/usr/bin/env python3 2# 3# Copyright 2019 - The Android Open Source Project 4# 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 17"""It is an AIDEGen sub task: generate the CLion project file. 18 19 Usage example: 20 json_path = common_util.get_blueprint_json_path( 21 constant.BLUEPRINT_CC_JSONFILE_NAME) 22 json_dict = common_util.get_soong_build_json_dict(json_path) 23 if 'modules' not in json_dict: 24 return 25 mod_info = json_dict['modules'].get('libui', {}) 26 if not mod_info: 27 return 28 CLionProjectFileGenerator(mod_info).generate_cmakelists_file() 29""" 30 31import logging 32import os 33 34from io import StringIO 35from io import TextIOWrapper 36 37from aidegen import constant 38from aidegen import templates 39from aidegen.lib import common_util 40from aidegen.lib import errors 41from aidegen.lib import native_module_info 42 43# Flags for writing to CMakeLists.txt section. 44_GLOBAL_COMMON_FLAGS = '\n# GLOBAL ALL FLAGS:\n' 45_LOCAL_COMMON_FLAGS = '\n# LOCAL ALL FLAGS:\n' 46_GLOBAL_CFLAGS = '\n# GLOBAL CFLAGS:\n' 47_LOCAL_CFLAGS = '\n# LOCAL CFLAGS:\n' 48_GLOBAL_C_ONLY_FLAGS = '\n# GLOBAL C ONLY FLAGS:\n' 49_LOCAL_C_ONLY_FLAGS = '\n# LOCAL C ONLY FLAGS:\n' 50_GLOBAL_CPP_FLAGS = '\n# GLOBAL CPP FLAGS:\n' 51_LOCAL_CPP_FLAGS = '\n# LOCAL CPP FLAGS:\n' 52_SYSTEM_INCLUDE_FLAGS = '\n# GLOBAL SYSTEM INCLUDE FLAGS:\n' 53 54# Keys for writing in module_bp_cc_deps.json 55_KEY_GLOBAL_COMMON_FLAGS = 'global_common_flags' 56_KEY_LOCAL_COMMON_FLAGS = 'local_common_flags' 57_KEY_GLOBAL_CFLAGS = 'global_c_flags' 58_KEY_LOCAL_CFLAGS = 'local_c_flags' 59_KEY_GLOBAL_C_ONLY_FLAGS = 'global_c_only_flags' 60_KEY_LOCAL_C_ONLY_FLAGS = 'local_c_only_flags' 61_KEY_GLOBAL_CPP_FLAGS = 'global_cpp_flags' 62_KEY_LOCAL_CPP_FLAGS = 'local_cpp_flags' 63_KEY_SYSTEM_INCLUDE_FLAGS = 'system_include_flags' 64 65# Dictionary maps keys to sections. 66_FLAGS_DICT = { 67 _KEY_GLOBAL_COMMON_FLAGS: _GLOBAL_COMMON_FLAGS, 68 _KEY_LOCAL_COMMON_FLAGS: _LOCAL_COMMON_FLAGS, 69 _KEY_GLOBAL_CFLAGS: _GLOBAL_CFLAGS, 70 _KEY_LOCAL_CFLAGS: _LOCAL_CFLAGS, 71 _KEY_GLOBAL_C_ONLY_FLAGS: _GLOBAL_C_ONLY_FLAGS, 72 _KEY_LOCAL_C_ONLY_FLAGS: _LOCAL_C_ONLY_FLAGS, 73 _KEY_GLOBAL_CPP_FLAGS: _GLOBAL_CPP_FLAGS, 74 _KEY_LOCAL_CPP_FLAGS: _LOCAL_CPP_FLAGS, 75 _KEY_SYSTEM_INCLUDE_FLAGS: _SYSTEM_INCLUDE_FLAGS 76} 77 78# Keys for parameter types. 79_KEY_FLAG = 'flag' 80_KEY_SYSTEM_ROOT = 'system_root' 81_KEY_RELATIVE = 'relative_file_path' 82 83# Constants for CMakeLists.txt. 84_MIN_VERSION_TOKEN = '@MINVERSION@' 85_PROJECT_NAME_TOKEN = '@PROJNAME@' 86_ANDOIR_ROOT_TOKEN = '@ANDROIDROOT@' 87_MINI_VERSION_SUPPORT = 'cmake_minimum_required(VERSION {})\n' 88_MINI_VERSION = '3.5' 89_KEY_CLANG = 'clang' 90_KEY_CPPLANG = 'clang++' 91_SET_C_COMPILER = 'set(CMAKE_C_COMPILER \"{}\")\n' 92_SET_CXX_COMPILER = 'set(CMAKE_CXX_COMPILER \"{}\")\n' 93_LIST_APPEND_HEADER = 'list(APPEND\n' 94_SOURCE_FILES_HEADER = 'SOURCE_FILES' 95_SOURCE_FILES_LINE = ' SOURCE_FILES\n' 96_END_WITH_ONE_BLANK_LINE = ')\n' 97_END_WITH_TWO_BLANK_LINES = ')\n\n' 98_SET_RELATIVE_PATH = 'set({} "{} {}={}")\n' 99_SET_ALL_FLAGS = 'set({} "{} {}")\n' 100_ANDROID_ROOT_SYMBOL = '${ANDROID_ROOT}' 101_SYSTEM = 'SYSTEM' 102_INCLUDE_DIR = 'include_directories({} \n' 103_SET_INCLUDE_FORMAT = ' "{}"\n' 104_CMAKE_C_FLAGS = 'CMAKE_C_FLAGS' 105_CMAKE_CXX_FLAGS = 'CMAKE_CXX_FLAGS' 106_USR = 'usr' 107_INCLUDE = 'include' 108_INCLUDE_SYSTEM = 'include_directories(SYSTEM "{}")\n' 109_GLOB_RECURSE_TMP_HEADERS = 'file (GLOB_RECURSE TMP_HEADERS\n' 110_ALL_HEADER_FILES = ' "{}/**/*.h"\n' 111_APPEND_SOURCE_FILES = "list (APPEND SOURCE_FILES ${TMP_HEADERS})\n\n" 112_ADD_EXECUTABLE_HEADER = '\nadd_executable({} {})' 113_PROJECT = 'project({})\n' 114_ADD_SUB = 'add_subdirectory({})\n' 115_DICT_EMPTY = 'mod_info is empty.' 116_DICT_NO_MOD_NAME_KEY = "mod_info does not contain 'module_name' key." 117_DICT_NO_PATH_KEY = "mod_info does not contain 'path' key." 118_MODULE_INFO_EMPTY = 'The module info dictionary is empty.' 119 120 121class CLionProjectFileGenerator: 122 """CLion project file generator. 123 124 Attributes: 125 mod_info: A dictionary of the target module's info. 126 mod_name: A string of module name. 127 mod_path: A string of module's path. 128 cc_dir: A string of generated CLion project file's directory. 129 cc_path: A string of generated CLion project file's path. 130 """ 131 132 def __init__(self, mod_info, parent_dir=None): 133 """ProjectFileGenerator initialize. 134 135 Args: 136 mod_info: A dictionary of native module's info. 137 parent_dir: The parent directory of this native module. The default 138 value is None. 139 """ 140 if not mod_info: 141 raise errors.ModuleInfoEmptyError(_MODULE_INFO_EMPTY) 142 self.mod_info = mod_info 143 self.mod_name = self._get_module_name() 144 self.mod_path = CLionProjectFileGenerator.get_module_path( 145 mod_info, parent_dir) 146 self.cc_dir = CLionProjectFileGenerator.get_cmakelists_file_dir( 147 os.path.join(self.mod_path, self.mod_name)) 148 if not os.path.exists(self.cc_dir): 149 os.makedirs(self.cc_dir) 150 self.cc_path = os.path.join(self.cc_dir, 151 constant.CLION_PROJECT_FILE_NAME) 152 153 def _get_module_name(self): 154 """Gets the value of the 'module_name' key if it exists. 155 156 Returns: 157 A string of the module's name. 158 159 Raises: 160 NoModuleNameDefinedInModuleInfoError if no 'module_name' key in 161 mod_info. 162 """ 163 mod_name = self.mod_info.get(constant.KEY_MODULE_NAME, '') 164 if not mod_name: 165 raise errors.NoModuleNameDefinedInModuleInfoError( 166 _DICT_NO_MOD_NAME_KEY) 167 return mod_name 168 169 @staticmethod 170 def get_module_path(mod_info, parent_dir=None): 171 """Gets the correct value of the 'path' key if it exists. 172 173 When a module with different paths, e.g., 174 'libqcomvoiceprocessingdescriptors': { 175 'path': [ 176 'device/google/bonito/voice_processing', 177 'device/google/coral/voice_processing', 178 'device/google/crosshatch/voice_processing', 179 'device/google/muskie/voice_processing', 180 'device/google/taimen/voice_processing' 181 ], 182 ... 183 } 184 it might be wrong if we always choose the first path. For example, in 185 this case if users command 'aidegen -i c device/google/coral' the 186 correct path they need should be the second one. 187 188 Args: 189 mod_info: A module's info dictionary. 190 parent_dir: The parent directory of this native module. The default 191 value is None. 192 193 Returns: 194 A string of the module's path. 195 196 Raises: 197 NoPathDefinedInModuleInfoError if no 'path' key in mod_info. 198 """ 199 mod_paths = mod_info.get(constant.KEY_PATH, []) 200 if not mod_paths: 201 raise errors.NoPathDefinedInModuleInfoError(_DICT_NO_PATH_KEY) 202 mod_path = mod_paths[0] 203 if parent_dir and len(mod_paths) > 1: 204 for path in mod_paths: 205 if common_util.is_source_under_relative_path(path, parent_dir): 206 mod_path = path 207 return mod_path 208 209 @staticmethod 210 @common_util.check_args(cc_path=str) 211 def get_cmakelists_file_dir(cc_path): 212 """Gets module's CMakeLists.txt file path to be created. 213 214 Return a string of $OUT/development/ide/clion/${cc_path}. 215 For example, if module name is 'libui'. The return path string would be: 216 out/development/ide/clion/frameworks/native/libs/ui/libui 217 218 Args: 219 cc_path: A string of absolute path of module's Android.bp file. 220 221 Returns: 222 A string of absolute path of module's CMakeLists.txt file to be 223 created. 224 """ 225 return os.path.join(common_util.get_android_root_dir(), 226 common_util.get_android_out_dir(), 227 constant.RELATIVE_NATIVE_PATH, cc_path) 228 229 def generate_cmakelists_file(self): 230 """Generates CLion project file from the target module's info.""" 231 with open(self.cc_path, 'w') as hfile: 232 self._write_cmakelists_file(hfile) 233 234 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 235 @common_util.io_error_handle 236 def _write_cmakelists_file(self, hfile): 237 """Writes CLion project file content with neccessary info. 238 239 Args: 240 hfile: A file handler instance. 241 """ 242 self._write_header(hfile) 243 self._write_c_compiler_paths(hfile) 244 self._write_source_files(hfile) 245 self._write_cmakelists_flags(hfile) 246 self._write_tail(hfile) 247 248 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 249 @common_util.io_error_handle 250 def _write_header(self, hfile): 251 """Writes CLion project file's header messages. 252 253 Args: 254 hfile: A file handler instance. 255 """ 256 content = templates.CMAKELISTS_HEADER.replace( 257 _MIN_VERSION_TOKEN, _MINI_VERSION) 258 content = content.replace(_PROJECT_NAME_TOKEN, self.mod_name) 259 content = content.replace( 260 _ANDOIR_ROOT_TOKEN, common_util.get_android_root_dir()) 261 hfile.write(content) 262 263 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 264 @common_util.io_error_handle 265 def _write_c_compiler_paths(self, hfile): 266 """Writes CMake compiler paths for C and Cpp to CLion project file. 267 268 Args: 269 hfile: A file handler instance. 270 """ 271 hfile.write(_SET_C_COMPILER.format( 272 native_module_info.NativeModuleInfo.c_lang_path)) 273 hfile.write(_SET_CXX_COMPILER.format( 274 native_module_info.NativeModuleInfo.cpp_lang_path)) 275 276 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 277 @common_util.io_error_handle 278 def _write_source_files(self, hfile): 279 """Writes source files' paths to CLion project file. 280 281 Args: 282 hfile: A file handler instance. 283 """ 284 if constant.KEY_SRCS not in self.mod_info: 285 logging.warning("No source files in %s's module info.", 286 self.mod_name) 287 return 288 source_files = self.mod_info[constant.KEY_SRCS] 289 hfile.write(_LIST_APPEND_HEADER) 290 hfile.write(_SOURCE_FILES_LINE) 291 for src in source_files: 292 hfile.write(''.join([_build_cmake_path(src, ' '), '\n'])) 293 hfile.write(_END_WITH_ONE_BLANK_LINE) 294 295 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 296 @common_util.io_error_handle 297 def _write_cmakelists_flags(self, hfile): 298 """Writes all kinds of flags in CLion project file. 299 300 Args: 301 hfile: A file handler instance. 302 """ 303 self._write_flags(hfile, _KEY_GLOBAL_COMMON_FLAGS, True, True) 304 self._write_flags(hfile, _KEY_LOCAL_COMMON_FLAGS, True, True) 305 self._write_flags(hfile, _KEY_GLOBAL_CFLAGS, True, True) 306 self._write_flags(hfile, _KEY_LOCAL_CFLAGS, True, True) 307 self._write_flags(hfile, _KEY_GLOBAL_C_ONLY_FLAGS, True, False) 308 self._write_flags(hfile, _KEY_LOCAL_C_ONLY_FLAGS, True, False) 309 self._write_flags(hfile, _KEY_GLOBAL_CPP_FLAGS, False, True) 310 self._write_flags(hfile, _KEY_LOCAL_CPP_FLAGS, False, True) 311 self._write_flags(hfile, _KEY_SYSTEM_INCLUDE_FLAGS, True, True) 312 313 @common_util.check_args(hfile=(TextIOWrapper, StringIO)) 314 @common_util.io_error_handle 315 def _write_tail(self, hfile): 316 """Writes CLion project file content with necessary info. 317 318 Args: 319 hfile: A file handler instance. 320 """ 321 hfile.write( 322 _ADD_EXECUTABLE_HEADER.format( 323 _cleanup_executable_name(self.mod_name), 324 _add_dollar_sign(_SOURCE_FILES_HEADER))) 325 326 @common_util.check_args( 327 hfile=(TextIOWrapper, StringIO), key=str, cflags=bool, cppflags=bool) 328 @common_util.io_error_handle 329 def _write_flags(self, hfile, key, cflags, cppflags): 330 """Writes CMake compiler paths of C, Cpp for different kinds of flags. 331 332 Args: 333 hfile: A file handler instance. 334 key: A string of flag type, e.g., 'global_common_flags' flag. 335 cflags: A boolean for setting 'CMAKE_C_FLAGS' flag. 336 cppflags: A boolean for setting 'CMAKE_CXX_FLAGS' flag. 337 """ 338 if key not in _FLAGS_DICT: 339 return 340 hfile.write(_FLAGS_DICT[key]) 341 params_dict = self._parse_compiler_parameters(key) 342 if params_dict: 343 _translate_to_cmake(hfile, params_dict, cflags, cppflags) 344 345 @common_util.check_args(flag=str) 346 def _parse_compiler_parameters(self, flag): 347 """Parses the specific flag data from a module_info dictionary. 348 349 Args: 350 flag: The string of key flag, e.g.: _KEY_GLOBAL_COMMON_FLAGS. 351 352 Returns: 353 A dictionary with compiled parameters. 354 """ 355 params = self.mod_info.get(flag, {}) 356 if not params: 357 return None 358 params_dict = { 359 constant.KEY_HEADER: [], 360 constant.KEY_SYSTEM: [], 361 _KEY_FLAG: [], 362 _KEY_SYSTEM_ROOT: '', 363 _KEY_RELATIVE: {} 364 } 365 for key, value in params.items(): 366 params_dict[key] = value 367 return params_dict 368 369 370@common_util.check_args(rel_project_path=str, mod_names=list) 371@common_util.io_error_handle 372def generate_base_cmakelists_file(cc_module_info, rel_project_path, mod_names): 373 """Generates base CLion project file for multiple CLion projects. 374 375 We create a multiple native project file: 376 {android_root}/development/ide/clion/{rel_project_path}/CMakeLists.txt 377 and use this project file to generate a link: 378 {android_root}/out/development/ide/clion/{rel_project_path}/CMakeLists.txt 379 380 Args: 381 cc_module_info: An instance of native_module_info.NativeModuleInfo. 382 rel_project_path: A string of the base project relative path. For 383 example: frameworks/native/libs/ui. 384 mod_names: A list of module names whose project were created under 385 rel_project_path. 386 387 Returns: 388 A symbolic link CLion project file path. 389 """ 390 root_dir = common_util.get_android_root_dir() 391 cc_dir = os.path.join(root_dir, constant.RELATIVE_NATIVE_PATH, 392 rel_project_path) 393 cc_out_dir = os.path.join(root_dir, common_util.get_android_out_dir(), 394 constant.RELATIVE_NATIVE_PATH, rel_project_path) 395 if not os.path.exists(cc_dir): 396 os.makedirs(cc_dir) 397 dst_path = os.path.join(cc_out_dir, constant.CLION_PROJECT_FILE_NAME) 398 if os.path.islink(dst_path): 399 os.unlink(dst_path) 400 src_path = os.path.join(cc_dir, constant.CLION_PROJECT_FILE_NAME) 401 if os.path.isfile(src_path): 402 os.remove(src_path) 403 with open(src_path, 'w') as hfile: 404 _write_base_cmakelists_file(hfile, cc_module_info, src_path, mod_names) 405 os.symlink(src_path, dst_path) 406 return dst_path 407 408 409@common_util.check_args( 410 hfile=(TextIOWrapper, StringIO), abs_project_path=str, mod_names=list) 411@common_util.io_error_handle 412def _write_base_cmakelists_file(hfile, cc_module_info, abs_project_path, 413 mod_names): 414 """Writes base CLion project file content. 415 416 When we write module info into base CLion project file, first check if the 417 module's CMakeLists.txt exists. If file exists, write content, 418 add_subdirectory({'relative_module_path'}) 419 420 Args: 421 hfile: A file handler instance. 422 cc_module_info: An instance of native_module_info.NativeModuleInfo. 423 abs_project_path: A string of the base project absolute path. 424 For example, 425 ${ANDROID_BUILD_TOP}/frameworks/native/libs/ui. 426 mod_names: A list of module names whose project were created under 427 abs_project_path. 428 """ 429 hfile.write(_MINI_VERSION_SUPPORT.format(_MINI_VERSION)) 430 project_dir = os.path.dirname(abs_project_path) 431 hfile.write(_PROJECT.format(os.path.basename(project_dir))) 432 root_dir = common_util.get_android_root_dir() 433 parent_dir = os.path.relpath(abs_project_path, root_dir) 434 for mod_name in mod_names: 435 mod_info = cc_module_info.get_module_info(mod_name) 436 mod_path = CLionProjectFileGenerator.get_module_path( 437 mod_info, parent_dir) 438 file_dir = CLionProjectFileGenerator.get_cmakelists_file_dir( 439 os.path.join(mod_path, mod_name)) 440 file_path = os.path.join(file_dir, constant.CLION_PROJECT_FILE_NAME) 441 if not os.path.isfile(file_path): 442 logging.warning("%s the project file %s doesn't exist.", 443 common_util.COLORED_INFO('Warning:'), file_path) 444 continue 445 link_project_dir = os.path.join(root_dir, 446 common_util.get_android_out_dir(), 447 os.path.relpath(project_dir, root_dir)) 448 rel_mod_path = os.path.relpath(file_dir, link_project_dir) 449 hfile.write(_ADD_SUB.format(rel_mod_path)) 450 451 452@common_util.check_args( 453 hfile=(TextIOWrapper, StringIO), params_dict=dict, cflags=bool, 454 cppflags=bool) 455def _translate_to_cmake(hfile, params_dict, cflags, cppflags): 456 """Translates parameter dict's contents into CLion project file format. 457 458 Args: 459 hfile: A file handler instance. 460 params_dict: A dict contains data to be translated into CLion 461 project file format. 462 cflags: A boolean is to set 'CMAKE_C_FLAGS' flag. 463 cppflags: A boolean is to set 'CMAKE_CXX_FLAGS' flag. 464 """ 465 _write_all_include_directories( 466 hfile, params_dict[constant.KEY_SYSTEM], True) 467 _write_all_include_directories( 468 hfile, params_dict[constant.KEY_HEADER], False) 469 470 if cflags: 471 _write_all_relative_file_path_flags(hfile, params_dict[_KEY_RELATIVE], 472 _CMAKE_C_FLAGS) 473 _write_all_flags(hfile, params_dict[_KEY_FLAG], _CMAKE_C_FLAGS) 474 475 if cppflags: 476 _write_all_relative_file_path_flags(hfile, params_dict[_KEY_RELATIVE], 477 _CMAKE_CXX_FLAGS) 478 _write_all_flags(hfile, params_dict[_KEY_FLAG], _CMAKE_CXX_FLAGS) 479 480 if params_dict[_KEY_SYSTEM_ROOT]: 481 path = os.path.join(params_dict[_KEY_SYSTEM_ROOT], _USR, _INCLUDE) 482 hfile.write(_INCLUDE_SYSTEM.format(_build_cmake_path(path))) 483 484 485@common_util.check_args(hfile=(TextIOWrapper, StringIO), is_system=bool) 486@common_util.io_error_handle 487def _write_all_include_directories(hfile, includes, is_system): 488 """Writes all included directories' paths to the CLion project file. 489 490 Args: 491 hfile: A file handler instance. 492 includes: A list of included file paths. 493 is_system: A boolean of whether it's a system flag. 494 """ 495 if not includes: 496 return 497 _write_all_includes(hfile, includes, is_system) 498 _write_all_headers(hfile, includes) 499 500 501@common_util.check_args( 502 hfile=(TextIOWrapper, StringIO), rel_paths_dict=dict, tag=str) 503@common_util.io_error_handle 504def _write_all_relative_file_path_flags(hfile, rel_paths_dict, tag): 505 """Writes all relative file path flags' parameters. 506 507 Args: 508 hfile: A file handler instance. 509 rel_paths_dict: A dict contains data of flag as a key and the relative 510 path string as its value. 511 tag: A string of tag, such as 'CMAKE_C_FLAGS'. 512 """ 513 for flag, path in rel_paths_dict.items(): 514 hfile.write( 515 _SET_RELATIVE_PATH.format(tag, _add_dollar_sign(tag), flag, 516 _build_cmake_path(path))) 517 518 519@common_util.check_args(hfile=(TextIOWrapper, StringIO), flags=list, tag=str) 520@common_util.io_error_handle 521def _write_all_flags(hfile, flags, tag): 522 """Wrties all flags to the project file. 523 524 Args: 525 hfile: A file handler instance. 526 flags: A list of flag strings to be added. 527 tag: A string to be added a dollar sign. 528 """ 529 for flag in flags: 530 hfile.write(_SET_ALL_FLAGS.format(tag, _add_dollar_sign(tag), flag)) 531 532 533def _add_dollar_sign(tag): 534 """Adds dollar sign to a string, e.g.: 'ANDROID_ROOT' -> '${ANDROID_ROOT}'. 535 536 Args: 537 tag: A string to be added a dollar sign. 538 539 Returns: 540 A dollar sign added string. 541 """ 542 return ''.join(['${', tag, '}']) 543 544 545def _build_cmake_path(path, tag=''): 546 """Joins tag, '${ANDROID_ROOT}' and path into a new string. 547 548 Args: 549 path: A string of a path. 550 tag: A string to be added in front of a dollar sign 551 552 Returns: 553 The composed string. 554 """ 555 return ''.join([tag, _ANDROID_ROOT_SYMBOL, os.path.sep, path]) 556 557 558@common_util.check_args(hfile=(TextIOWrapper, StringIO), is_system=bool) 559@common_util.io_error_handle 560def _write_all_includes(hfile, includes, is_system): 561 """Writes all included directories' paths to the CLion project file. 562 563 Args: 564 hfile: A file handler instance. 565 includes: A list of included file paths. 566 is_system: A boolean of whether it's a system flag. 567 """ 568 if not includes: 569 return 570 system = '' 571 if is_system: 572 system = _SYSTEM 573 hfile.write(_INCLUDE_DIR.format(system)) 574 for include in includes: 575 hfile.write(_SET_INCLUDE_FORMAT.format(_build_cmake_path(include))) 576 hfile.write(_END_WITH_TWO_BLANK_LINES) 577 578 579@common_util.check_args(hfile=(TextIOWrapper, StringIO)) 580@common_util.io_error_handle 581def _write_all_headers(hfile, includes): 582 """Writes all header directories' paths to the CLion project file. 583 584 Args: 585 hfile: A file handler instance. 586 includes: A list of included file paths. 587 """ 588 if not includes: 589 return 590 hfile.write(_GLOB_RECURSE_TMP_HEADERS) 591 for include in includes: 592 hfile.write(_ALL_HEADER_FILES.format(_build_cmake_path(include))) 593 hfile.write(_END_WITH_ONE_BLANK_LINE) 594 hfile.write(_APPEND_SOURCE_FILES) 595 596 597def _cleanup_executable_name(mod_name): 598 """Clean up an executable name to be suitable for CMake. 599 600 Replace the last '@' of a module name with '-' and make it become a suitable 601 executable name for CMake. 602 603 Args: 604 mod_name: A string of module name to be cleaned up. 605 606 Returns: 607 A string of the executable name. 608 """ 609 return mod_name[::-1].replace('@', '-', 1)[::-1] 610