add gcc-like -I include dir options to ipdl compiler
authorChris Jones <jones.chris.g@gmail.com>
Tue, 07 Jul 2009 17:52:38 -0500
changeset 35761 2c99c4920e6d46758bcc44b46662bc8988a5d189
parent 35760 c51a123ddba49c6641c59c92ebb6b1597a6ce60a
child 35762 8524cccb39eb3b28e5e17542d8e30921459b1942
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
add gcc-like -I include dir options to ipdl compiler
ipc/ipdl/ipdl.py
ipc/ipdl/ipdl/__init__.py
ipc/ipdl/ipdl/parser.py
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -39,24 +39,27 @@ def log(minv, fmt, *args):
     if _verbosity >= minv:
         print >>sys.stderr, fmt % args
 
 # process command line
 
 op = optparse.OptionParser(usage='ipdl.py [options] IPDLfiles...')
 op.add_option('-d', '--output-dir', dest='outputdir', default='.',
               help='Directory in which to put generated headers')
+op.add_option('-I', '--include', dest='includedirs', action='append',
+              help='Additional directory to search for included protocol specifications')
 op.add_option('-v', '--verbose', dest='verbosity', default=1, action='count',
               help='Verbose logging (specify -vv or -vvv for very verbose logging)')
 op.add_option('-q', '--quiet', dest='verbosity', action='store_const', const=0,
               help="Suppress logging output")
 
 options, files = op.parse_args()
 _verbosity = options.verbosity
 codedir = options.outputdir
+includedirs = [ os.path.abspath(incdir) for incdir in options.includedirs ]
 
 if not len(files):
     op.error("No IPDL files specified")
 
 log(1, 'Generated headers will be placed in "%s"', codedir)
 
 allprotocols = []
 
@@ -67,17 +70,17 @@ for f in files:
         filename = '<stdin>'
     else:
         fd = open(f)
         filename = f
 
     specstring = fd.read()
     fd.close()
 
-    ast = ipdl.parse(specstring, filename)
+    ast = ipdl.parse(specstring, filename, includedirs=includedirs)
 
     allprotocols.append,('%sProtocolMsgStart' % ast.protocol.name)
 
     log(2, 'checking types')
     if not ipdl.typecheck(ast):
         print >>sys.stderr, 'Specification is not well typed.'
         sys.exit(1)
 
--- a/ipc/ipdl/ipdl/__init__.py
+++ b/ipc/ipdl/ipdl/__init__.py
@@ -37,18 +37,18 @@ from cStringIO import StringIO
 
 from ipdl.cgen import IPDLCodeGen
 from ipdl.lower import LowerToCxx
 from ipdl.parser import Parser
 from ipdl.type import TypeCheck
 
 from ipdl.cxx.cgen import CxxCodeGen
 
-def parse(specstring, filename='<stdin>'):
-    return Parser().parse(specstring, filename)
+def parse(specstring, filename='/stdin', includedirs=[ ]):
+    return Parser().parse(specstring, os.path.abspath(filename), includedirs)
 
 def typecheck(ast, errout=sys.stderr):
     '''Returns True iff |ast| is well typed.  Print errors to |errout| if
     it is not.'''
     return TypeCheck().check(ast, errout)
 
 def gencxx(ast, outdir):
     for hdr in LowerToCxx().lower(ast):
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -54,47 +54,59 @@ class Parser:
     # there is one Parser per file
     current = None
     parseStack = [ ]
     parsed = { }
 
     def __init__(self, debug=0):
         self.debug = debug
         self.filename = None
+        self.includedirs = None
         self.loc = None         # not always up to date
         self.lexer = None
         self.parser = None
         self.tu = TranslationUnit()
 
-    def parse(self, input, filename):
-        realpath = os.path.abspath(filename)
-        if realpath in Parser.parsed:
-            return Parser.parsed[realpath].tu
+    def parse(self, input, filename, includedirs):
+        assert os.path.isabs(filename)
+
+        if filename in Parser.parsed:
+            return Parser.parsed[filename].tu
 
         self.lexer = lex.lex(debug=self.debug,
                              optimize=not self.debug,
                              lextab="ipdl_lextab",
                              outputdir=_thisdir)
         self.parser = yacc.yacc(debug=self.debug,
                                 optimize=not self.debug,
                                 tabmodule="ipdl_yacctab",
                                 outputdir=_thisdir)
         self.filename = filename
-        self.tu.filename = realpath
+        self.includedirs = includedirs
+        self.tu.filename = filename
 
-        Parser.parsed[realpath] = self
+        Parser.parsed[filename] = self
         Parser.parseStack.append(Parser.current)
         Parser.current = self
 
         ast = self.parser.parse(input=input, lexer=self.lexer,
                                  debug=self.debug)
 
         Parser.current = Parser.parseStack.pop()
         return ast
 
+    def resolveIncludePath(self, filepath):
+        '''Return the absolute path from which the possibly partial
+|filepath| should be read, or |None| if |filepath| can't be located.'''
+        for incdir in self.includedirs +[ '' ]:
+            realpath = os.path.join(incdir, filepath)
+            if os.path.isfile(realpath):
+                return realpath
+        return None
+
     # returns a GCC-style string representation of the include stack.
     # e.g.,
     #   in file included from 'foo.ipdl', line 120:
     #   in file included from 'bar.ipd', line 12:
     # which can be printed above a proper error message or warning
     @staticmethod
     def includeStackString():
         s = ''
@@ -200,19 +212,24 @@ def p_PreambleStmt(p):
 def p_CxxIncludeStmt(p):
     """CxxIncludeStmt : INCLUDE STRING"""
     p[0] = CxxInclude(locFromTok(p, 1), p[2])
 
 def p_ProtocolIncludeStmt(p):
     """ProtocolIncludeStmt : INCLUDE PROTOCOL STRING"""
     loc = locFromTok(p, 1)
     Parser.current.loc = loc
+    inc = ProtocolInclude(loc, p[3])
 
-    inc = ProtocolInclude(loc, p[3])
-    inc.tu = Parser().parse(open(inc.file).read(), inc.file)
+    path = Parser.current.resolveIncludePath(inc.file)
+    if path is None:
+        print >>sys.stderr, "error: can't locate protocol include file `%s'"% (inc.file)
+        inc.tu = TranslationUnit()
+    else:
+        inc.tu = Parser().parse(open(path).read(), path, Parser.current.includedirs)
     p[0] = inc
 
 def p_UsingStmt(p):
     """UsingStmt : USING CxxType"""
     p[0] = UsingStmt(locFromTok(p, 1), p[2])
 
 ##--------------------
 ## Protocol definition