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
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 " ]
2023-07-28 01:25:18 +09:00
DEFAULT_SKIP_LIST = [ " abi " ]
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 "
2023-07-13 07:23:35 +09:00
DEFAULT_OUT_DIR = " {workspace} /out/msm-kernel- {target} - {variant} "
class Target :
def __init__ ( self , workspace , target , variant , bazel_label , out_dir = None ) :
self . workspace = workspace
self . target = target
self . variant = variant
self . bazel_label = bazel_label
self . out_dir = out_dir
def __lt__ ( self , other ) :
return len ( self . bazel_label ) < len ( other . bazel_label )
def get_out_dir ( self , suffix = None ) :
if self . out_dir :
out_dir = self . out_dir
else :
2023-07-22 03:55:52 +09:00
# Mirror the logic in msm_common.bzl:get_out_dir()
if " allyes " in self . target :
target_norm = self . target . replace ( " _ " , " - " )
else :
target_norm = self . target . replace ( " - " , " _ " )
variant_norm = self . variant . replace ( " - " , " _ " )
2023-07-13 07:23:35 +09:00
out_dir = DEFAULT_OUT_DIR . format (
2023-07-22 03:55:52 +09:00
workspace = self . workspace , target = target_norm , variant = variant_norm
2023-07-13 07:23:35 +09:00
)
2022-09-10 03:54:34 +09:00
2023-07-13 07:23:35 +09:00
if suffix :
return os . path . join ( out_dir , suffix )
else :
return out_dir
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
2023-07-07 07:02:16 +09:00
def __init__ ( self , target_list , skip_list , out_dir , dry_run , 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
2023-07-07 07:02:16 +09:00
self . dry_run = dry_run
2022-11-04 06:32:42 +09:00
self . user_opts = user_opts
self . process_list = [ ]
2023-07-13 07:23:35 +09:00
if len ( self . target_list ) > 1 and out_dir :
logging . error ( " cannot specify multiple targets with one out dir " )
sys . exit ( 1 )
else :
self . out_dir = out_dir
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
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
2023-07-20 04:14:56 +09:00
targets = [ ]
2022-11-04 06:32:42 +09:00
for t , v in self . target_list :
if v == " ALL " :
2023-07-13 07:23:35 +09:00
if self . out_dir :
logging . error ( " cannot specify multiple targets (ALL variants) with one out dir " )
sys . exit ( 1 )
2022-11-04 06:32:42 +09:00
skip_list_re = [
re . compile ( r " // {} : {} _.*_ {} _dist " . format ( self . kernel_dir , t , s ) )
for s in self . skip_list
]
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
]
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 )
2023-07-13 07:23:35 +09:00
label_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 )
2023-07-13 07:23:35 +09:00
if not label_list :
2022-11-04 06:32:42 +09:00
logging . error (
" failed to find any Bazel targets for target/variant combo %s _ %s " ,
t ,
v ,
)
sys . exit ( 1 )
2023-07-13 07:23:35 +09:00
for label in label_list :
if any ( ( skip_re . match ( label ) for skip_re in skip_list_re ) ) :
2022-11-04 06:32:42 +09:00
continue
2023-07-13 07:23:35 +09:00
if v == " ALL " :
real_variant = re . search (
r " // {} : {} _([^_]+)_ " . format ( self . kernel_dir , t ) , label
) . group ( 1 )
2022-11-04 06:32:42 +09:00
else :
2023-07-13 07:23:35 +09:00
real_variant = v
2022-11-04 06:32:42 +09:00
2023-07-20 04:14:56 +09:00
targets . append (
Target ( self . workspace , t , real_variant , label , self . out_dir )
)
2023-07-13 07:23:35 +09:00
# Sort build targets by label string length to guarantee the base target goes
2023-01-19 03:23:25 +09:00
# first when copying to output directory
2023-07-20 04:14:56 +09:00
targets . sort ( )
2023-01-19 03:23:25 +09:00
2023-07-20 04:14:56 +09:00
return targets
2022-11-04 06:32:42 +09:00
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 )
2023-07-13 07:23:35 +09:00
cmdline . extend ( [ t . bazel_label for t in 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-07-20 04:14:56 +09:00
def build_targets ( self , targets ) :
2022-11-04 06:32:42 +09:00
""" Run " bazel build " on all targets in parallel """
2023-07-20 04:14:56 +09:00
self . bazel ( " build " , targets , extra_options = self . user_opts )
2022-09-10 03:54:34 +09:00
2023-07-20 04:14:56 +09:00
def run_targets ( self , targets ) :
2022-11-04 06:32:42 +09:00
""" Run " bazel run " on all targets in serial (since bazel run cannot have multiple targets) """
for target in targets :
2023-07-20 04:14:56 +09:00
# Set the output directory based on if it's a host target
if any (
re . match ( r " // {} :.*_ {} _dist " . format ( self . kernel_dir , h ) , target . bazel_label )
for h in HOST_TARGETS
) :
out_dir = target . get_out_dir ( " host " )
else :
out_dir = target . get_out_dir ( " dist " )
self . bazel (
" run " ,
[ target ] ,
extra_options = self . user_opts ,
bazel_target_opts = [ " --dist_dir " , out_dir ]
)
self . write_opts ( out_dir )
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 :
2023-07-22 10:03:29 +09:00
menuconfig_label = " // {} : {} _ {} _config " . format ( self . kernel_dir , t , v )
menuconfig_target = [ Target ( self . workspace , t , v , menuconfig_label , self . out_dir ) ]
self . bazel ( " run " , menuconfig_target , bazel_target_opts = [ " menuconfig " ] )
2022-10-28 06:53:00 +09:00
2023-07-20 04:14:56 +09:00
def write_opts ( self , out_dir ) :
2023-07-13 07:23:35 +09:00
with open ( os . path . join ( out_dir , " build_opts.txt " ) , " w " ) as opt_file :
2023-07-20 04:14:56 +09:00
if self . user_opts :
opt_file . write ( " {} " . format ( " \n " . join ( self . user_opts ) ) )
2023-07-13 07:23:35 +09:00
opt_file . write ( " \n " )
2022-11-04 06:32:42 +09:00
def build ( self ) :
""" Determine which targets to build, then build them """
2023-07-20 04:14:56 +09:00
targets_to_build = self . get_build_targets ( )
2022-11-04 06:32:42 +09:00
2023-07-20 04:14:56 +09:00
if not targets_to_build :
2023-07-13 07:23:35 +09:00
logging . error ( " no targets to build " )
sys . exit ( 1 )
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-07-01 06:14:10 +09:00
self . user_opts . extend ( [
" --user_kmi_symbol_lists=//msm-kernel:android/abi_gki_aarch64_qcom " ,
2023-07-01 06:22:06 +09:00
" --ignore_missing_projects " ,
2023-07-01 06:14:10 +09:00
] )
2023-07-07 07:02:16 +09:00
if self . dry_run :
self . user_opts . append ( " --nobuild " )
2023-07-20 04:14:56 +09:00
logging . debug (
" Building the following targets: \n %s " ,
" \n " . join ( [ t . bazel_label for t in targets_to_build ] )
2022-12-01 10:44:33 +09:00
)
2023-07-07 07:02:16 +09:00
2023-07-20 04:14:56 +09:00
self . clean_legacy_generated_files ( )
2022-11-04 06:32:42 +09:00
2023-07-20 04:14:56 +09:00
logging . info ( " Building targets... " )
self . build_targets ( targets_to_build )
2023-07-07 07:02:16 +09:00
if not self . dry_run :
2023-07-20 04:14:56 +09:00
self . run_targets ( targets_to_build )
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 " ,
)
2023-07-07 07:02:16 +09:00
parser . add_argument (
" -d " ,
" --dry-run " ,
action = " store_true " ,
help = " Perform a dry-run of the build which will perform loading/analysis of build files " ,
)
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
2023-07-07 07:02:16 +09:00
builder = BazelBuilder ( args . target , args . skip , args . out_dir , args . dry_run , 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
2023-07-07 07:02:16 +09:00
if args . dry_run :
logging . info ( " Dry-run completed successfully! " )
else :
logging . info ( " Build completed successfully! " )
2022-09-10 03:54:34 +09:00
if __name__ == " __main__ " :
main ( )