1*333d2b36SAndroid Build Coastguard Worker#!/bin/bash 2*333d2b36SAndroid Build Coastguard Worker 3*333d2b36SAndroid Build Coastguard Workerset -eu 4*333d2b36SAndroid Build Coastguard Worker 5*333d2b36SAndroid Build Coastguard Worker# Copyright 2020 Google Inc. All rights reserved. 6*333d2b36SAndroid Build Coastguard Worker# 7*333d2b36SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 8*333d2b36SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 9*333d2b36SAndroid Build Coastguard Worker# You may obtain a copy of the License at 10*333d2b36SAndroid Build Coastguard Worker# 11*333d2b36SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 12*333d2b36SAndroid Build Coastguard Worker# 13*333d2b36SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 14*333d2b36SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 15*333d2b36SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16*333d2b36SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 17*333d2b36SAndroid Build Coastguard Worker# limitations under the License. 18*333d2b36SAndroid Build Coastguard Worker 19*333d2b36SAndroid Build Coastguard Worker# Tool to evaluate the transitive closure of the ninja dependency graph of the 20*333d2b36SAndroid Build Coastguard Worker# files and targets depending on a given target. 21*333d2b36SAndroid Build Coastguard Worker# 22*333d2b36SAndroid Build Coastguard Worker# i.e. the list of things that could change after changing a target. 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Workerreadonly me=$(basename "${0}") 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Workerreadonly usage="usage: ${me} {options} target [target...] 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard WorkerEvaluate the reverse transitive closure of ninja targets depending on one or 29*333d2b36SAndroid Build Coastguard Workermore targets. 30*333d2b36SAndroid Build Coastguard Worker 31*333d2b36SAndroid Build Coastguard WorkerOptions: 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Worker -(no)quiet Suppresses progress output to stderr and interactive 34*333d2b36SAndroid Build Coastguard Worker alias -(no)q prompts. By default, when stderr is a tty, progress gets 35*333d2b36SAndroid Build Coastguard Worker reported to stderr; when both stderr and stdin are tty, 36*333d2b36SAndroid Build Coastguard Worker the script asks user whether to delete intermediate files. 37*333d2b36SAndroid Build Coastguard Worker When suppressed or not prompted, script always deletes the 38*333d2b36SAndroid Build Coastguard Worker temporary / intermediate files. 39*333d2b36SAndroid Build Coastguard Worker -sep=<delim> Use 'delim' as output field separator between notice 40*333d2b36SAndroid Build Coastguard Worker checksum and notice filename in notice output. 41*333d2b36SAndroid Build Coastguard Worker e.g. sep='\t' 42*333d2b36SAndroid Build Coastguard Worker (Default space) 43*333d2b36SAndroid Build Coastguard Worker -csv Shorthand for -sep=',' 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard WorkerAt minimum, before running this script, you must first run: 46*333d2b36SAndroid Build Coastguard Worker$ source build/envsetup.sh 47*333d2b36SAndroid Build Coastguard Worker$ lunch 48*333d2b36SAndroid Build Coastguard Worker$ m nothing 49*333d2b36SAndroid Build Coastguard Workerto setup the build environment, choose a target platform, and build the ninja 50*333d2b36SAndroid Build Coastguard Workerdependency graph. 51*333d2b36SAndroid Build Coastguard Worker" 52*333d2b36SAndroid Build Coastguard Worker 53*333d2b36SAndroid Build Coastguard Workerfunction die() { echo -e "${*}" >&2; exit 2; } 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Worker# Reads one input target per line from stdin; outputs (isnotice target) tuples. 56*333d2b36SAndroid Build Coastguard Worker# 57*333d2b36SAndroid Build Coastguard Worker# output target is a ninja target that the input target depends on 58*333d2b36SAndroid Build Coastguard Worker# isnotice in {0,1} with 1 for output targets believed to be license or notice 59*333d2b36SAndroid Build Coastguard Worker# 60*333d2b36SAndroid Build Coastguard Worker# only argument is the dependency depth indicator 61*333d2b36SAndroid Build Coastguard Workerfunction getDeps() { 62*333d2b36SAndroid Build Coastguard Worker (tr '\n' '\0' | xargs -0 "${ninja_bin}" -f "${ninja_file}" -t query) \ 63*333d2b36SAndroid Build Coastguard Worker | awk -v depth="${1}" ' 64*333d2b36SAndroid Build Coastguard Worker BEGIN { 65*333d2b36SAndroid Build Coastguard Worker inoutput = 0 66*333d2b36SAndroid Build Coastguard Worker } 67*333d2b36SAndroid Build Coastguard Worker $0 ~ /^\S\S*:$/ { 68*333d2b36SAndroid Build Coastguard Worker inoutput = 0 69*333d2b36SAndroid Build Coastguard Worker } 70*333d2b36SAndroid Build Coastguard Worker $1 == "validations:" { 71*333d2b36SAndroid Build Coastguard Worker inoutput = 0 72*333d2b36SAndroid Build Coastguard Worker } 73*333d2b36SAndroid Build Coastguard Worker inoutput != 0 { 74*333d2b36SAndroid Build Coastguard Worker print gensub(/^\s*/, "", "g")" "depth 75*333d2b36SAndroid Build Coastguard Worker } 76*333d2b36SAndroid Build Coastguard Worker $1 == "outputs:" { 77*333d2b36SAndroid Build Coastguard Worker inoutput = 1 78*333d2b36SAndroid Build Coastguard Worker } 79*333d2b36SAndroid Build Coastguard Worker ' 80*333d2b36SAndroid Build Coastguard Worker} 81*333d2b36SAndroid Build Coastguard Worker 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Workerif [ -z "${ANDROID_BUILD_TOP}" ]; then 84*333d2b36SAndroid Build Coastguard Worker die "${me}: Run 'lunch' to configure the build environment" 85*333d2b36SAndroid Build Coastguard Workerfi 86*333d2b36SAndroid Build Coastguard Worker 87*333d2b36SAndroid Build Coastguard Workerif [ -z "${TARGET_PRODUCT}" ]; then 88*333d2b36SAndroid Build Coastguard Worker die "${me}: Run 'lunch' to configure the build environment" 89*333d2b36SAndroid Build Coastguard Workerfi 90*333d2b36SAndroid Build Coastguard Worker 91*333d2b36SAndroid Build Coastguard Workerninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja" 92*333d2b36SAndroid Build Coastguard Workerif [ ! -f "${ninja_file}" ]; then 93*333d2b36SAndroid Build Coastguard Worker die "${me}: Run 'm nothing' to build the dependency graph" 94*333d2b36SAndroid Build Coastguard Workerfi 95*333d2b36SAndroid Build Coastguard Worker 96*333d2b36SAndroid Build Coastguard Workerninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja" 97*333d2b36SAndroid Build Coastguard Workerif [ ! -x "${ninja_bin}" ]; then 98*333d2b36SAndroid Build Coastguard Worker die "${me}: Cannot find ninja executable expected at ${ninja_bin}" 99*333d2b36SAndroid Build Coastguard Workerfi 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Worker 102*333d2b36SAndroid Build Coastguard Worker# parse the command-line 103*333d2b36SAndroid Build Coastguard Worker 104*333d2b36SAndroid Build Coastguard Workerdeclare -a targets # one or more targets to evaluate 105*333d2b36SAndroid Build Coastguard Worker 106*333d2b36SAndroid Build Coastguard Workerquiet=false # whether to suppress progress 107*333d2b36SAndroid Build Coastguard Worker 108*333d2b36SAndroid Build Coastguard Workersep=" " # output separator between depth and target 109*333d2b36SAndroid Build Coastguard Worker 110*333d2b36SAndroid Build Coastguard Workeruse_stdin=false # whether to read targets from stdin i.e. target - 111*333d2b36SAndroid Build Coastguard Worker 112*333d2b36SAndroid Build Coastguard Workerwhile [ $# -gt 0 ]; do 113*333d2b36SAndroid Build Coastguard Worker case "${1:-}" in 114*333d2b36SAndroid Build Coastguard Worker -) 115*333d2b36SAndroid Build Coastguard Worker use_stdin=true 116*333d2b36SAndroid Build Coastguard Worker ;; 117*333d2b36SAndroid Build Coastguard Worker -*) 118*333d2b36SAndroid Build Coastguard Worker flag=$(expr "${1}" : '^-*\(.*\)$') 119*333d2b36SAndroid Build Coastguard Worker case "${flag:-}" in 120*333d2b36SAndroid Build Coastguard Worker q) ;& 121*333d2b36SAndroid Build Coastguard Worker quiet) 122*333d2b36SAndroid Build Coastguard Worker quiet=true;; 123*333d2b36SAndroid Build Coastguard Worker noq) ;& 124*333d2b36SAndroid Build Coastguard Worker noquiet) 125*333d2b36SAndroid Build Coastguard Worker quiet=false;; 126*333d2b36SAndroid Build Coastguard Worker csv) 127*333d2b36SAndroid Build Coastguard Worker sep=",";; 128*333d2b36SAndroid Build Coastguard Worker sep) 129*333d2b36SAndroid Build Coastguard Worker sep="${2?"${usage}"}"; shift;; 130*333d2b36SAndroid Build Coastguard Worker sep=*) 131*333d2b36SAndroid Build Coastguard Worker sep=$(expr "${flag}" : '^sep=\(.*\)$';; 132*333d2b36SAndroid Build Coastguard Worker *) 133*333d2b36SAndroid Build Coastguard Worker die "Unknown flag ${1}" 134*333d2b36SAndroid Build Coastguard Worker ;; 135*333d2b36SAndroid Build Coastguard Worker esac 136*333d2b36SAndroid Build Coastguard Worker ;; 137*333d2b36SAndroid Build Coastguard Worker *) 138*333d2b36SAndroid Build Coastguard Worker targets+=("${1:-}") 139*333d2b36SAndroid Build Coastguard Worker ;; 140*333d2b36SAndroid Build Coastguard Worker esac 141*333d2b36SAndroid Build Coastguard Worker shift 142*333d2b36SAndroid Build Coastguard Workerdone 143*333d2b36SAndroid Build Coastguard Worker 144*333d2b36SAndroid Build Coastguard Workerif [ ! -v targets[0] ] && ! ${use_stdin}; then 145*333d2b36SAndroid Build Coastguard Worker die "${usage}\n\nNo target specified." 146*333d2b36SAndroid Build Coastguard Workerfi 147*333d2b36SAndroid Build Coastguard Worker 148*333d2b36SAndroid Build Coastguard Worker# showProgress when stderr is a tty 149*333d2b36SAndroid Build Coastguard Workerif [ -t 2 ] && ! ${quiet}; then 150*333d2b36SAndroid Build Coastguard Worker showProgress=true 151*333d2b36SAndroid Build Coastguard Workerelse 152*333d2b36SAndroid Build Coastguard Worker showProgress=false 153*333d2b36SAndroid Build Coastguard Workerfi 154*333d2b36SAndroid Build Coastguard Worker 155*333d2b36SAndroid Build Coastguard Worker# interactive when both stderr and stdin are tty 156*333d2b36SAndroid Build Coastguard Workerif ${showProgress} && [ -t 0 ]; then 157*333d2b36SAndroid Build Coastguard Worker interactive=true 158*333d2b36SAndroid Build Coastguard Workerelse 159*333d2b36SAndroid Build Coastguard Worker interactive=false 160*333d2b36SAndroid Build Coastguard Workerfi 161*333d2b36SAndroid Build Coastguard Worker 162*333d2b36SAndroid Build Coastguard Worker 163*333d2b36SAndroid Build Coastguard Workerreadonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX") 164*333d2b36SAndroid Build Coastguard Workerif [ -z "${tmpFiles}" ]; then 165*333d2b36SAndroid Build Coastguard Worker die "${me}: unable to create temporary directory" 166*333d2b36SAndroid Build Coastguard Workerfi 167*333d2b36SAndroid Build Coastguard Worker 168*333d2b36SAndroid Build Coastguard Worker# The deps files contain unique (isnotice target) tuples where 169*333d2b36SAndroid Build Coastguard Worker# isnotice in {0,1} with 1 when ninja target `target` is a license or notice. 170*333d2b36SAndroid Build Coastguard Workerreadonly oldDeps="${tmpFiles}/old" 171*333d2b36SAndroid Build Coastguard Workerreadonly newDeps="${tmpFiles}/new" 172*333d2b36SAndroid Build Coastguard Workerreadonly allDeps="${tmpFiles}/all" 173*333d2b36SAndroid Build Coastguard Worker 174*333d2b36SAndroid Build Coastguard Workerif ${use_stdin}; then # start deps by reading 1 target per line from stdin 175*333d2b36SAndroid Build Coastguard Worker awk ' 176*333d2b36SAndroid Build Coastguard Worker NF > 0 { 177*333d2b36SAndroid Build Coastguard Worker print gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))" "0 178*333d2b36SAndroid Build Coastguard Worker } 179*333d2b36SAndroid Build Coastguard Worker ' >"${newDeps}" 180*333d2b36SAndroid Build Coastguard Workerelse # start with no deps by clearing file 181*333d2b36SAndroid Build Coastguard Worker : >"${newDeps}" 182*333d2b36SAndroid Build Coastguard Workerfi 183*333d2b36SAndroid Build Coastguard Worker 184*333d2b36SAndroid Build Coastguard Worker# extend deps by appending targets from command-line 185*333d2b36SAndroid Build Coastguard Workerfor idx in "${!targets[*]}"; do 186*333d2b36SAndroid Build Coastguard Worker echo "${targets[${idx}]} 0" >>"${newDeps}" 187*333d2b36SAndroid Build Coastguard Workerdone 188*333d2b36SAndroid Build Coastguard Worker 189*333d2b36SAndroid Build Coastguard Worker# remove duplicates and start with new, old and all the same 190*333d2b36SAndroid Build Coastguard Workersort -u <"${newDeps}" >"${allDeps}" 191*333d2b36SAndroid Build Coastguard Workercp "${allDeps}" "${newDeps}" 192*333d2b36SAndroid Build Coastguard Workercp "${allDeps}" "${oldDeps}" 193*333d2b36SAndroid Build Coastguard Worker 194*333d2b36SAndroid Build Coastguard Worker# report depth of dependenciens when showProgress 195*333d2b36SAndroid Build Coastguard Workerdepth=0 196*333d2b36SAndroid Build Coastguard Worker 197*333d2b36SAndroid Build Coastguard Workerwhile [ $(wc -l < "${newDeps}") -gt 0 ]; do 198*333d2b36SAndroid Build Coastguard Worker if ${showProgress}; then 199*333d2b36SAndroid Build Coastguard Worker echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2 200*333d2b36SAndroid Build Coastguard Worker fi 201*333d2b36SAndroid Build Coastguard Worker depth=$(expr ${depth} + 1) 202*333d2b36SAndroid Build Coastguard Worker ( # recalculate dependencies by combining unique inputs of new deps w. old 203*333d2b36SAndroid Build Coastguard Worker cut -d\ -f1 "${newDeps}" | getDeps "${depth}" 204*333d2b36SAndroid Build Coastguard Worker cat "${oldDeps}" 205*333d2b36SAndroid Build Coastguard Worker ) | sort -n | awk ' 206*333d2b36SAndroid Build Coastguard Worker BEGIN { 207*333d2b36SAndroid Build Coastguard Worker prev = "" 208*333d2b36SAndroid Build Coastguard Worker } 209*333d2b36SAndroid Build Coastguard Worker { 210*333d2b36SAndroid Build Coastguard Worker depth = $NF 211*333d2b36SAndroid Build Coastguard Worker $NF = "" 212*333d2b36SAndroid Build Coastguard Worker gsub(/\s*$/, "") 213*333d2b36SAndroid Build Coastguard Worker if ($0 != prev) { 214*333d2b36SAndroid Build Coastguard Worker print gensub(/\s*$/, "", "g")" "depth 215*333d2b36SAndroid Build Coastguard Worker } 216*333d2b36SAndroid Build Coastguard Worker prev = $0 217*333d2b36SAndroid Build Coastguard Worker } 218*333d2b36SAndroid Build Coastguard Worker ' >"${allDeps}" 219*333d2b36SAndroid Build Coastguard Worker # recalculate new dependencies as net additions to old dependencies 220*333d2b36SAndroid Build Coastguard Worker set +e 221*333d2b36SAndroid Build Coastguard Worker diff "${oldDeps}" "${allDeps}" --old-line-format='' \ 222*333d2b36SAndroid Build Coastguard Worker --new-line-format='%L' --unchanged-line-format='' > "${newDeps}" 223*333d2b36SAndroid Build Coastguard Worker set -e 224*333d2b36SAndroid Build Coastguard Worker # recalculate old dependencies for next iteration 225*333d2b36SAndroid Build Coastguard Worker cp "${allDeps}" "${oldDeps}" 226*333d2b36SAndroid Build Coastguard Workerdone 227*333d2b36SAndroid Build Coastguard Worker 228*333d2b36SAndroid Build Coastguard Worker# found all deps -- clean up last iteration of old and new 229*333d2b36SAndroid Build Coastguard Workerrm -f "${oldDeps}" 230*333d2b36SAndroid Build Coastguard Workerrm -f "${newDeps}" 231*333d2b36SAndroid Build Coastguard Worker 232*333d2b36SAndroid Build Coastguard Workerif ${showProgress}; then 233*333d2b36SAndroid Build Coastguard Worker echo $(wc -l < "${allDeps}")" targets" >&2 234*333d2b36SAndroid Build Coastguard Workerfi 235*333d2b36SAndroid Build Coastguard Worker 236*333d2b36SAndroid Build Coastguard Workerawk -v sep="${sep}" '{ 237*333d2b36SAndroid Build Coastguard Worker depth = $NF 238*333d2b36SAndroid Build Coastguard Worker $NF = "" 239*333d2b36SAndroid Build Coastguard Worker gsub(/\s*$/, "") 240*333d2b36SAndroid Build Coastguard Worker print depth sep $0 241*333d2b36SAndroid Build Coastguard Worker}' "${allDeps}" | sort -n 242*333d2b36SAndroid Build Coastguard Worker 243*333d2b36SAndroid Build Coastguard Workerif ${interactive}; then 244*333d2b36SAndroid Build Coastguard Worker echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2 245*333d2b36SAndroid Build Coastguard Worker read answer 246*333d2b36SAndroid Build Coastguard Worker case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac 247*333d2b36SAndroid Build Coastguard Workerelse 248*333d2b36SAndroid Build Coastguard Worker rm -fr "${tmpFiles}" 249*333d2b36SAndroid Build Coastguard Workerfi 250