parameters: (filename, names, overrides=None, properties=None)
return_statement: return refined
docstring: Parse a qmake compatible file of build system macros and convert it to a
      dictionary.  A macro is a name/value pair.  The dictionary is returned or
      None if any of the overrides was invalid.
  
      filename is the name of the file to parse.
      names is a list of the macro names to extract from the file.
      overrides is an optional list of macro names and values that modify those
      found in the file.  They are of the form "name=value" (in which case the
      value replaces the value found in the file) or "name+=value" (in which case
      the value is appended to the value found in the file).
      properties is an optional dictionary of property name and values that are
      used to resolve any expressions of the form "$[name]" in the file.
docstring_summary: Parse a qmake compatible file of build system macros and convert it to a
      dictionary.  A macro is a name/value pair.  The dictionary is returned or
      None if any of the overrides was invalid.
docstring_tokens: Parse a qmake compatible file of build system macros and convert it to a dictionary . A macro is a name / value pair . The dictionary is returned or None if any of the overrides was invalid .
function: def parse_build_macros(filename, names, overrides=None, properties=None):
      """Parse a qmake compatible file of build system macros and convert it to a
      dictionary.  A macro is a name/value pair.  The dictionary is returned or
      None if any of the overrides was invalid.
  
      filename is the name of the file to parse.
      names is a list of the macro names to extract from the file.
      overrides is an optional list of macro names and values that modify those
      found in the file.  They are of the form "name=value" (in which case the
      value replaces the value found in the file) or "name+=value" (in which case
      the value is appended to the value found in the file).
      properties is an optional dictionary of property name and values that are
      used to resolve any expressions of the form "$[name]" in the file.
      """
      # Validate and convert the overrides to a dictionary.
      orides = {}
  
      if overrides is not None:
          for oride in overrides:
              prefix = ""
              name_end = oride.find("+=")
  
              if name_end >= 0:
                  prefix = "+"
                  val_start = name_end + 2
              else:
                  name_end = oride.find("=")
  
                  if name_end >= 0:
                      val_start = name_end + 1
                  else:
                      return None
  
              name = oride[:name_end]
  
              if name not in names:
                  return None
  
              orides[name] = prefix + oride[val_start:]
  
      # This class defines a file like object that handles the nested include()
      # directives in qmake files.
      class qmake_build_file_reader:
          def __init__(self, filename):
              self.filename = filename
              self.currentfile = None
              self.filestack = []
              self.pathstack = []
              self.cond_fname = None
              self._openfile(filename)
  
          def _openfile(self, filename):
              try:
                  f = open(filename, 'r')
              except IOError:
                  # If this file is conditional then don't raise an error.
                  if self.cond_fname == filename:
                      return
  
                  error("Unable to open %s" % filename)
  
              if self.currentfile:
                  self.filestack.append(self.currentfile)
                  self.pathstack.append(self.path)
  
              self.currentfile = f
              self.path = os.path.dirname(filename)
  
          def readline(self):
              line = self.currentfile.readline()
              sline = line.strip()
  
              if self.cond_fname and sline == '}':
                  # The current condition is closed.
                  self.cond_fname = None
                  line = self.currentfile.readline()
              elif sline.startswith('exists(') and sline.endswith('{'):
                  # A new condition is opened so extract the filename.
                  self.cond_fname = self._normalise(sline[:-1].strip()[7:-1].strip())
                  line = self.currentfile.readline()
              elif sline.startswith('include('):
                  nextfile = self._normalise(sline[8:-1].strip())
                  self._openfile(nextfile)
                  return self.readline()
  
              if not line:
                  self.currentfile.close()
  
                  if self.filestack:
                      self.currentfile = self.filestack.pop()
                      self.path = self.pathstack.pop()
                      return self.readline()
  
              return line
  
          # Normalise a filename by expanding any environment variables and
          # making sure it is absolute.
          def _normalise(self, fname):
              if "$(" in fname:
                  fname = os.path.normpath(self._expandvars(fname))
  
              if not os.path.isabs(fname):
                  fname = os.path.join(self.path, fname)
  
              return fname
  
          # Expand the environment variables in a filename.
          def _expandvars(self, fname):
              i = 0
              while True:
                  m = re.search(r'\$\((\w+)\)', fname[i:])
                  if not m:
                      break
  
                  i, j = m.span(0)
                  name = m.group(1)
                  if name in os.environ:
                      tail = fname[j:]
                      fname = fname[:i] + os.environ[name]
                      i = len(fname)
                      fname += tail
                  else:
                      i = j
  
              return fname
  
      f = qmake_build_file_reader(filename)
  
      # Get everything into a dictionary.
      raw = {
          "DIR_SEPARATOR":        os.sep,
          "LITERAL_WHITESPACE":   " ",
          "LITERAL_DOLLAR":       "$",
          "LITERAL_HASH":         "#"
      }
  
      line = f.readline()
      while line:
          # Handle line continuations.
          while len(line) > 1 and line[-2] == "\\":
              line = line[:-2]
  
              next = f.readline()
  
              if next:
                  line = line + next
              else:
                  break
  
          line = line.strip()
  
          # Ignore comments.
          if line and line[0] != "#":
              assstart = line.find("+")
              if assstart > 0 and line[assstart + 1] == '=':
                  adding = True
                  assend = assstart + 1
              else:
                  adding = False
                  assstart = line.find("=")
                  assend = assstart
  
              if assstart > 0:
                  lhs = line[:assstart].strip()
                  rhs = line[assend + 1:].strip()
  
                  # Remove the escapes for any quotes.
                  rhs = rhs.replace(r'\"', '"').replace(r"\'", "'")
  
                  if adding and rhs != "":
                      orig_rhs = raw.get(lhs)
                      if orig_rhs is not None:
                          rhs = orig_rhs + " " + rhs
  
                  raw[lhs] = _expand_macro_value(raw, rhs, properties)
  
          line = f.readline()
  
      # Go through the raw dictionary extracting the macros we need and
      # resolving any macro expansions.  First of all, make sure every macro has
      # a value.
      refined = {}
  
      for m in names:
          refined[m] = ""
  
      macro_prefix = "QMAKE_"
  
      for lhs in list(raw.keys()):
          # Strip any prefix.
          if lhs.startswith(macro_prefix):
              reflhs = lhs[len(macro_prefix):]
          else:
              reflhs = lhs
  
          # See if we are interested in this one.
          if reflhs not in names:
              continue
  
          rhs = raw[lhs]
  
          # Expand any POSIX style environment variables.
          pleadin = ["$$(", "$("]
  
          for pl in pleadin:
              estart = rhs.find(pl)
  
              if estart >= 0:
                  nstart = estart + len(pl)
                  break
          else:
              estart = -1
  
          while estart >= 0:
              eend = rhs[nstart:].find(")")
  
              if eend < 0:
                  break
  
              eend = nstart + eend
  
              name = rhs[nstart:eend]
  
              try:
                  env = os.environ[name]
              except KeyError:
                  env = ""
  
              rhs = rhs[:estart] + env + rhs[eend + 1:]
  
              for pl in pleadin:
                  estart = rhs.find(pl)
  
                  if estart >= 0:
                      nstart = estart + len(pl)
                      break
              else:
                  estart = -1
  
          # Expand any Windows style environment variables.
          estart = rhs.find("%")
  
          while estart >= 0:
              eend = rhs[estart + 1:].find("%")
  
              if eend < 0:
                  break
  
              eend = estart + 1 + eend
  
              name = rhs[estart + 1:eend]
  
              try:
                  env = os.environ[name]
              except KeyError:
                  env = ""
  
              rhs = rhs[:estart] + env + rhs[eend + 1:]
  
              estart = rhs.find("%")
  
          refined[reflhs] = rhs
  
      # Handle the user overrides.
      for lhs in list(orides.keys()):
          rhs = refined[lhs]
          oride = orides[lhs]
  
          if oride.find("+") == 0:
              if rhs:
                  rhs = rhs + " " + oride[1:]
              else:
                  rhs = oride[1:]
          else:
              rhs = oride
  
          refined[lhs] = rhs
  
      return refined
