Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.

This is a Tool for SCons that can parse a Nullsoft Scriptable Installation System (NSIS) script (a .nsi file) and determine its dependencies and its actual target name. The following file can be be copied to site-packages/scons/SCons/Tools/ and it will 'just work'.

Enhancement note: This uses glob.glob to find the source files if they have filename glob chars, but if (as is usual) the sources are built by some other builder, you might want to use one of the techniques in BuildDirGlob to find them instead, so scons gets all the dependencies correct.

Feel free to modify and improve as you wish.

The original script for the tool is provided below.

   1 # NSIS Support for SCons
   2 # Written by Mike Elkins, January 2004
   3 # Provided 'as-is', it works for me!
   4 
   5 
   6 """
   7 This tool provides SCons support for the Nullsoft Scriptable Install System
   8 a windows installer builder available at http://nsis.sourceforge.net/home
   9 
  10 
  11 To use it you must copy this file into the scons/SCons/Tools directory or use
  12 the tooldir arg in the Tool function and put a line like 'env.Tool("NSIS")'
  13 into your file. Then you can do 'env.Installer("foobar")' which will read foobar.nsi and
  14 create dependencies on all the files you put into your installer, so that if
  15 anything changes your installer will be rebuilt.  It also makes the target
  16 equal to the filename you specified in foobar.nsi.  Wildcards are handled correctly.
  17 
  18 In addition, if you set NSISDEFINES to a dictionary, those variables will be passed
  19 to NSIS.
  20 """
  21 
  22 
  23 
  24 import SCons.Builder
  25 import SCons.Util
  26 import SCons.Scanner
  27 # NOTE (4 September 2007):  The following import line was part of the original
  28 # code on this wiki page before this date.  It's not used anywhere below and
  29 # therefore unnecessary.  The SCons.Sig module is going away after 0.97.0d20070809,
  30 # so the line should be removed from your copy of this module.  There may be a
  31 # do-nothing SCons.Sig module that generates a warning message checked in, so existing
  32 # configurations won't break and can help point people to the line that needs removing.
  33 #import SCons.Sig
  34 import os.path
  35 import glob
  36 
  37 
  38 def nsis_parse( sources, keyword, multiple ):
  39   """
  40   A function that knows how to read a .nsi file and figure
  41   out what files are referenced, or find the 'OutFile' line.
  42 
  43 
  44   sources is a list of nsi files.
  45   keyword is the command ('File' or 'OutFile') to look for
  46   multiple is true if you want all the args as a list, false if you
  47   just want the first one.
  48   """
  49   stuff = []
  50   for s in sources:
  51     c = s.get_contents()
  52     for l in c.split('\n'):
  53       semi = l.find(';')
  54       if semi != -1:
  55         l = l[:semi]
  56       hash = l.find('#')
  57       if hash != -1:
  58         l = l[:hash]
  59       # Look for the keyword
  60       l = l.strip()
  61       spl = l.split(None,1)
  62       if len(spl) > 1:
  63         if spl[0].lower() == keyword.lower():
  64           arg = spl[1]
  65           if arg.startswith('"') and arg.endswith('"'):
  66             arg = arg[1:-1]
  67           if multiple:
  68             stuff += [ arg ]
  69           else:
  70             return arg
  71   return stuff
  72 
  73 
  74 def nsis_path( filename, nsisdefines, rootdir ):
  75   """
  76   Do environment replacement, and prepend with the SCons root dir if
  77   necessary
  78   """
  79   # We can't do variables defined by NSIS itself (like $INSTDIR),
  80   # only user supplied ones (like ${FOO})
  81   varPos = filename.find('${')
  82   while varPos != -1:
  83     endpos = filename.find('}',varPos)
  84     assert endpos != -1
  85     if filename[varPos+2:endpos] not in nsisdefines:
  86       raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
  87     val = nsisdefines[filename[varPos+2:endpos]]
  88     if type(val) == list:
  89       if varPos != 0 or endpos+1 != len(filename):
  90         raise Exception("Can't use lists on variables that aren't complete filenames")
  91       return val
  92     filename = filename[:varPos] + val + filename[endpos+1:]
  93     varPos = filename.find('${')
  94   return filename
  95 
  96 
  97 def nsis_scanner( node, env, path ):
  98   """
  99   The scanner that looks through the source .nsi files and finds all lines
 100   that are the 'File' command, fixes the directories etc, and returns them.
 101   """
 102   nodes = node.rfile()
 103   if not node.exists():
 104     return []
 105   nodes = []
 106   source_dir = node.get_dir()
 107   for include in nsis_parse([node],'file',1):
 108     exp = nsis_path(include,env['NSISDEFINES'],source_dir)
 109     if type(exp) != list:
 110       exp = [exp]
 111     for p in exp:
 112       for filename in glob.glob( os.path.abspath(
 113         os.path.join(str(source_dir),p))):
 114           # Why absolute path?  Cause it breaks mysteriously without it :(
 115           nodes.append(filename)
 116   return nodes
 117 
 118 
 119 def nsis_emitter( source, target, env ):
 120   """
 121   The emitter changes the target name to match what the command actually will
 122   output, which is the argument to the OutFile command.
 123   """
 124   nsp = nsis_parse(source,'outfile',0)
 125   if not nsp:
 126     return (target,source)
 127   x  = (
 128     nsis_path(nsp,env['NSISDEFINES'],''),
 129     source)
 130   return x
 131 
 132 def quoteIfSpaced(text):
 133   if ' ' in text:
 134     return '"'+text+'"'
 135   else:
 136     return text
 137 
 138 def toString(item,env):
 139   if type(item) == list:
 140     ret = ''
 141     for i in item:
 142       if ret:
 143         ret += ' '
 144       val = toString(i,env)
 145       if ' ' in val:
 146         val = "'"+val+"'"
 147       ret += val
 148     return ret
 149   else:
 150     # For convienence, handle #s here
 151     if str(item).startswith('#'):
 152       item = env.File(item).get_abspath()
 153     return str(item)
 154 
 155 def runNSIS(source,target,env,for_signature):
 156   ret = env['NSIS']+" "
 157   if 'NSISFLAGS' in env:
 158     for flag in env['NSISFLAGS']:
 159       ret += flag
 160       ret += ' '
 161   if 'NSISDEFINES' in env:
 162     for d in env['NSISDEFINES']:
 163       ret += '/D'+d
 164       if env['NSISDEFINES'][d]:
 165         ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
 166       ret += ' '
 167   for s in source:
 168     ret += quoteIfSpaced(str(s))
 169   return ret
 170 
 171 def generate(env):
 172   """
 173   This function adds NSIS support to your environment.
 174   """
 175   env['BUILDERS']['Installer'] = SCons.Builder.Builder(generator=runNSIS,
 176                                  src_suffix='.nsi',
 177                                  emitter=nsis_emitter)
 178   env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
 179              skeys = ['.nsi']))
 180   if 'NSISDEFINES' not in env:
 181     env['NSISDEFINES'] = {}
 182   env['NSIS'] = find_nsis(env)
 183 
 184 def find_nsis(env):
 185   """
 186   Try and figure out if NSIS is installed on this machine, and if so,
 187   where.
 188   """
 189   if SCons.Util.can_read_reg:
 190     # If we can read the registry, get the NSIS command from it
 191     try:
 192       k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 193                                   'SOFTWARE\\NSIS')
 194       val, tok = SCons.Util.RegQueryValueEx(k,None)
 195       ret = val + os.path.sep + 'makensis.exe'
 196       if os.path.exists(ret):
 197         return '"' + ret + '"'
 198       else:
 199         return None
 200     except:
 201       pass # Couldn't find the key, just act like we can't read the registry
 202   # Hope it's on the path
 203   return env.WhereIs('makensis.exe')
 204 
 205 def exists(env):
 206   """
 207   Is NSIS findable on this machine?
 208   """
 209   return find_nsis(env) != None:

NsisSconsTool (last edited 2012-02-03 00:20:15 by bc-proxy-2)