• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# This file is part of the openHiTLS project.
4#
5# openHiTLS is licensed under the Mulan PSL v2.
6# You can use this software according to the terms and conditions of the Mulan PSL v2.
7# You may obtain a copy of Mulan PSL v2 at:
8#
9#     http://license.coscl.org.cn/MulanPSL2
10#
11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
12# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
13# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
14# See the Mulan PSL v2 for more details.
15"""
16Customize the openHiTLS build.
17Generate the modules.cmake file based on command line arguments and configuration files.
18
19Options usage and examples:
201 Enable the feature on demand and specify the implementation type of the feature, c or assembly.
21    # Use 'enable' to specify the features to be constructed.
22    # Compile C code if there is no other parameter.
23    ./configure.py --enable all                                        # Build all features of openHiTLS.
24    ./configure.py --enable hitls_crypto                               # Build all features in the lib hitls_crypto.
25    ./configure.py --enable md                                         # Build all sub features of md.
26    ./configure.py --enable sha2 sha3 hmac                             # Specifies to build certain features.
27
28    # Use 'enable' to specify the features to be constructed.
29    # Use 'asm_type' to specify the assembly type.
30    # If there are features in enable list that supports assembly, compile its assembly implementation.
31    ./configure.py --enable sm3 aes ... --asm_type armv8
32
33    # Use 'enable' to specify the features to be constructed.
34    # Use 'asm_type' to specify the assembly type.
35    # Use 'asm' to specify the assembly feature(s), which is(are) based on the enabled features.
36    # Compile the assembly code of the features in the asm, and the C code of other features in the enable list.
37    ./configure.py --enable sm3 aes ... --asm_type armv8 --asm sm3
38
392 Compile options: Add or delete compilation options based on the default compilation options (compile.json).
40    ./configure.py --add_options "-O0 -g" --del_options "-O2 -D_FORTIFY_SOURCE=2"
41
423 Link options: Add or delete link options based on the default link options (compile.json).
43    ./configure.py --add_link_flags "xxx xxx" --del_link_flags "xxx xxx"
44
454 Set the endian mode of the system. Set the endian mode of the system. The default value is little endian.
46    ./configure.py --endian big
47
485 Specifies the system type.
49    ./configure.py --system linux
50
516 Specifies the number of system bits.
52    ./configure.py --bits 32
53
547 Generating modules.cmake
55    ./configure.py -m
56
578 Specifies the directory where the compilation middleware is generated. The default directory is ./output.
58    ./configure.py --build_dir build
59
609 Specifies the lib type.
61    ./configure.py --lib_type static
62    ./configure.py --lib_type static shared object
63
6410 You can directly specify the compilation configuration files, omitting the above 1~9 command line parameters.
65   For the file format, please refer to the compile_config.json and feature_config.json files generated after executing
66   the above 1~9 commands.
67    ./configure.py --feature_config path/to/xxx.json --compile_config path/to/xxx.json
68
69Note:
70    Options for different functions can be combined.
71"""
72
73import sys
74sys.dont_write_bytecode = True
75import os
76import argparse
77import traceback
78import glob
79from script.methods import copy_file, save_json_file, trans2list
80from script.config_parser import (FeatureParser, CompileParser, FeatureConfigParser,
81                                  CompileConfigParser, CompleteOptionParser)
82
83srcdir = os.path.dirname(os.path.realpath(sys.argv[0]))
84work_dir = os.path.abspath(os.getcwd())
85
86def get_cfg_args():
87    parser = argparse.ArgumentParser(prog='openHiTLS', description='parser configure arguments')
88    try:
89        # Version/Release Build Configuration Parameters
90        parser.add_argument('-m', '--module_cmake', action='store_true', help='generate moudules.cmake file')
91        parser.add_argument('--build_dir', metavar='dir', type=str, default=os.path.join(srcdir, 'build'),
92                            help='compile temp directory')
93        parser.add_argument('--output_dir', metavar='dir', type=str, default=os.path.join(srcdir, 'output'),
94                            help='compile output directory')
95        # Configuration file
96        parser.add_argument('--feature_config', metavar='file_path', type=str, default='',
97                            help='Configuration file of the compilation features.')
98        parser.add_argument('--compile_config', metavar='file_path', type=str, default='',
99                            help='Configuration file of compilation parameters.')
100        # Compilation Feature Configuration
101        parser.add_argument('--enable', metavar='feature', nargs='+', default=[],
102                            help='enable some libs or features, such as --enable sha256 aes gcm_asm, default is "all"')
103        parser.add_argument('--disable', metavar='feature', nargs='+', default=['uio_sctp'],
104                            help='disable some libs or features, such as --disable aes gcm_asm, default is disable "uio_sctp" ')
105        parser.add_argument('--enable-sctp', action="store_true", help='enable sctp which is used in DTLS')
106        parser.add_argument('--asm_type', type=str, help='Assembly Type, default is "no_asm".')
107        parser.add_argument('--asm', metavar='feature', default=[], nargs='+', help='config asm, such as --asm sha2')
108        # System Configuration
109        parser.add_argument('--system', type=str,
110                            help='To enable feature "sal_xxx", should specify the system.')
111        parser.add_argument('--endian', metavar='little|big', type=str, choices=['little', 'big'],
112                            help='Specify the platform endianness as little or big, default is "little".')
113        parser.add_argument('--bits', metavar='32|64', type=int, choices=[32, 64],
114                            help='To enable feature "bn", should specify the number of OS bits, default is "64".')
115        # Compiler Options, Link Options
116        parser.add_argument('--lib_type', choices=['static', 'shared', 'object'], nargs='+',
117                            help='set lib type, such as --lib_type staic shared, default is "staic shared object"')
118        parser.add_argument('--add_options', default='', type=str,
119                            help='add some compile options, such as --add_options="-O0 -g"')
120        parser.add_argument('--del_options', default='', type=str,
121                            help='delete some compile options such as --del_options="-O2 -Werror"')
122        parser.add_argument('--add_link_flags', default='', type=str,
123                            help='add some link flags such as --add_link_flags="-pie"')
124        parser.add_argument('--del_link_flags', default='', type=str,
125                            help='delete some link flags such as --del_link_flags="-shared -Wl,-z,relro"')
126
127        parser.add_argument('--hitls_version', default='openHiTLS 0.2.1 20 May 2025', help='%(prog)s version str')
128        parser.add_argument('--hitls_version_num', default=0x0020001f, help='%(prog)s version num')
129        parser.add_argument('--bundle_libs', action='store_true', help='Indicates that multiple libraries are bundled together. By default, it is not bound.\
130                            It need to be used together with "-m"')
131
132        args = vars(parser.parse_args())
133
134        args['tmp_feature_config'] = os.path.join(args['build_dir'], 'feature_config.json')
135        args['tmp_compile_config'] = os.path.join(args['build_dir'], 'compile_config.json')
136
137        # disable uio_sctp by default
138        if args['enable_sctp'] or args['module_cmake']:
139            if 'uio_sctp' in args['disable']:
140                args['disable'].remove('uio_sctp')
141
142    except argparse.ArgumentError as e:
143        parser.print_help()
144        raise ValueError("Error: Failed to obtain parameters.") from e
145
146    return argparse.Namespace(**args)
147
148class Configure:
149    """Provides operations related to configuration and input parameter parsing:
150    1 Parse input parameters.
151    2 Read configuration files and input parameters.
152    3 Update the final configuration files in the build directory.
153    """
154    config_json_file = 'config.json'
155    feature_json_file = 'config/json/feature.json'
156    complete_options_json_file = 'config/json/complete_options.json'
157    default_compile_json_file = 'config/json/compile.json'
158
159    def __init__(self, features: FeatureParser):
160        self._features = features
161        self._args = get_cfg_args()
162        self._preprocess_args()
163
164    @property
165    def args(self):
166        return self._args
167
168    def _preprocess_args(self):
169        if self._args.feature_config and not os.path.exists(self._args.feature_config):
170            raise FileNotFoundError('File not found: %s' % self._args.feature_config)
171        if self._args.compile_config and not os.path.exists(self._args.compile_config):
172            raise FileNotFoundError('File not found: %s' % self._args.compile_config)
173
174        if 'all' in self._args.enable:
175            if len(self._args.enable) > 1:
176                raise ValueError("Error: 'all' and other features cannot be set at the same time.")
177        else:
178            for fea in self._args.enable:
179                if fea in self._features.libs or fea in self._features.feas_info:
180                    continue
181                raise ValueError("unrecognized fea '%s'" % fea)
182
183        if self._args.asm_type:
184            if self._args.asm_type not in self._features.asm_types:
185                raise ValueError("Unsupported asm_type: asm_type should be one of [%s]" % self._features.asm_types)
186        else:
187            if self._args.asm and not self._args.asm_type:
188                raise ValueError("Error: 'asm_type' and 'asm' must be set at the same time.")
189        # The value of 'asm' will be verified later.
190
191    @staticmethod
192    def _load_config(is_fea_cfg, src_file, dest_file):
193        if os.path.exists(dest_file):
194            if src_file != '':
195                raise FileExistsError('{} already exists'.format(dest_file))
196        else:
197            if src_file == '':
198                # No custom configuration file is specified, create a default config file.
199                cfg = FeatureConfigParser.default_cfg() if is_fea_cfg else CompileConfigParser.default_cfg()
200                save_json_file(cfg, dest_file)
201            else:
202                copy_file(src_file, dest_file)
203
204    def load_config_to_build(self):
205        """Load the compilation feature and compilation option configuration files to the build directory:
206            build/feature_config.json
207            build/compile_config.json
208        """
209        if not os.path.exists(self._args.build_dir):
210            os.makedirs(self._args.build_dir)
211        self._load_config(True, self._args.feature_config, self._args.tmp_feature_config)
212        self._load_config(False, self._args.compile_config, self._args.tmp_compile_config)
213
214    def update_feature_config(self, gen_cmake):
215        """Update the feature configuration file in the build based on the input parameters."""
216        conf_custom_feature = FeatureConfigParser(self._features, self._args.tmp_feature_config)
217
218        # If no feature is enabled before modules.cmake is generated, set enable to "all".
219        if not conf_custom_feature.libs and not self._args.enable and gen_cmake:
220            self._args.enable = ['all']
221
222        # Set parameters by referring to "FeatureConfigParser.key_value".
223        conf_custom_feature.set_param('libType', self._args.lib_type)
224        conf_custom_feature.set_param('endian', self._args.endian)
225        conf_custom_feature.set_param('system', self._args.system, False)
226        conf_custom_feature.set_param('bits', self._args.bits, False)
227        if self._args.bundle_libs:
228            conf_custom_feature.set_param('bundleLibs', self._args.bundle_libs)
229        enable_feas, asm_feas = conf_custom_feature.get_enable_feas(self._args.enable, self._args.asm)
230
231        asm_type = self._args.asm_type if self._args.asm_type else ''
232        if not asm_type and conf_custom_feature.asm_type != 'no_asm':
233            asm_type = conf_custom_feature.asm_type
234
235        if asm_type:
236            conf_custom_feature.set_asm_type(asm_type)
237            conf_custom_feature.set_asm_features(enable_feas, asm_feas, asm_type)
238        if enable_feas:
239            conf_custom_feature.set_c_features(enable_feas)
240
241        self._args.securec_lib = conf_custom_feature.securec_lib
242        # update feature and resave file.
243        conf_custom_feature.update_feature(self._args.enable, self._args.disable, gen_cmake)
244        conf_custom_feature.save(self._args.tmp_feature_config)
245        self._args.bundle_libs = conf_custom_feature.bundle_libs
246
247    def update_compile_config(self, all_options: CompleteOptionParser):
248        """Update the compilation configuration file in the build based on the input parameters."""
249        conf_custom_compile = CompileConfigParser(all_options, self._args.tmp_compile_config)
250
251        if self._args.add_options:
252            conf_custom_compile.change_options(self._args.add_options.strip().split(' '), True)
253        if self._args.del_options:
254            conf_custom_compile.change_options(self._args.del_options.strip().split(' '), False)
255
256        if self._args.add_link_flags:
257            conf_custom_compile.change_link_flags(self._args.add_link_flags.strip().split(' '), True)
258        if self._args.del_link_flags:
259            conf_custom_compile.change_link_flags(self._args.del_link_flags.strip().split(' '), False)
260
261        conf_custom_compile.save(self._args.tmp_compile_config)
262
263class CMakeGenerator:
264    """ Generating CMake Commands and Scripts Based on Configuration Files """
265    def __init__(self, args, features: FeatureParser, all_options: CompleteOptionParser):
266        self._args = args
267        self._cfg_feature = features
268        self._cfg_compile = CompileParser(all_options, Configure.default_compile_json_file)
269        self._cfg_custom_feature = FeatureConfigParser(features, args.tmp_feature_config)
270        self._cfg_custom_feature.check_fea_opts()
271        self._cfg_custom_compile = CompileConfigParser(all_options, args.tmp_compile_config)
272
273        self._asm_type = self._cfg_custom_feature.asm_type
274
275        self._platform = 'linux'
276
277    @staticmethod
278    def _get_common_include(modules: list):
279        """ modules: ['::','::']"""
280        inc_dirs = set()
281        top_modules = set(x.split('::')[0] for x in modules)
282        top_modules.add('bsl/log')
283        top_modules.add('bsl/err')
284        for module in top_modules:
285            path = module + '/include'
286            if os.path.exists(path):
287                inc_dirs.add(path)
288            path = 'include/' + module
289            if os.path.exists(path):
290                inc_dirs.add(path)
291
292        if os.path.exists('config/macro_config'):
293            inc_dirs.add('config/macro_config')
294        if os.path.exists('../../../../Secure_C/include'):
295            inc_dirs.add('../../../../Secure_C/include')
296        if os.path.exists('../../../platform/Secure_C/include'):
297            inc_dirs.add('../../../platform/Secure_C/include')
298        return inc_dirs
299
300    def _get_module_include(self, mod: str, dep_mods: list):
301        inc_dirs = set()
302        dep_mods.append(mod)
303        for dep in dep_mods:
304            top_dir, sub_dir = dep.split('::')
305            path = "{}/{}/include".format(top_dir, sub_dir)
306            if os.path.exists(path):
307                inc_dirs.add(path)
308        top_mod, sub_mod = dep.split('::')
309
310        cfg_inc = self._cfg_feature.modules[top_mod][sub_mod].get('.include', [])
311        for inc_dir in cfg_inc:
312            if os.path.exists(inc_dir):
313                inc_dirs.add(inc_dir)
314        return inc_dirs
315
316    @staticmethod
317    def _expand_srcs(srcs):
318        if not srcs:
319            return []
320
321        ret = []
322        for x in srcs:
323            ret += glob.glob(x, recursive=True)
324        if len(ret) == 0:
325            raise SystemError("The .c file does not exist in the {} directory.".format(srcs))
326        ret.sort()
327        return ret
328
329    @classmethod
330    def _gen_cmd_cmake(cls, cmd: str, title, content_obj=None):
331        if not content_obj:
332            return '{}({})\n'.format(cmd, title)
333
334        items = None
335        if isinstance(content_obj, list) or isinstance(content_obj, set):
336            items = content_obj
337        elif isinstance(content_obj, dict):
338            items = content_obj.values()
339        elif isinstance(content_obj, str):
340            items = [content_obj]
341        else:
342            raise ValueError('Unsupported type "%s"' % type(content_obj))
343
344        content = ''
345        for item in items:
346            content += '    {}\n'.format(item)
347
348        if len(items) == 1:
349            return '{}({} {})\n'.format(cmd, title, item)
350        else:
351            return '{}({}\n{})\n'.format(cmd, title, content)
352
353    def _get_module_src_set(self, lib, top_mod, sub_mod, mod_obj):
354        srcs = self._cfg_feature.get_mod_srcs(top_mod, sub_mod, mod_obj)
355        return self._expand_srcs(srcs)
356
357    def _gen_module_cmake(self, lib, mod, mod_obj, mods_cmake):
358        top_mod, module_name = mod.split('::')
359        inc_set = self._get_module_include(mod, mod_obj.get('deps', []))
360        src_list = self._get_module_src_set(lib, top_mod, module_name, mod_obj)
361
362        tgt_name = module_name + '-objs'
363        cmake = '\n# Add module {} \n'.format(module_name)
364        cmake += self._gen_cmd_cmake('add_library', '{} OBJECT'.format(tgt_name))
365        cmake += self._gen_cmd_cmake('target_include_directories', '{} PRIVATE'.format(tgt_name), inc_set)
366        cmake += self._gen_cmd_cmake('target_sources', '{} PRIVATE'.format(tgt_name), src_list)
367        mods_cmake[tgt_name] = cmake
368
369    def _gen_shared_lib_cmake(self, lib_name, tgt_obj_list, tgt_list, macros):
370        tgt_name = lib_name + '-shared'
371        properties = 'OUTPUT_NAME {}'.format(lib_name)
372
373        cmake = '\n'
374        cmake += self._gen_cmd_cmake('add_library', '{} SHARED'.format(tgt_name), tgt_obj_list)
375        cmake += self._gen_cmd_cmake('target_link_options', '{} PRIVATE'.format(tgt_name), '${SHARED_LNK_FLAGS}')
376        if os.path.exists('{}/platform/Secure_C/lib'.format(srcdir)):
377            cmake += self._gen_cmd_cmake('target_link_directories', '{} PRIVATE'.format(tgt_name), '{}/platform/Secure_C/lib'.format(srcdir))
378        cmake += self._gen_cmd_cmake('set_target_properties', '{} PROPERTIES'.format(tgt_name), properties)
379        cmake += 'install(TARGETS %s DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)\n' % tgt_name
380
381        if lib_name == 'hitls_bsl':
382            for item in macros:
383                if item == '-DHITLS_BSL_UIO' or item == '-DHITLS_BSL_UIO_SCTP':
384                    cmake += self._gen_cmd_cmake("target_link_directories", "hitls_bsl-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
385                    cmake += self._gen_cmd_cmake("target_link_libraries", "hitls_bsl-shared " + str(self._args.securec_lib))
386                if item == '-DHITLS_BSL_SAL_DL':
387                    cmake += self._gen_cmd_cmake("target_link_directories", "hitls_bsl-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
388                    cmake += self._gen_cmd_cmake("target_link_libraries", "hitls_bsl-shared dl " + str(self._args.securec_lib))
389        if lib_name == 'hitls_crypto':
390            cmake += self._gen_cmd_cmake("target_link_directories", "hitls_crypto-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
391            cmake += self._gen_cmd_cmake("target_link_libraries", "hitls_crypto-shared hitls_bsl-shared " + str(self._args.securec_lib))
392        if lib_name == 'hitls_tls':
393            cmake += self._gen_cmd_cmake("target_link_directories", "hitls_tls-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
394            cmake += self._gen_cmd_cmake("target_link_libraries", "hitls_tls-shared hitls_pki-shared hitls_crypto-shared hitls_bsl-shared " + str(self._args.securec_lib))
395        if lib_name == 'hitls_pki':
396            cmake += self._gen_cmd_cmake("target_link_directories", "hitls_pki-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
397            cmake += self._gen_cmd_cmake(
398                "target_link_libraries", "hitls_pki-shared hitls_crypto-shared hitls_bsl-shared " + str(self._args.securec_lib))
399        if lib_name == 'hitls_auth':
400            cmake += self._gen_cmd_cmake("target_link_directories", "hitls_auth-shared PRIVATE " + "${CMAKE_SOURCE_DIR}/platform/Secure_C/lib")
401            cmake += self._gen_cmd_cmake(
402                "target_link_libraries", "hitls_auth-shared hitls_crypto-shared hitls_bsl-shared " + str(self._args.securec_lib))
403        tgt_list.append(tgt_name)
404        return cmake
405
406    def _gen_static_lib_cmake(self, lib_name, tgt_obj_list, tgt_list):
407        tgt_name = lib_name + '-static'
408        properties = 'OUTPUT_NAME {}'.format(lib_name)
409
410        cmake = '\n'
411        cmake += self._gen_cmd_cmake('add_library', '{} STATIC'.format(tgt_name), tgt_obj_list)
412        cmake += self._gen_cmd_cmake('set_target_properties', '{} PROPERTIES'.format(tgt_name), properties)
413        cmake += 'install(TARGETS %s DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)\n' % tgt_name
414
415        tgt_list.append(tgt_name)
416        return cmake
417
418    def _gen_obejct_lib_cmake(self, lib_name, tgt_obj_list, tgt_list):
419        tgt_name = lib_name + '-object'
420        properties = 'OUTPUT_NAME lib{}.o'.format(lib_name)
421
422        cmake = '\n'
423        cmake += self._gen_cmd_cmake('add_executable', tgt_name, tgt_obj_list)
424        cmake += self._gen_cmd_cmake('target_link_options', '{} PRIVATE'.format(tgt_name), '${PIE_EXE_LNK_FLAGS}')
425        cmake += self._gen_cmd_cmake('set_target_properties', '{} PROPERTIES'.format(tgt_name), properties)
426        cmake += 'install(TARGETS %s DESTINATION ${CMAKE_INSTALL_PREFIX}/obj)\n' % tgt_name
427
428        tgt_list.append(tgt_name)
429        return cmake
430
431    def _get_definitions(self):
432        return '"${CMAKE_C_FLAGS} -DOPENHITLS_VERSION_S=\'\\"%s\\"\' -DOPENHITLS_VERSION_I=%lu %s"' % (
433            self._args.hitls_version, self._args.hitls_version_num, '-D__FILENAME__=\'\\"$(notdir $(subst .o,,$@))\\"\'')
434
435    def _gen_lib_cmake(self, lib_name, inc_dirs, lib_obj, macros):
436        lang = self._cfg_feature.libs[lib_name].get('lang', 'C')
437
438        cmake = 'project({} {})\n\n'.format(lib_name, lang)
439        cmake += self._gen_cmd_cmake('set', 'CMAKE_ASM_NASM_OBJECT_FORMAT elf64')
440        cmake += self._gen_cmd_cmake('set', 'CMAKE_C_FLAGS', '${CC_ALL_OPTIONS}')
441        cmake += self._gen_cmd_cmake('set', 'CMAKE_ASM_FLAGS', '${CC_ALL_OPTIONS}')
442        cmake += self._gen_cmd_cmake('set', 'CMAKE_C_FLAGS', self._get_definitions())
443        cmake += self._gen_cmd_cmake('include_directories', '', inc_dirs)
444        for _, mod_cmake in lib_obj['mods_cmake'].items():
445            cmake += mod_cmake
446
447        tgt_obj_list = list('$<TARGET_OBJECTS:{}>'.format(x) for x in lib_obj['mods_cmake'].keys())
448
449        tgt_list = []
450        lib_type = self._cfg_custom_feature.lib_type
451        if 'shared' in lib_type:
452            cmake += self._gen_shared_lib_cmake(lib_name, tgt_obj_list, tgt_list, macros)
453        if 'static' in lib_type:
454            cmake += self._gen_static_lib_cmake(lib_name, tgt_obj_list, tgt_list)
455        if 'object' in lib_type:
456            cmake += self._gen_obejct_lib_cmake(lib_name, tgt_obj_list, tgt_list)
457        lib_obj['cmake'] = cmake
458        lib_obj['targets'] = tgt_list
459
460    def _gen_bundled_lib_cmake(self, lib_name, inc_dirs, projects, macros):
461        lang = 'C ASM'
462        if 'mpa' in projects.keys():
463            lang += 'ASM_NASM'
464
465        cmake = 'project({} {})\n\n'.format(lib_name, lang)
466        cmake += self._gen_cmd_cmake('set', 'CMAKE_ASM_NASM_OBJECT_FORMAT elf64')
467        cmake += self._gen_cmd_cmake('set', 'CMAKE_C_FLAGS', '${CC_ALL_OPTIONS}')
468        cmake += self._gen_cmd_cmake('set', 'CMAKE_ASM_FLAGS', '${CC_ALL_OPTIONS}')
469        cmake += self._gen_cmd_cmake('set', 'CMAKE_C_FLAGS', self._get_definitions())
470        cmake += self._gen_cmd_cmake('include_directories', '', inc_dirs)
471
472        tgt_obj_list = []
473        for _, lib_obj in projects.items():
474            tgt_obj_list.extend(list('$<TARGET_OBJECTS:{}>'.format(x) for x in lib_obj['mods_cmake'].keys()))
475            for _, mod_cmake in lib_obj['mods_cmake'].items():
476                cmake += mod_cmake
477
478        tgt_list = []
479        lib_type = self._cfg_custom_feature.lib_type
480        if 'shared' in lib_type:
481            cmake += self._gen_shared_lib_cmake(lib_name, tgt_obj_list, tgt_list, macros)
482        if 'static' in lib_type:
483            cmake += self._gen_static_lib_cmake(lib_name, tgt_obj_list, tgt_list)
484        if 'object' in lib_type:
485            cmake += self._gen_obejct_lib_cmake(lib_name, tgt_obj_list, tgt_list)
486
487        return {lib_name:{'cmake':cmake, 'targets':tgt_list}}
488
489    def _gen_projects_cmake(self, macros):
490        lib_enable_modules = self._cfg_custom_feature.get_enable_modules()
491
492        projects = {}
493        all_inc_dirs = set()
494        for lib, lib_obj in lib_enable_modules.items():
495            projects[lib] = {}
496            projects[lib]['mods_cmake'] = {}
497            inc_dirs = self._get_common_include(lib_obj.keys())
498            for mod, mod_obj in lib_obj.items():
499                self._gen_module_cmake(lib, mod, mod_obj, projects[lib]['mods_cmake'])
500            if self._args.bundle_libs:
501                all_inc_dirs = all_inc_dirs.union(inc_dirs)
502                continue
503            self._gen_lib_cmake(lib, inc_dirs, projects[lib], macros)
504
505        if self._args.bundle_libs:
506            # update projects
507            projects = self._gen_bundled_lib_cmake('hitls', all_inc_dirs, projects, macros)
508        return projects
509
510    def _gen_target_cmake(self, lib_tgts):
511        cmake = 'add_custom_target(openHiTLS)\n'
512        cmake += self._gen_cmd_cmake('add_dependencies', 'openHiTLS', lib_tgts)
513        return cmake
514
515    def _gen_set_param_cmake(self, macro_file):
516        compile_flags, link_flags = self._cfg_compile.union_options(self._cfg_custom_compile)
517        macros = self._cfg_custom_feature.get_fea_macros()
518        macros.sort()
519
520        if '-DHITLS_CRYPTO_CMVP' in macros:
521            self._hmac = True
522
523        compile_flags.extend(macros)
524        hitls_macros = list(filter(lambda x: '-DHITLS' in x, compile_flags))
525        with open(macro_file, "w") as f:
526            f.write(" ".join(hitls_macros))
527            f.close()
528
529        compile_flags_str = '"{}"'.format(" ".join(compile_flags))
530        shared_link_flags = '{}'.format(" ".join(link_flags['SHARED']) + " " + " ".join(link_flags['PUBLIC']))
531        exe_link_flags = '{}'.format(" ".join(link_flags['EXE']) + " " + " ".join(link_flags['PUBLIC']))
532
533        cmake = self._gen_cmd_cmake('set', 'CC_ALL_OPTIONS', compile_flags_str) + "\n"
534        cmake += self._gen_cmd_cmake('set', 'SHARED_LNK_FLAGS', shared_link_flags) + "\n"
535        cmake += self._gen_cmd_cmake('set', 'PIE_EXE_LNK_FLAGS', exe_link_flags) + "\n"
536
537        return cmake, macros
538
539    def out_cmake(self, cmake_path, macro_file):
540        self._cfg_custom_feature.check_bn_config()
541
542        set_param_cmake, macros = self._gen_set_param_cmake(macro_file)
543
544        projects = self._gen_projects_cmake(macros)
545
546        lib_tgts = list(tgt for lib_obj in projects.values() for tgt in lib_obj['targets'])
547        bottom_cmake = self._gen_target_cmake(lib_tgts)
548
549        with open(cmake_path, "w") as f:
550            f.write(set_param_cmake)
551            for lib_obj in projects.values():
552                f.write(lib_obj['cmake'])
553                f.write('\n\n')
554            f.write(bottom_cmake)
555
556def main():
557    os.chdir(srcdir)
558
559    # The Python version cannot be earlier than 3.5.
560    if sys.version_info < (3, 5):
561        print("your python version %d.%d should not be lower than 3.5" % tuple(sys.version_info[:2]))
562        raise Exception("your python version %d.%d should not be lower than 3.5" % tuple(sys.version_info[:2]))
563
564    conf_feature = FeatureParser(Configure.feature_json_file)
565    complete_options = CompleteOptionParser(Configure.complete_options_json_file)
566
567    cfg = Configure(conf_feature)
568    cfg.load_config_to_build()
569    cfg.update_feature_config(cfg.args.module_cmake)
570    cfg.update_compile_config(complete_options)
571
572    if cfg.args.module_cmake:
573        tmp_cmake = os.path.join(cfg.args.build_dir, 'modules.cmake')
574        macro_file = os.path.join(cfg.args.build_dir, 'macro.txt')
575        if (os.path.exists(macro_file)):
576            os.remove(macro_file)
577        CMakeGenerator(cfg.args, conf_feature, complete_options).out_cmake(tmp_cmake, macro_file)
578
579if __name__ == '__main__':
580    try:
581        main()
582    except SystemExit:
583        exit(0)
584    except:
585        traceback.print_exc()
586        exit(2)
587