function_tokens: def parse_build_macros ( filename , names , overrides = None , properties = None ) : # Validate and convert the overrides to a dictionary. orides = { } if overrides is not None : for oride in overrides : prefix = "" name_end = oride . find ( "+=" ) if name_end >= 0 : prefix = "+" val_start = name_end + 2 else : name_end = oride . find ( "=" ) if name_end >= 0 : val_start = name_end + 1 else : return None name = oride [ : name_end ] if name not in names : return None orides [ name ] = prefix + oride [ val_start : ] # This class defines a file like object that handles the nested include() # directives in qmake files. class qmake_build_file_reader : def __init__ ( self , filename ) : self . filename = filename self . currentfile = None self . filestack = [ ] self . pathstack = [ ] self . cond_fname = None self . _openfile ( filename ) def _openfile ( self , filename ) : try : f = open ( filename , 'r' ) except IOError : # If this file is conditional then don't raise an error. if self . cond_fname == filename : return error ( "Unable to open %s" % filename ) if self . currentfile : self . filestack . append ( self . currentfile ) self . pathstack . append ( self . path ) self . currentfile = f self . path = os . path . dirname ( filename ) def readline ( self ) : line = self . currentfile . readline ( ) sline = line . strip ( ) if self . cond_fname and sline == '}' : # The current condition is closed. self . cond_fname = None line = self . currentfile . readline ( ) elif sline . startswith ( 'exists(' ) and sline . endswith ( '{' ) : # A new condition is opened so extract the filename. self . cond_fname = self . _normalise ( sline [ : - 1 ] . strip ( ) [ 7 : - 1 ] . strip ( ) ) line = self . currentfile . readline ( ) elif sline . startswith ( 'include(' ) : nextfile = self . _normalise ( sline [ 8 : - 1 ] . strip ( ) ) self . _openfile ( nextfile ) return self . readline ( ) if not line : self . currentfile . close ( ) if self . filestack : self . currentfile = self . filestack . pop ( ) self . path = self . pathstack . pop ( ) return self . readline ( ) return line # Normalise a filename by expanding any environment variables and # making sure it is absolute. def _normalise ( self , fname ) : if "$(" in fname : fname = os . path . normpath ( self . _expandvars ( fname ) ) if not os . path . isabs ( fname ) : fname = os . path . join ( self . path , fname ) return fname # Expand the environment variables in a filename. def _expandvars ( self , fname ) : i = 0 while True : m = re . search ( r'\$\((\w+)\)' , fname [ i : ] ) if not m : break i , j = m . span ( 0 ) name = m . group ( 1 ) if name in os . environ : tail = fname [ j : ] fname = fname [ : i ] + os . environ [ name ] i = len ( fname ) fname += tail else : i = j return fname f = qmake_build_file_reader ( filename ) # Get everything into a dictionary. raw = { "DIR_SEPARATOR" : os . sep , "LITERAL_WHITESPACE" : " " , "LITERAL_DOLLAR" : "$" , "LITERAL_HASH" : "#" } line = f . readline ( ) while line : # Handle line continuations. while len ( line ) > 1 and line [ - 2 ] == "\\" : line = line [ : - 2 ] next = f . readline ( ) if next : line = line + next else : break line = line . strip ( ) # Ignore comments. if line and line [ 0 ] != "#" : assstart = line . find ( "+" ) if assstart > 0 and line [ assstart + 1 ] == '=' : adding = True assend = assstart + 1 else : adding = False assstart = line . find ( "=" ) assend = assstart if assstart > 0 : lhs = line [ : assstart ] . strip ( ) rhs = line [ assend + 1 : ] . strip ( ) # Remove the escapes for any quotes. rhs = rhs . replace ( r'\"' , '"' ) . replace ( r"\'" , "'" ) if adding and rhs != "" : orig_rhs = raw . get ( lhs ) if orig_rhs is not None : rhs = orig_rhs + " " + rhs raw [ lhs ] = _expand_macro_value ( raw , rhs , properties ) line = f . readline ( ) # Go through the raw dictionary extracting the macros we need and # resolving any macro expansions.  First of all, make sure every macro has # a value. refined = { } for m in names : refined [ m ] = "" macro_prefix = "QMAKE_" for lhs in list ( raw . keys ( ) ) : # Strip any prefix. if lhs . startswith ( macro_prefix ) : reflhs = lhs [ len ( macro_prefix ) : ] else : reflhs = lhs # See if we are interested in this one. if reflhs not in names : continue rhs = raw [ lhs ] # Expand any POSIX style environment variables. pleadin = [ "$$(" , "$(" ] for pl in pleadin : estart = rhs . find ( pl ) if estart >= 0 : nstart = estart + len ( pl ) break else : estart = - 1 while estart >= 0 : eend = rhs [ nstart : ] . find ( ")" ) if eend < 0 : break eend = nstart + eend name = rhs [ nstart : eend ] try : env = os . environ [ name ] except KeyError : env = "" rhs = rhs [ : estart ] + env + rhs [ eend + 1 : ] for pl in pleadin : estart = rhs . find ( pl ) if estart >= 0 : nstart = estart + len ( pl ) break else : estart = - 1 # Expand any Windows style environment variables. estart = rhs . find ( "%" ) while estart >= 0 : eend = rhs [ estart + 1 : ] . find ( "%" ) if eend < 0 : break eend = estart + 1 + eend name = rhs [ estart + 1 : eend ] try : env = os . environ [ name ] except KeyError : env = "" rhs = rhs [ : estart ] + env + rhs [ eend + 1 : ] estart = rhs . find ( "%" ) refined [ reflhs ] = rhs # Handle the user overrides. for lhs in list ( orides . keys ( ) ) : rhs = refined [ lhs ] oride = orides [ lhs ] if oride . find ( "+" ) == 0 : if rhs : rhs = rhs + " " + oride [ 1 : ] else : rhs = oride [ 1 : ] else : rhs = oride refined [ lhs ] = rhs return refined