build_process.py 9.7 KB
Newer Older
M
mamingshuai 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#
# Copyright (c) 2020 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
P
pilipala195 已提交
20
import sys
M
mamingshuai 已提交
21 22 23 24 25 26 27
from collections import defaultdict

from hb.common.utils import exec_command
from hb.common.utils import makedirs
from hb.common.utils import remove_path
from hb.common.utils import hb_info
from hb.common.utils import hb_warning
G
gzyang 已提交
28
from hb.common.utils import OHOSException
29
from hb.common.utils import get_current_time
M
mamingshuai 已提交
30 31 32 33
from hb.common.config import Config
from hb.cts.cts import CTS
from hb.common.device import Device
from hb.common.product import Product
P
pilipala195 已提交
34
from hb.build.fs_process import Packer
35
from hb.build.patch_process import Patch
Y
yangming_ha 已提交
36
from distutils.spawn import find_executable
M
mamingshuai 已提交
37

38

M
mamingshuai 已提交
39
class Build():
G
gzyang 已提交
40
    def __init__(self, component=None):
M
mamingshuai 已提交
41 42 43 44 45 46 47 48
        self.config = Config()

        # Get gn args ready
        self._args_list = []
        self._target = None
        self._compiler = None
        self._test = None

G
gzyang 已提交
49
        self.target = component
50
        self.start_time = get_current_time()
G
gzyang 已提交
51 52
        self.check_in_device()

M
mamingshuai 已提交
53 54 55 56 57 58
    @property
    def target(self):
        return self._target

    @target.setter
    def target(self, component):
G
gzyang 已提交
59 60 61 62
        if component is None or not len(component):
            return
        component = component[0]

M
mamingshuai 已提交
63 64 65 66 67
        cts = CTS()
        cts.init_from_json()
        for subsystem_cls in cts:
            for cname, component_cls in subsystem_cls:
                if cname == component:
68
                    if not len(component_cls.adapted_board) or\
M
mamingshuai 已提交
69
                       self.config.board in component_cls.adapted_board:
70
                        if not len(component_cls.adapted_kernel) or\
M
mamingshuai 已提交
71 72 73 74 75 76
                           self.config.kernel in component_cls.adapted_kernel:
                            self._target = component_cls.targets
                            self.register_args('ohos_build_target',
                                               self._target)
                            return

G
gzyang 已提交
77
        raise OHOSException(f'Component {component} not found')
M
mamingshuai 已提交
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96

    @property
    def compiler(self):
        return self._compiler

    @compiler.setter
    def compiler(self, value):
        self._compiler = value
        self.register_args('ohos_build_compiler_specified', self._compiler)
        if self._compiler == 'clang':
            self.register_args('ohos_build_compiler_dir',
                               self.config.clang_path)

    @property
    def test(self):
        return self._test

    @test.setter
    def test(self, test_args):
97
        cmd_list = ['xts', 'notest']
M
mamingshuai 已提交
98
        if test_args[0] in cmd_list:
99 100 101 102 103 104
            if test_args[0] == 'notest':
                self.register_args('ohos_test_args', 'notest')
            else:
                self._test = test_args[1]
                if len(test_args) > 1:
                    self.register_args('ohos_xts_test_args', self._test)
M
mamingshuai 已提交
105
        else:
G
gzyang 已提交
106
            raise OHOSException('Error: wrong input of test')
M
mamingshuai 已提交
107

108 109 110 111
    @property
    def build_time(self):
        return get_current_time() - self.start_time

M
mamingshuai 已提交
112
    def register_args(self, args_name, args_value, quota=True):
113
        quota = False if args_value in ['true', 'false'] else quota
M
mamingshuai 已提交
114 115 116 117 118 119 120 121
        if quota:
            if isinstance(args_value, list):
                self._args_list += ['{}="{}"'.format(args_name,
                                                     "&&".join(args_value))]
            else:
                self._args_list += ['{}="{}"'.format(args_name, args_value)]
        else:
            self._args_list += ['{}={}'.format(args_name, args_value)]
G
gzyang 已提交
122 123
        if args_name == 'ohos_build_target' and len(args_value):
            self.config.fs_attr = None
M
mamingshuai 已提交
124

125 126
    def build(self, full_compile, patch=False, ninja=True, cmd_args=None):
        cmd_list = self.get_cmd(full_compile, patch, ninja)
M
mamingshuai 已提交
127

128 129 130
        # enable ccache if it installed.
        ccache_path = find_executable('ccache')
        if ccache_path is not None:
Y
yangming_ha 已提交
131
            self.register_args('ohos_build_enable_ccache', 'true',  quota=False)
132

M
mamingshuai 已提交
133 134 135 136 137
        if cmd_args is None:
            cmd_args = defaultdict(list)
        for exec_cmd in cmd_list:
            exec_cmd(cmd_args)

G
gzyang 已提交
138
        hb_info(f'{os.path.basename(self.config.out_path)} build success')
139
        hb_info(f'cost time: {self.build_time}')
M
mamingshuai 已提交
140 141
        return 0

