From 1e5f3ebb2982f8d7e414d5fc4808000b941563cc Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 6 Jan 2009 01:35:44 +0000 Subject: [PATCH] ccc: Introduce ArgList for keeping input argv & parsed Args together. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61780 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/ccc/ccclib/Arguments.py | 40 +++++++-- tools/ccc/ccclib/Driver.py | 160 +++++++++++++++++----------------- tools/ccc/ccclib/Jobs.py | 4 +- 3 files changed, 117 insertions(+), 87 deletions(-) diff --git a/tools/ccc/ccclib/Arguments.py b/tools/ccc/ccclib/Arguments.py index ef8466fd62..57793cbae3 100644 --- a/tools/ccc/ccclib/Arguments.py +++ b/tools/ccc/ccclib/Arguments.py @@ -209,29 +209,59 @@ class DerivedArg(ValueArg): def getValue(self, args): return self.value - def setValue(self, args): + def setValue(self, args, value): raise ValueError,"Cannot call setValue() on a DerivedArg." def render(self, args): return [self.value] +class ArgList: + """ArgList - Collect an input argv along with a set of parsed Args + and supporting information.""" + + def __init__(self, argv): + self.argv = list(argv) + self.args = [] + + # Support use as a simple arg list. + + def __iter__(self): + return iter(self.args) + + def append(self, arg): + self.args.append(arg) + + # Forwarding methods. + + def getValue(self, arg): + return arg.getValue(self.argv) + + def getValues(self, arg): + return arg.getValues(self.argv) + + def getSeparateValue(self, arg): + return arg.getSeparateValue(self.argv) + + def getJoinedValue(self, arg): + return arg.getJoinedValue(self.argv) + class OptionParser: def __init__(self): self.options = [] - + def addOption(self, opt): self.options.append(opt) - def chunkArgs(self, argv): + def parseArgs(self, argv): """ - chunkArgs([str]) -> [Arg] + parseArgs([str]) -> ArgList Parse command line into individual option instances. """ iargs = enumerate(argv) it = iter(iargs) - args = [] + args = ArgList(argv) for i,a in it: # FIXME: Handle '@' if not a: diff --git a/tools/ccc/ccclib/Driver.py b/tools/ccc/ccclib/Driver.py index 4bf0478a50..c07631e8db 100644 --- a/tools/ccc/ccclib/Driver.py +++ b/tools/ccc/ccclib/Driver.py @@ -27,7 +27,7 @@ class Driver(object): def __init__(self): self.parser = Arguments.createOptionParser() - def run(self, args): + def run(self, argv): # FIXME: Things to support from environment: GCC_EXEC_PREFIX, # COMPILER_PATH, LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS, # QA_OVERRIDE_GCC3_OPTIONS, ...? @@ -39,8 +39,8 @@ class Driver(object): cccPrintOptions = False cccPrintPhases = False cccUseDriverDriver = True - while args and args[0].startswith('-ccc-'): - opt,args = args[0][5:],args[1:] + while argv and argv[0].startswith('-ccc-'): + opt,argv = argv[0][5:],argv[1:] if opt == 'print-options': cccPrintOptions = True @@ -54,7 +54,7 @@ class Driver(object): else: raise ValueError,"Invalid ccc option: %r" % cccPrintOptions - options = self.parser.chunkArgs(args) + args = self.parser.parseArgs(argv) # FIXME: Ho hum I have just realized -Xarch_ is broken. We really # need to reparse the Arguments after they have been expanded by @@ -68,24 +68,24 @@ class Driver(object): # tied to it. if cccPrintOptions: - self.printOptions(args, options) + self.printOptions(args) sys.exit(0) - self.handleImmediateOptions(args, options) + self.handleImmediateOptions(args) if cccUseDriverDriver: - phases = self.buildPipeline(options, args) + phases = self.buildPipeline(args) else: - phases = self.buildNormalPipeline(options, args) + phases = self.buildNormalPipeline(args) if cccPrintPhases: - self.printPhases(args, phases) + self.printPhases(phases, args) sys.exit(0) if 0: print Util.pprint(phases) - jobs = self.bindPhases(phases, options, args) + jobs = self.bindPhases(phases, args) # FIXME: We should provide some basic sanity checking of the # pipeline as a "verification" sort of stage. For example, the @@ -100,18 +100,18 @@ class Driver(object): # Print in -### syntax. hasHashHashHash = None - for oi in options: - if oi.opt and oi.opt.name == '-###': - hasHashHashHash = oi + for arg in args: + if arg.opt and arg.opt.name == '-###': + hasHashHashHash = arg if hasHashHashHash: self.claim(hasHashHashHash) for j in jobs.iterjobs(): if isinstance(j, Jobs.Command): - print '"%s"' % '" "'.join(j.render(args)) + print '"%s"' % '" "'.join(j.render(argv)) elif isinstance(j, Jobs.PipedJob): for c in j.commands: - print '"%s" %c' % ('" "'.join(c.render(args)), + print '"%s" %c' % ('" "'.join(c.render(argv)), "| "[c is j.commands[-1]]) elif not isinstance(j, JobList): raise ValueError,'Encountered unknown job.' @@ -119,7 +119,7 @@ class Driver(object): for j in jobs.iterjobs(): if isinstance(j, Jobs.Command): - cmd_args = j.render(args) + cmd_args = j.render(argv) res = os.spawnvp(os.P_WAIT, cmd_args[0], cmd_args) if res: sys.exit(res) @@ -135,28 +135,28 @@ class Driver(object): def warning(self, message): print >>sys.stderr,'%s: %s' % (sys.argv[0], message) - def printOptions(self, args, options): - for i,oi in enumerate(options): - if isinstance(oi, Arguments.InputArg): + def printOptions(self, args): + for i,arg in enumerate(args): + if isinstance(arg, Arguments.InputArg): name = "" - elif isinstance(oi, Arguments.UnknownArg): + elif isinstance(arg, Arguments.UnknownArg): name = "" else: - assert oi.opt - name = oi.opt.name - if isinstance(oi, Arguments.MultipleValuesArg): - values = list(oi.getValues(args)) - elif isinstance(oi, Arguments.ValueArg): - values = [oi.getValue(args)] - elif isinstance(oi, Arguments.JoinedAndSeparateValuesArg): - values = [oi.getJoinedValue(args), oi.getSeparateValue(args)] + assert arg.opt + name = arg.opt.name + if isinstance(arg, Arguments.MultipleValuesArg): + values = list(args.getValues(arg)) + elif isinstance(arg, Arguments.ValueArg): + values = [args.getValue(arg)] + elif isinstance(arg, Arguments.JoinedAndSeparateValuesArg): + values = [args.getJoinedValue(arg), args.getSeparateValue(arg)] else: values = [] print 'Option %d - Name: "%s", Values: {%s}' % (i, name, ', '.join(['"%s"' % v for v in values])) - def printPhases(self, args, phases): + def printPhases(self, phases, args): def printPhase(p, f, steps, arch=None): if p in steps: return steps[p] @@ -168,14 +168,14 @@ class Driver(object): if isinstance(p, Phases.InputAction): phaseName = 'input' - inputStr = '"%s"' % p.filename.getValue(args) + inputStr = '"%s"' % args.getValue(p.filename) else: phaseName = p.phase.name inputs = [printPhase(i, f, steps, arch) for i in p.inputs] inputStr = '{%s}' % ', '.join(map(str, inputs)) if arch is not None: - phaseName += '-' + arch.getValue(args) + phaseName += '-' + args.getValue(arch) steps[p] = index = len(steps) print "%d: %s, %s, %s" % (index,phaseName,inputStr,p.type.name) return index @@ -183,7 +183,7 @@ class Driver(object): for phase in phases: printPhase(phase, sys.stdout, steps) - def handleImmediateOptions(self, args, options): + def handleImmediateOptions(self, args): # FIXME: Some driver Arguments are consumed right off the bat, # like -dumpversion. Currently the gcc-dd handles these # poorly, so we should be ok handling them upfront instead of @@ -199,37 +199,37 @@ class Driver(object): # FIXME: Do we want to report "argument unused" type errors in the # presence of things like -dumpmachine and -print-search-dirs? # Probably not. - for oi in options: - if oi.opt is not None: - if oi.opt.name == '-dumpmachine': - print 'FIXME: %s' % oi.opt.name + for arg in args: + if arg.opt is not None: + if arg.opt.name == '-dumpmachine': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-dumpspecs': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-dumpspecs': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-dumpversion': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-dumpversion': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-file-name=': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-file-name=': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-multi-directory': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-multi-directory': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-multi-lib': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-multi-lib': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-prog-name=': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-prog-name=': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-libgcc-file-name': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-libgcc-file-name': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - elif oi.opt.name == '-print-search-dirs': - print 'FIXME: %s' % oi.opt.name + elif arg.opt.name == '-print-search-dirs': + print 'FIXME: %s' % arg.opt.name sys.exit(1) - def buildNormalPipeline(self, args, inputArgs): + def buildNormalPipeline(self, args): hasCombine = None hasSyntaxOnly = None hasDashC = hasDashE = hasDashS = None @@ -240,7 +240,7 @@ class Driver(object): for a in args: if isinstance(a, Arguments.InputArg): if inputType is None: - base,ext = os.path.splitext(a.getValue(inputArgs)) + base,ext = os.path.splitext(args.getValue(a)) if ext and ext in Types.kTypeSuffixMap: klass = Types.kTypeSuffixMap[ext] else: @@ -279,7 +279,7 @@ class Driver(object): elif a.opt.name == '-x': self.claim(a) inputTypeOpt = a - value = a.getValue(inputArgs) + value = args.getValue(a) if value in Types.kTypeSpecifierMap: inputType = Types.kTypeSpecifierMap[value] else: @@ -353,7 +353,7 @@ class Driver(object): assert finalPhaseOpt and finalPhaseOpt.opt # FIXME: Explain what type of input file is. Or just match # gcc warning. - self.warning("%s: %s input file unused when %s is present" % (input.getValue(inputArgs), + self.warning("%s: %s input file unused when %s is present" % (args.getValue(input), sequence[0].name, finalPhaseOpt.opt.name)) else: @@ -407,30 +407,30 @@ class Driver(object): return actions - def buildPipeline(self, args, inputArgs): + def buildPipeline(self, args): # FIXME: We need to handle canonicalization of the specified arch. archs = [] hasOutput = None hasDashM = hasSaveTemps = None - for o in args: - if o.opt is None: + for arg in args: + if arg.opt is None: continue - if isinstance(o, Arguments.ValueArg): - if o.opt.name == '-arch': - archs.append(o) - elif o.opt.name.startswith('-M'): - hasDashM = o - elif o.opt.name in ('-save-temps','--save-temps'): - hasSaveTemps = o + if isinstance(arg, Arguments.ValueArg): + if arg.opt.name == '-arch': + archs.append(arg) + elif arg.opt.name.startswith('-M'): + hasDashM = arg + elif arg.opt.name in ('-save-temps','--save-temps'): + hasSaveTemps = arg if not archs: # FIXME: Need to infer arch so that we sub -Xarch # correctly. archs.append(Arguments.DerivedArg('i386')) - actions = self.buildNormalPipeline(args, inputArgs) + actions = self.buildNormalPipeline(args) # FIXME: Use custom exception for this. # @@ -489,7 +489,7 @@ class Driver(object): return finalActions - def bindPhases(self, phases, args, inputArgs): + def bindPhases(self, phases, args): jobs = Jobs.JobList() finalOutput = None @@ -553,25 +553,25 @@ class Driver(object): if isinstance(phase, Phases.InputAction): return InputInfo(phase.filename, phase.type, phase.filename) elif isinstance(phase, Phases.BindArchAction): - archName = phase.arch.getValue(inputArgs) + archName = args.getValue(phase.arch) filteredArgs = [] - for oi in forwardArgs: - if oi.opt is None: - filteredArgs.append(oi) - elif oi.opt.name == '-arch': - if oi is phase.arch: - filteredArgs.append(oi) - elif oi.opt.name == '-Xarch_': + for arg in forwardArgs: + if arg.opt is None: + filteredArgs.append(arg) + elif arg.opt.name == '-arch': + if arg is phase.arch: + filteredArgs.append(arg) + elif arg.opt.name == '-Xarch_': # FIXME: gcc-dd has another conditional for passing # through, when the arch conditional array has an empty # string. Why? - if oi.getJoinedValue(inputArgs) == archName: + if args.getJoinedValue(arg) == archName: # FIXME: This is wrong, we don't want a # DerivedArg we want an actual parsed version # of this arg. - filteredArgs.append(Arguments.DerivedArg(oi.getSeparateValue(inputArgs))) + filteredArgs.append(Arguments.DerivedArg(args.getSeparateValue(arg))) else: - filteredArgs.append(oi) + filteredArgs.append(arg) return createJobs(phase.inputs[0], filteredArgs, canAcceptPipe, atTopLevel, phase.arch) @@ -631,7 +631,7 @@ class Driver(object): # # FIXME: gcc has some special case in here so that it doesn't # create output files if they would conflict with an input. - inputName = baseInput.getValue(inputArgs) + inputName = args.getValue(baseInput) if phase.type is Types.ImageType: namedOutput = "a.out" else: diff --git a/tools/ccc/ccclib/Jobs.py b/tools/ccc/ccclib/Jobs.py index 8ef8a03fc2..b7d4288788 100644 --- a/tools/ccc/ccclib/Jobs.py +++ b/tools/ccc/ccclib/Jobs.py @@ -22,8 +22,8 @@ class Command(Job): def render(self, args): argv = [self.executable] - for oi in self.args: - argv.extend(oi.render(args)) + for arg in self.args: + argv.extend(arg.render(args)) return argv def iterjobs(self):