2022-09-10 03:54:34 +09:00
#!/usr/bin/env python
# SPDX-License-Identifier: GPL-2.0-only
2023-03-09 08:09:15 +09:00
# Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
2022-09-10 03:54:34 +09:00
import argparse
2022-11-30 06:30:24 +09:00
import errno
2023-01-12 04:51:28 +09:00
import glob
2022-09-10 03:54:34 +09:00
import logging
import os
2022-11-04 06:32:42 +09:00
import re
2023-03-18 10:43:52 +09:00
import shutil
2022-09-10 03:54:34 +09:00
import sys
2022-11-04 06:32:42 +09:00
import subprocess
2022-09-10 03:54:34 +09:00
2022-11-04 06:32:42 +09:00
HOST_TARGETS = [ " dtc " ]
DEFAULT_SKIP_LIST = [ " abi " , " test_mapping " ]
2022-11-30 06:30:24 +09:00
MSM_EXTENSIONS = " build/msm_kernel_extensions.bzl "
ABL_EXTENSIONS = " build/abl_extensions.bzl "
DEFAULT_MSM_EXTENSIONS_SRC = " ../msm-kernel/msm_kernel_extensions.bzl "
DEFAULT_ABL_EXTENSIONS_SRC = " ../bootable/bootloader/edk2/abl_extensions.bzl "
2022-09-10 03:54:34 +09:00
2022-11-04 06:32:42 +09:00
class BazelBuilder :
""" Helper class for building with Bazel """
2022-10-28 06:53:00 +09:00
2022-12-01 10:44:33 +09:00
def __init__ ( self , target_list , skip_list , out_dir , user_opts ) :
2022-11-04 06:32:42 +09:00
self . workspace = os . path . realpath (
os . path . join ( os . path . dirname ( os . path . realpath ( __file__ ) ) , " .. " )
)
self . bazel_bin = os . path . join ( self . workspace , " tools " , " bazel " )
if not os . path . exists ( self . bazel_bin ) :
logging . error ( " failed to find Bazel binary at %s " , self . bazel_bin )
sys . exit ( 1 )
self . kernel_dir = os . path . basename (
( os . path . dirname ( os . path . realpath ( __file__ ) ) )
)
2022-12-21 09:54:37 +09:00
for t , v in target_list :
if not t or not v :
logging . error ( " invalid target_variant combo \" %s _ %s \" " , t , v )
sys . exit ( 1 )
2022-11-04 06:32:42 +09:00
self . target_list = target_list
self . skip_list = skip_list
2022-12-01 10:44:33 +09:00
self . out_dir = out_dir
2022-11-04 06:32:42 +09:00
self . user_opts = user_opts
self . process_list = [ ]
2022-11-30 06:30:24 +09:00
self . setup_extensions ( )
2022-10-28 06:53:00 +09:00
2022-11-04 06:32:42 +09:00
def __del__ ( self ) :
for proc in self . process_list :
2022-11-29 06:37:07 +09:00
try :
proc . kill ( )
proc . wait ( )
except OSError :
pass
2022-09-10 03:54:34 +09:00
2023-03-18 10:43:52 +09:00
def copy_abi_file ( self ) :
""" Copy ABI STG file from msm-kernel to common """
msm_sym_list = os . path . join ( self . workspace , " msm-kernel " , " android " , " abi_gki_aarch64_qcom " )
if os . path . exists ( msm_sym_list ) :
shutil . copy2 ( msm_sym_list , os . path . join ( self . workspace , " common " , " android " , " abi_gki_aarch64_qcom " ) )
2022-11-30 06:30:24 +09:00
def setup_extensions ( self ) :
""" Set up the extension files if needed """
for ( ext , def_src ) in [
( MSM_EXTENSIONS , DEFAULT_MSM_EXTENSIONS_SRC ) ,
( ABL_EXTENSIONS , DEFAULT_ABL_EXTENSIONS_SRC ) ,
] :
ext_path = os . path . join ( self . workspace , ext )
# If the file doesn't exist or is a dead link, link to the default
try :
os . stat ( ext_path )
except OSError as e :
if e . errno == errno . ENOENT :
logging . info (
" %s does not exist or is a broken symlink... linking to default at %s " ,
ext ,
def_src ,
)
if os . path . islink ( ext_path ) :
os . unlink ( ext_path )
os . symlink ( def_src , ext_path )
else :
raise e
2022-11-04 06:32:42 +09:00
def get_build_targets ( self ) :
""" Query for build targets """
logging . info ( " Querying build targets... " )
2022-09-10 03:54:34 +09:00
2022-11-04 06:32:42 +09:00
cross_target_list = [ ]
host_target_list = [ ]
for t , v in self . target_list :
if v == " ALL " :
skip_list_re = [
re . compile ( r " // {} : {} _.*_ {} _dist " . format ( self . kernel_dir , t , s ) )
for s in self . skip_list
]
host_target_list_re = [
re . compile ( r " // {} : {} _.*_ {} _dist " . format ( self . kernel_dir , t , h ) )
for h in HOST_TARGETS
]
query = ' filter( " {} _.*_dist$ " , attr(generator_function, define_msm_platforms, {} /...)) ' . format (
t , self . kernel_dir
)
else :
skip_list_re = [
re . compile ( r " // {} : {} _ {} _ {} _dist " . format ( self . kernel_dir , t , v , s ) )
for s in self . skip_list
]
host_target_list_re = [
re . compile ( r " // {} : {} _ {} _ {} _dist " . format ( self . kernel_dir , t , v , h ) )
for h in HOST_TARGETS
]
query = ' filter( " {} _ {} .*_dist$ " , attr(generator_function, define_msm_platforms, {} /...)) ' . format (
t , v , self . kernel_dir
)
2022-09-10 03:54:34 +09:00
2022-11-04 06:32:42 +09:00
cmdline = [
self . bazel_bin ,
" query " ,
" --ui_event_filters=-info " ,
" --noshow_progress " ,
query ,
]
2022-10-25 10:04:53 +09:00
2022-11-04 06:32:42 +09:00
logging . debug ( ' Running " %s " ' , " " . join ( cmdline ) )
2022-09-10 03:54:34 +09:00
2022-11-04 06:32:42 +09:00
try :
query_cmd = subprocess . Popen (
cmdline , cwd = self . workspace , stdout = subprocess . PIPE
)
self . process_list . append ( query_cmd )
2022-12-21 10:07:17 +09:00
target_list = [ l . decode ( " utf-8 " ) for l in query_cmd . stdout . read ( ) . splitlines ( ) ]
2022-11-04 06:32:42 +09:00
except Exception as e :
logging . error ( e )
sys . exit ( 1 )
self . process_list . remove ( query_cmd )
if not target_list :
logging . error (
" failed to find any Bazel targets for target/variant combo %s _ %s " ,
t ,
v ,
)
sys . exit ( 1 )
for target in target_list :
if any ( ( skip_re . match ( target ) for skip_re in skip_list_re ) ) :
continue
if any ( ( host_re . match ( target ) for host_re in host_target_list_re ) ) :
host_target_list . append ( target )
else :
cross_target_list . append ( target )
2023-01-19 03:23:25 +09:00
# Sort build targets by string length to guarantee the base target goes
# first when copying to output directory
cross_target_list . sort ( key = len )
host_target_list . sort ( key = len )
2022-11-04 06:32:42 +09:00
return ( cross_target_list , host_target_list )
2023-01-12 04:51:28 +09:00
def clean_legacy_generated_files ( self ) :
""" Clean generated files from legacy build to avoid conflicts with Bazel """
2023-03-03 07:55:13 +09:00
for f in glob . glob ( " {} /msm-kernel/arch/arm64/configs/vendor/*_defconfig " . format ( self . workspace ) ) :
2023-01-12 04:51:28 +09:00
os . remove ( f )
f = os . path . join ( self . workspace , " bootable " , " bootloader " , " edk2 " , " Conf " , " .AutoGenIdFile.txt " )
if os . path . exists ( f ) :
os . remove ( f )
for root , _ , files in os . walk ( os . path . join ( self . workspace , " bootable " ) ) :
for f in files :
if f . endswith ( " .pyc " ) :
os . remove ( os . path . join ( root , f ) )
2022-11-04 06:32:42 +09:00
def bazel (
2022-12-01 10:44:33 +09:00
self ,
bazel_subcommand ,
targets ,
extra_options = None ,
2023-03-09 08:09:15 +09:00
bazel_target_opts = None ,
2022-11-04 06:32:42 +09:00
) :
""" Execute a bazel command """
cmdline = [ self . bazel_bin , bazel_subcommand ]
2023-03-07 18:13:12 +09:00
if extra_options :
cmdline . extend ( extra_options )
2022-11-04 06:32:42 +09:00
cmdline . extend ( targets )
2023-03-09 08:09:15 +09:00
if bazel_target_opts is not None :
cmdline . extend ( [ " -- " ] + bazel_target_opts )
2022-12-01 10:44:33 +09:00
2022-11-04 06:32:42 +09:00
cmdline_str = " " . join ( cmdline )
try :
logging . info ( ' Running " %s " ' , cmdline_str )
build_proc = subprocess . Popen ( cmdline_str , cwd = self . workspace , shell = True )
self . process_list . append ( build_proc )
build_proc . wait ( )
if build_proc . returncode != 0 :
sys . exit ( build_proc . returncode )
except Exception as e :
logging . error ( e )
sys . exit ( 1 )
self . process_list . remove ( build_proc )
2023-03-22 14:42:14 +09:00
def build_targets ( self , targets , user_opts = None ) :
2022-11-04 06:32:42 +09:00
""" Run " bazel build " on all targets in parallel """
if not targets :
logging . warning ( " no targets to build " )
2023-03-22 14:42:14 +09:00
self . bazel ( " build " , targets , extra_options = user_opts )
2022-09-10 03:54:34 +09:00
2023-03-22 14:42:14 +09:00
def run_targets ( self , targets , out_subdir = " dist " , user_opts = None ) :
2022-11-04 06:32:42 +09:00
""" Run " bazel run " on all targets in serial (since bazel run cannot have multiple targets) """
2023-03-09 08:09:15 +09:00
bto = [ ]
if self . out_dir :
bto . extend ( [ " --dist_dir " , os . path . join ( self . out_dir , out_subdir ) ] )
2022-11-04 06:32:42 +09:00
for target in targets :
2023-03-22 14:42:14 +09:00
self . bazel ( " run " , [ target ] , extra_options = user_opts , bazel_target_opts = bto )
2023-03-09 08:09:15 +09:00
def run_menuconfig ( self ) :
""" Run menuconfig on all target-variant combos class is initialized with """
for t , v in self . target_list :
self . bazel ( " run " , [ " // {} : {} _ {} _config " . format ( self . kernel_dir , t , v ) ] ,
2023-03-22 14:42:14 +09:00
bazel_target_opts = [ " menuconfig " ] )
2022-10-28 06:53:00 +09:00
2022-11-04 06:32:42 +09:00
def build ( self ) :
""" Determine which targets to build, then build them """
cross_targets_to_build , host_targets_to_build = self . get_build_targets ( )
logging . debug (
2023-03-22 14:42:14 +09:00
" Building the following device targets: \n %s " ,
2022-11-04 06:32:42 +09:00
" \n " . join ( cross_targets_to_build ) ,
)
logging . debug (
" Building the following host targets: \n %s " , " \n " . join ( host_targets_to_build )
)
if not cross_targets_to_build and not host_targets_to_build :
logging . error ( " no targets to build " )
sys . exit ( 1 )
2023-01-12 04:51:28 +09:00
self . clean_legacy_generated_files ( )
2023-03-18 10:43:52 +09:00
self . copy_abi_file ( )
2023-01-12 04:51:28 +09:00
2023-01-21 07:46:33 +09:00
if self . skip_list :
self . user_opts . extend ( [ " --//msm-kernel:skip_ {} =true " . format ( s ) for s in self . skip_list ] )
2023-03-22 14:42:14 +09:00
self . user_opts . append ( " --config=android_arm64 " )
logging . info ( " Building device targets... " )
2022-12-01 10:44:33 +09:00
self . build_targets (
cross_targets_to_build ,
user_opts = self . user_opts ,
)
self . run_targets (
cross_targets_to_build ,
user_opts = self . user_opts ,
)
2022-11-04 06:32:42 +09:00
2023-03-22 14:42:14 +09:00
# Replace the last option above (--config=android_arm64) with the host config
self . user_opts [ - 1 ] = " --config=hermetic_cc "
2022-11-04 06:32:42 +09:00
logging . info ( " Building host targets... " )
2022-12-01 10:44:33 +09:00
self . build_targets (
2023-03-22 14:42:14 +09:00
host_targets_to_build , user_opts = self . user_opts
2022-12-01 10:44:33 +09:00
)
self . run_targets (
host_targets_to_build , out_subdir = " host " , user_opts = self . user_opts
)
2022-09-10 03:54:34 +09:00
def main ( ) :
2022-11-04 06:32:42 +09:00
""" Main script entrypoint """
2022-09-10 03:54:34 +09:00
parser = argparse . ArgumentParser ( description = " Build kernel platform with Bazel " )
parser . add_argument (
" -t " ,
" --target " ,
metavar = ( " TARGET " , " VARIANT " ) ,
action = " append " ,
nargs = 2 ,
required = True ,
2022-11-04 06:32:42 +09:00
help = ' Target and variant to build (e.g. -t kalama gki). May be passed multiple times. A special VARIANT may be passed, " ALL " , which will build all variants for a particular target ' ,
2022-09-10 03:54:34 +09:00
)
2022-10-28 06:53:00 +09:00
parser . add_argument (
2022-11-04 06:32:42 +09:00
" -s " ,
" --skip " ,
metavar = " BUILD_RULE " ,
2022-10-28 06:53:00 +09:00
action = " append " ,
default = [ ] ,
2022-11-04 06:32:42 +09:00
help = " Skip specific build rules (e.g. --skip abl will skip the //msm-kernel:<target>_<variant>_abl build) " ,
2022-09-10 03:54:34 +09:00
)
2022-12-01 10:44:33 +09:00
parser . add_argument (
" -o " ,
" --out_dir " ,
metavar = " OUT_DIR " ,
help = ' Specify the output distribution directory (by default, " $PWD/out/msm-kernel-<target>-variant " ) ' ,
)
2022-09-10 03:54:34 +09:00
parser . add_argument (
" --log " ,
2022-11-04 06:32:42 +09:00
metavar = " LEVEL " ,
default = " info " ,
2022-09-10 03:54:34 +09:00
choices = [ " debug " , " info " , " warning " , " error " ] ,
2022-11-04 06:32:42 +09:00
help = " Log level (debug, info, warning, error) " ,
2022-09-10 03:54:34 +09:00
)
2023-03-09 08:09:15 +09:00
parser . add_argument (
" -c " ,
" --menuconfig " ,
action = " store_true " ,
help = " Run menuconfig for <target>-<variant> and exit without building " ,
)
2022-09-10 03:54:34 +09:00
args , user_opts = parser . parse_known_args ( sys . argv [ 1 : ] )
logging . basicConfig (
level = getattr ( logging , args . log . upper ( ) ) ,
format = " [ {} ] %(levelname)s : %(message)s " . format ( os . path . basename ( sys . argv [ 0 ] ) ) ,
)
2022-11-04 06:32:42 +09:00
args . skip . extend ( DEFAULT_SKIP_LIST )
2022-09-10 03:54:34 +09:00
2022-12-01 10:44:33 +09:00
builder = BazelBuilder ( args . target , args . skip , args . out_dir , user_opts )
2022-11-04 06:32:42 +09:00
try :
2023-03-09 08:09:15 +09:00
if args . menuconfig :
builder . run_menuconfig ( )
else :
builder . build ( )
2022-11-04 06:32:42 +09:00
except KeyboardInterrupt :
logging . info ( " Received keyboard interrupt... exiting " )
del builder
sys . exit ( 1 )
2022-09-10 03:54:34 +09:00
logging . info ( " Build completed successfully! " )
if __name__ == " __main__ " :
main ( )