142
    def get_cmd(self, full_compile, patch, ninja):
M
mamingshuai 已提交
143 144 145 146
        if not ninja:
            self.register_args('ohos_full_compile', 'true', quota=False)
            return [self.gn_build]

G
gzyang 已提交
147 148
        cmd_list = []

M
mamingshuai 已提交
149 150 151 152
        build_ninja = os.path.join(self.config.out_path, 'build.ninja')
        if not os.path.isfile(build_ninja):
            self.register_args('ohos_full_compile', 'true', quota=False)
            makedirs(self.config.out_path)
G
gzyang 已提交
153 154
            cmd_list = [self.gn_build, self.ninja_build]
        elif full_compile:
M
mamingshuai 已提交
155 156 157
            self.register_args('ohos_full_compile', 'true', quota=False)
            remove_path(self.config.out_path)
            makedirs(self.config.out_path)
G
gzyang 已提交
158 159 160 161
            cmd_list = [self.gn_build, self.ninja_build]
        else:
            self.register_args('ohos_full_compile', 'false', quota=False)
            cmd_list = [self.ninja_build]
M
mamingshuai 已提交
162

163 164 165 166
        if patch:
            patch = Patch()
            cmd_list = [patch.patch_make] + cmd_list

G
gzyang 已提交
167 168 169 170 171
        if self.config.fs_attr is not None:
            packer = Packer()
            cmd_list.append(packer.fs_make)

        return cmd_list
M
mamingshuai 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185

    def gn_build(self, cmd_args):
        # Clean out path
        remove_path(self.config.out_path)
        makedirs(self.config.out_path)

        # Gn cmd init and execute
        gn_path = self.config.gn_path
        gn_args = cmd_args.get('gn', [])
        gn_cmd = [gn_path,
                  'gen',
                  self.config.out_path,
                  '--root={}'.format(self.config.root_path),
                  '--dotfile={}/.gn'.format(self.config.build_path),
P
pilipala195 已提交
186
                  f'--script-executable={sys.executable}',
M
mamingshuai 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
                  '--args={}'.format(" ".join(self._args_list))] + gn_args
        exec_command(gn_cmd, log_path=self.config.log_path)

    def gn_clean(self, out_path=None):
        # Gn cmd init and execute
        gn_path = self.config.gn_path

        if out_path is not None:
            self.config.out_path = os.path.abspath(out_path)
        else:
            self.config.out_path = os.path.join(self.config.root_path,
                                                'out',
                                                self.config.board,
                                                self.config.product)

        if not os.path.isdir(self.config.out_path):
            hb_warning('{} not found'.format(self.config.out_path))
            return

        gn_cmd = [gn_path,
                  '--root={}'.format(self.config.root_path),
                  '--dotfile={}/.gn'.format(self.config.build_path),
                  'clean',
                  self.config.out_path]
        exec_command(gn_cmd, log_path=self.config.log_path)

    def ninja_build(self, cmd_args):
        ninja_path = self.config.ninja_path

        ninja_args = cmd_args.get('ninja', [])
        ninja_cmd = [ninja_path,
                     '-w',
                     'dupbuild=warn',
                     '-C',
                     self.config.out_path] + ninja_args
        exec_command(ninja_cmd, log_path=self.config.log_path, log_filter=True)

    def check_in_device(self):
        if self._target is None and Device.is_in_device():
            # Compile device board
            device_path, kernel, board = Device.device_menuconfig()
G
gzyang 已提交
228 229 230 231 232 233 234 235
            hb_info(f'{device_path}')
            # build device, no need to set root manually,
            # so set it speculatively.
            self.config.root_path = os.path.abspath(os.path.join(device_path,
                                                                 os.pardir,
                                                                 os.pardir,
                                                                 os.pardir,
                                                                 os.pardir))
M
mamingshuai 已提交
236 237 238
            self.config.out_path = os.path.join(self.config.root_path,
                                                'out',
                                                board)
G
gzyang 已提交
239
            self.compiler = Device.get_compiler(device_path)
G
gzyang 已提交
240 241
            gn_device_path = os.path.dirname(device_path)
            gn_kernel_path = device_path
M
mamingshuai 已提交
242 243 244 245 246
            self.register_args('ohos_build_target', [gn_device_path])
            self.register_args('device_path', gn_kernel_path)
            self.register_args('ohos_kernel_type', kernel)
        else:
            # Compile product in "hb set"
G
gzyang 已提交
247
            self.compiler = Device.get_compiler(self.config.device_path)
G
gzyang 已提交
248 249
            self.register_args('product_path', self.config.product_path)
            self.register_args('device_path', self.config.device_path)
M
mamingshuai 已提交
250 251 252 253 254 255 256 257 258
            self.register_args('ohos_kernel_type', self.config.kernel)

            product_json = os.path.join(self.config.product_path,
                                        'config.json')
            self._args_list += Product.get_features(product_json)
            self.config.out_path = os.path.join(self.config.root_path,
                                                'out',
                                                self.config.board,
                                                self.config.product)