1*0988482fSSean Morrissey#!/usr/bin/env python3 2*0988482fSSean Morrissey# SPDX-License-Identifier: BSD-3-Clause 3*0988482fSSean Morrissey# Copyright(c) 2021 Intel Corporation 4*0988482fSSean Morrissey# 5*0988482fSSean Morrissey 6*0988482fSSean Morrisseyimport argparse 7*0988482fSSean Morrisseyimport fileinput 8*0988482fSSean Morrisseyimport sys 9*0988482fSSean Morrisseyfrom os.path import abspath, relpath, join 10*0988482fSSean Morrisseyfrom pathlib import Path 11*0988482fSSean Morrisseyfrom mesonbuild import mesonmain 12*0988482fSSean Morrissey 13*0988482fSSean Morrissey 14*0988482fSSean Morrisseydef args_parse(): 15*0988482fSSean Morrissey "parse arguments and return the argument object back to main" 16*0988482fSSean Morrissey parser = argparse.ArgumentParser(description="This script can be used to remove includes which are not in use\n") 17*0988482fSSean Morrissey parser.add_argument('-b', '--build_dir', type=str, default='build', 18*0988482fSSean Morrissey help="The path to the build directory in which the IWYU tool was used in.") 19*0988482fSSean Morrissey parser.add_argument('-d', '--sub_dir', type=str, default='', 20*0988482fSSean Morrissey help="The sub-directory to remove headers from.") 21*0988482fSSean Morrissey parser.add_argument('file', type=Path, 22*0988482fSSean Morrissey help="The path to the IWYU log file or output from stdin.") 23*0988482fSSean Morrissey 24*0988482fSSean Morrissey return parser.parse_args() 25*0988482fSSean Morrissey 26*0988482fSSean Morrissey 27*0988482fSSean Morrisseydef run_meson(args): 28*0988482fSSean Morrissey "Runs a meson command logging output to process-iwyu.log" 29*0988482fSSean Morrissey with open('process-iwyu.log', 'a') as sys.stdout: 30*0988482fSSean Morrissey ret = mesonmain.run(args, abspath('meson')) 31*0988482fSSean Morrissey sys.stdout = sys.__stdout__ 32*0988482fSSean Morrissey return ret 33*0988482fSSean Morrissey 34*0988482fSSean Morrissey 35*0988482fSSean Morrisseydef remove_includes(filepath, include, build_dir): 36*0988482fSSean Morrissey "Attempts to remove include, if it fails then revert to original state" 37*0988482fSSean Morrissey with open(filepath) as f: 38*0988482fSSean Morrissey lines = f.readlines() # Read lines when file is opened 39*0988482fSSean Morrissey 40*0988482fSSean Morrissey with open(filepath, 'w') as f: 41*0988482fSSean Morrissey for ln in lines: # Removes the include passed in 42*0988482fSSean Morrissey if not ln.startswith(include): 43*0988482fSSean Morrissey f.write(ln) 44*0988482fSSean Morrissey 45*0988482fSSean Morrissey # run test build -> call meson on the build folder, meson compile -C build 46*0988482fSSean Morrissey ret = run_meson(['compile', '-C', build_dir]) 47*0988482fSSean Morrissey if (ret == 0): # Include is not needed -> build is successful 48*0988482fSSean Morrissey print('SUCCESS') 49*0988482fSSean Morrissey else: 50*0988482fSSean Morrissey # failed, catch the error 51*0988482fSSean Morrissey # return file to original state 52*0988482fSSean Morrissey with open(filepath, 'w') as f: 53*0988482fSSean Morrissey f.writelines(lines) 54*0988482fSSean Morrissey print('FAILED') 55*0988482fSSean Morrissey 56*0988482fSSean Morrissey 57*0988482fSSean Morrisseydef get_build_config(builddir, condition): 58*0988482fSSean Morrissey "returns contents of rte_build_config.h" 59*0988482fSSean Morrissey with open(join(builddir, 'rte_build_config.h')) as f: 60*0988482fSSean Morrissey return [ln for ln in f.readlines() if condition(ln)] 61*0988482fSSean Morrissey 62*0988482fSSean Morrissey 63*0988482fSSean Morrisseydef uses_libbsd(builddir): 64*0988482fSSean Morrissey "return whether the build uses libbsd or not" 65*0988482fSSean Morrissey return bool(get_build_config(builddir, lambda ln: 'RTE_USE_LIBBSD' in ln)) 66*0988482fSSean Morrissey 67*0988482fSSean Morrissey 68*0988482fSSean Morrisseydef process(args): 69*0988482fSSean Morrissey "process the iwyu output on a set of files" 70*0988482fSSean Morrissey filepath = None 71*0988482fSSean Morrissey build_dir = abspath(args.build_dir) 72*0988482fSSean Morrissey directory = args.sub_dir 73*0988482fSSean Morrissey 74*0988482fSSean Morrissey print("Warning: The results of this script may include false positives which are required for different systems", 75*0988482fSSean Morrissey file=sys.stderr) 76*0988482fSSean Morrissey 77*0988482fSSean Morrissey keep_str_fns = uses_libbsd(build_dir) # check for libbsd 78*0988482fSSean Morrissey if keep_str_fns: 79*0988482fSSean Morrissey print("Warning: libbsd is present, build will fail to detect incorrect removal of rte_string_fns.h", 80*0988482fSSean Morrissey file=sys.stderr) 81*0988482fSSean Morrissey # turn on werror 82*0988482fSSean Morrissey run_meson(['configure', build_dir, '-Dwerror=true']) 83*0988482fSSean Morrissey # Use stdin if no iwyu_tool out file given 84*0988482fSSean Morrissey for line in fileinput.input(args.file): 85*0988482fSSean Morrissey if 'should remove' in line: 86*0988482fSSean Morrissey # If the file path in the iwyu_tool output is an absolute path it 87*0988482fSSean Morrissey # means the file is outside of the dpdk directory, therefore ignore it. 88*0988482fSSean Morrissey # Also check to see if the file is within the specified sub directory. 89*0988482fSSean Morrissey filename = line.split()[0] 90*0988482fSSean Morrissey if (filename != abspath(filename) and 91*0988482fSSean Morrissey directory in filename): 92*0988482fSSean Morrissey filepath = relpath(join(build_dir, filename)) 93*0988482fSSean Morrissey elif line.startswith('-') and filepath: 94*0988482fSSean Morrissey include = '#include ' + line.split()[2] 95*0988482fSSean Morrissey print(f"Remove {include} from {filepath} ... ", end='', flush=True) 96*0988482fSSean Morrissey if keep_str_fns and '<rte_string_fns.h>' in include: 97*0988482fSSean Morrissey print('skipped') 98*0988482fSSean Morrissey continue 99*0988482fSSean Morrissey remove_includes(filepath, include, build_dir) 100*0988482fSSean Morrissey else: 101*0988482fSSean Morrissey filepath = None 102*0988482fSSean Morrissey 103*0988482fSSean Morrissey 104*0988482fSSean Morrisseydef main(): 105*0988482fSSean Morrissey process(args_parse()) 106*0988482fSSean Morrissey 107*0988482fSSean Morrissey 108*0988482fSSean Morrisseyif __name__ == '__main__': 109*0988482fSSean Morrissey main() 110