[Mesa-dev] [PATCH 1/2] scons: add ParseSourcesMak method

Chia-I Wu olvaffe at gmail.com
Thu Aug 18 02:48:14 PDT 2011


From: Chia-I Wu <olv at lunarg.com>

ParseSourcesMak() parses sources.mak in the source directory and returns
the files defined by the specified variables.  It can be used like

  sources = env.ParseSourcesMak(['C_SOURCES'])
---
 scons/custom.py      |   19 ++++++++++
 scons/sources_mak.py |   96 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+), 0 deletions(-)
 create mode 100644 scons/sources_mak.py

diff --git a/scons/custom.py b/scons/custom.py
index df7ac93..2ddd0a2 100644
--- a/scons/custom.py
+++ b/scons/custom.py
@@ -42,6 +42,7 @@ import SCons.Scanner
 
 import fixes
 
+import sources_mak
 
 def quietCommandLines(env):
     # Quiet command lines
@@ -229,6 +230,23 @@ def createPkgConfigMethods(env):
     env.AddMethod(pkg_use_modules, 'PkgUseModules')
 
 
+def parse_sources_mak(env, names):
+    parser = sources_mak.SourcesMakParser()
+    src = env.File('sources.mak').srcnode()
+    variables = parser.parse(src.abspath)
+
+    all_files = []
+    for name in names:
+        val = variables[name]
+        files = [env.File(f) for f in val.split(' ') if f]
+        all_files.extend(files)
+
+    return all_files
+
+def createParseSourcesMakMethod(env):
+    env.AddMethod(parse_sources_mak, 'ParseSourcesMak')
+
+
 def generate(env):
     """Common environment generation code"""
 
@@ -240,6 +258,7 @@ def generate(env):
     createConvenienceLibBuilder(env)
     createCodeGenerateMethod(env)
     createPkgConfigMethods(env)
+    createParseSourcesMakMethod(env)
 
     # for debugging
     #print env.Dump()
diff --git a/scons/sources_mak.py b/scons/sources_mak.py
new file mode 100644
index 0000000..ae4b47e
--- /dev/null
+++ b/scons/sources_mak.py
@@ -0,0 +1,96 @@
+"""sources.mak Parser
+
+The syntax of sources.mak is a very small subset of GNU Make.
+"""
+
+class SourcesMakParser(object):
+    def __init__(self):
+        self._reset()
+
+    def _reset(self):
+        self.variables = {}
+        self.line_cont = ''
+
+    def _next_dereference(self, val, cur):
+        deref_pos = val.find('$', cur)
+        if deref_pos < 0:
+            return (-1, -1)
+        elif val[deref_pos + 1] != '(':
+            raise RuntimeError('non-variable dereference')
+
+        deref_end = val.find(')', deref_pos + 2)
+        if deref_end < 0:
+            raise RuntimeError('unterminated variable dereference')
+
+        return (deref_pos, deref_end + 1)
+
+    def _expand_value(self, val):
+        expanded = ''
+        cur = 0
+        while True:
+            deref_pos, deref_end = self._next_dereference(val, cur)
+            if deref_pos < 0:
+                expanded += val[cur:]
+                break
+
+            deref = val[(deref_pos + 2):(deref_end - 1)]
+            expanded += val[cur:deref_pos] + self.variables[deref]
+            cur = deref_end
+
+        return expanded
+
+    def _parse_definition(self, line):
+        op_pos = line.find('=')
+        op_end = op_pos + 1
+        if op_pos < 0:
+            raise RuntimeError('not a definition %s')
+
+        if op_pos > 0 and line[op_pos - 1] in [':', '+']:
+            op_pos -= 1
+        else:
+            raise RuntimeError('only := and += are supported')
+
+        # set op, name, and val
+        op = line[op_pos:op_end]
+        name = line[:op_pos].strip()
+        val = self._expand_value(line[op_end:].lstrip())
+
+        if op == ':=':
+            self.variables[name] = val
+        elif op == '+=':
+            self.variables[name] += ' ' + val
+
+    def _parse_line(self, line):
+        # more lines to come
+        if line and line[-1] == '\\':
+            line = line[:-1].strip() + ' '
+            self.line_cont += line
+            return
+
+        # combine with previous lines
+        if self.line_cont:
+            line = self.line_cont + line.lstrip()
+            self.line_cont = ''
+        
+        if line:
+            begins_with_tab = (line[0] == '\t')
+
+            line = line.lstrip()
+            if line[0] != '#':
+                if begins_with_tab:
+                    raise RuntimeError('recipe line not supported')
+                else:
+                    self._parse_definition(line)
+
+    def parse(self, filename):
+        """Parse a source list file."""
+        fp = open(filename)
+        lines = fp.read().splitlines()
+        fp.close()
+
+        self._reset()
+        
+        for line in lines:
+            self._parse_line(line)
+
+        return self.variables
-- 
1.7.5.4



More information about the mesa-dev mailing list