build_process.py 10.2 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():
Y
yaoxiaoyu 已提交
40
    def __init__(self, component=None, compact_mode=False):
M
mamingshuai 已提交
41 42 43 44 45 46 47
        self.config = Config()

        # Get gn args ready
        self._args_list = []
        self._target = None
        self._compiler = None
        self._test = None
Y
yaoxiaoyu 已提交
48
        self._compact_mode = compact_mode
M
mamingshuai 已提交
49

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

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

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

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

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

    @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):
98
        cmd_list = ['xts', 'notest']
M
mamingshuai 已提交
99
        if test_args[0] in cmd_list:
100 101 102 103 104 105
            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 已提交
106
        else:
G
gzyang 已提交
107
            raise OHOSException('Error: wrong input of test')
M
mamingshuai 已提交
108

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

M
mamingshuai 已提交
113
    def register_args(self, args_name, args_value, quota=True):
114
        quota = False if args_value in ['true', 'false'] else quota
M
mamingshuai 已提交
115 116 117 118 119 120 121 122
        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 已提交
123 124
        if args_name == 'ohos_build_target' and len(args_value):
            self.config.fs_attr = None
M
mamingshuai 已提交
125

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

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

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

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

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

G
gzyang 已提交
148 149
        cmd_list = []

M
mamingshuai 已提交
150 151 152 153
        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 已提交
154 155
            cmd_list = [self.gn_build, self.ninja_build]
        elif full_compile:
M
mamingshuai 已提交
156 157 158
            self.register_args('ohos_full_compile', 'true', quota=False)
            remove_path(self.config.out_path)
            makedirs(self.config.out_path)
G
gzyang 已提交
159 160 161 162
            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 已提交
163

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

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

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

    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,
P
pilipala195 已提交
185
                  f'--script-executable={sys.executable}',
M
mamingshuai 已提交
186
                  '--args={}'.format(" ".join(self._args_list))] + gn_args
Y
yaoxiaoyu 已提交
187 188 189 190 191
        if self._compact_mode is False:
            gn_cmd += [
                '--root={}'.format(self.config.root_path),
                '--dotfile={}/.gn'.format(self.config.build_path),
            ]
M
mamingshuai 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        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,
                  'clean',
                  self.config.out_path]
Y
yaoxiaoyu 已提交
213 214 215 216 217
        if self._compact_mode is False:
            gn_cmd += [
                '--root={}'.format(self.config.root_path),
                '--dotfile={}/.gn'.format(self.config.build_path),
            ]
M
mamingshuai 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
        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 已提交
235 236 237 238 239 240 241 242
            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 已提交
243 244 245
            self.config.out_path = os.path.join(self.config.root_path,
                                                'out',
                                                board)
G
gzyang 已提交
246
            self.compiler = Device.get_compiler(device_path)
G
gzyang 已提交
247 248
            gn_device_path = os.path.dirname(device_path)
            gn_kernel_path = device_path
M
mamingshuai 已提交
249 250
            self.register_args('ohos_build_target', [gn_device_path])
            self.register_args('device_path', gn_kernel_path)
251
            self.register_args('device_company', self.config.device_company)
M
mamingshuai 已提交
252 253 254
            self.register_args('ohos_kernel_type', kernel)
        else:
            # Compile product in "hb set"
G
gzyang 已提交
255
            self.compiler = Device.get_compiler(self.config.device_path)
G
gzyang 已提交
256
            self.register_args('product_path', self.config.product_path)
Y
yaoxiaoyu 已提交
257 258
            if self._compact_mode:
                self.register_args('product_name', self.config.product)
G
gzyang 已提交
259
            self.register_args('device_path', self.config.device_path)
260
            self.register_args('device_company', self.config.device_company)
M
mamingshuai 已提交
261 262 263 264 265 266 267 268 269
            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)