Please note:The SCons wiki is now restored from the attack in March 2013. All old passwords have been invalidated. Please reset your password if you have an account. If you note missing pages, please report them to webmaster@scons.org. Also, new account creation is currently disabled due to an ongoing spam flood (2013/08/27).

Attachment 'nsis-with-modifications-for-linux-and-includes.py'

Download

   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 import platform
  37 
  38 is_linux = (platform.system() == 'Linux')
  39 
  40 def nsis_parse( sources, keyword, multiple, nsisdefines ):
  41   """
  42   A function that knows how to read a .nsi file and figure
  43   out what files are referenced, or find the 'OutFile' line.
  44 
  45 
  46   sources is a list of nsi files.
  47   keyword is the command ('File' or 'OutFile') to look for
  48   multiple is true if you want all the args as a list, false if you
  49   just want the first one.
  50   """
  51   stuff = []
  52   current_ignored = 0
  53   for s in sources:
  54     c = s.get_contents()
  55     linenum = 0
  56     for l in c.split('\n'):
  57       linenum += 1
  58       try:
  59         semi = l.find(';')
  60         if (semi != -1):
  61           l = l[:semi]
  62         hash = l.find('#')
  63         if (hash != -1):
  64           l = l[:hash]
  65         # Look for the keyword
  66         l = l.strip()
  67         spl = l.split(None,1)
  68         if len(spl) == 1 and current_ignored > 0 and spl[0].capitalize() == '!endif':
  69           current_ignored -= 1
  70         elif len(spl) > 1:
  71           if current_ignored > 0 and spl[0].capitalize() in [ '!ifdef', '!ifmacrodef', '!ifndef' ]:
  72             current_ignored += 1
  73           elif current_ignored == 0 and spl[0].capitalize() == '!ifdef' and spl[1] not in nsisdefines:
  74             current_ignored += 1
  75           elif current_ignored == 0 and spl[0].capitalize() == '!ifndef' and spl[1] in nsisdefines:
  76             current_ignored += 1
  77           elif current_ignored == 0 and spl[0].capitalize() == keyword.capitalize():
  78             arg = spl[1]
  79             if keyword.capitalize() == 'File' and arg.lower().startswith('/oname') and len(spl) > 1:
  80               arg = spl[2]
  81             if arg.startswith('"') and arg.endswith('"'):
  82               arg = arg[1:-1]
  83             if multiple:
  84               stuff += [ arg ]
  85             else:
  86               return arg
  87       except:
  88         print "in %(source)s, line %(linenum)d\n" % { 'source': s, 'linenum': linenum }
  89         raise
  90   return stuff
  91 
  92 
  93 def nsis_path( filename, nsisdefines, rootdir ):
  94   """
  95   Do environment replacement, and prepend with the SCons root dir if
  96   necessary
  97   """
  98   # We can't do variables defined by NSIS itself (like $INSTDIR),
  99   # only user supplied ones (like ${FOO})
 100   varPos = filename.find('${')
 101   while varPos != -1:
 102     endpos = filename.find('}',varPos)
 103     assert endpos != -1
 104     if not nsisdefines.has_key(filename[varPos+2:endpos]):
 105       raise KeyError ("Could not find %s in NSISDEFINES" % filename[varPos+2:endpos])
 106     val = nsisdefines[filename[varPos+2:endpos]]
 107     if type(val) == list:
 108       if varPos != 0 or endpos+1 != len(filename):
 109         raise Exception("Can't use lists on variables that aren't complete filenames")
 110       return val
 111     filename = filename[0:varPos] + val + filename[endpos+1:]
 112     varPos = filename.find('${')
 113   return filename
 114 
 115 
 116 def nsis_scanner( node, env, path, source_dir = None):
 117   """
 118   The scanner that looks through the source .nsi files and finds all lines
 119   that are the 'File' command, fixes the directories etc, and returns them.
 120   """
 121   nodes = node.rfile()
 122   if not node.exists():
 123     return []
 124   nodes = []
 125   if source_dir is None:
 126     try:
 127       source_dir = env['NSISSRCDIR']
 128     except:
 129       source_dir = node.get_dir()
 130   for include in nsis_parse([node],'file',1, env['NSISDEFINES']):
 131     exp = nsis_path(include,env['NSISDEFINES'],source_dir)
 132     if type(exp) != list:
 133       exp = [exp]
 134     for p in exp:
 135       for filename in env.Glob( os.path.abspath(
 136         os.path.join(str(source_dir),p))):
 137           # Why absolute path?  Cause it breaks mysteriously without it :(
 138           nodes.append(filename)
 139   for include in nsis_parse([node],'!include',1, env['NSISDEFINES']):
 140     exp = nsis_path(include,env['NSISDEFINES'],source_dir)
 141     if type(exp) != list:
 142       exp = [exp]
 143     for p in exp:
 144       if p not in [ 'LogicLib.nsh', 'MUI2.nsh' ]:
 145         # get ../bin/makensis and go up two directories
 146         nsis_install_location = os.path.dirname(os.path.dirname(env['NSIS']))
 147         filename = os.path.abspath(os.path.join(nsis_install_location, 'share', 'nsis', 'Include', p))
 148         if not os.path.isfile(filename):
 149           filename = os.path.abspath(os.path.join(str(source_dir),p))
 150         # Why absolute path?  Cause it breaks mysteriously without it :(
 151         nodes.append(filename)
 152         nodes += nsis_scanner(env.File(filename), env, path, source_dir = source_dir)
 153   return nodes
 154 
 155 
 156 def nsis_emitter( source, target, env ):
 157   """
 158   The emitter changes the target name to match what the command actually will
 159   output, which is the argument to the OutFile command.
 160   """
 161   nsp = nsis_parse(source,'outfile',0, env['NSISDEFINES'])
 162   if not nsp:
 163     return (target,source)
 164   x  = (
 165     nsis_path(nsp,env['NSISDEFINES'],''),
 166     source)
 167   return x
 168 
 169 def quoteIfSpaced(text):
 170   if ' ' in text:
 171     return '"'+text+'"'
 172   else:
 173     return text
 174 
 175 def toString(item,env):
 176   if type(item) == list:
 177     ret = ''
 178     for i in item:
 179       if ret:
 180         ret += ' '
 181       val = toString(i,env)
 182       if ' ' in val:
 183         val = "'"+val+"'"
 184       ret += val
 185     return ret
 186   else:
 187     # For convienence, handle #s here
 188     if str(item).startswith('#'):
 189       item = env.File(item).get_abspath()
 190     return str(item)
 191 
 192 def runNSIS(source,target,env,for_signature):
 193   ret = env['NSIS']+" "
 194   if env.has_key('NSISFLAGS'):
 195     for flag in env['NSISFLAGS']:
 196       ret += flag
 197       ret += ' '
 198   if env.has_key('NSISDEFINES'):
 199     for d in env['NSISDEFINES']:
 200       if is_linux:
 201         ret += '-D'+d
 202       else:
 203         ret += '/D'+d
 204       if env['NSISDEFINES'][d]:
 205         ret +='='+quoteIfSpaced(toString(env['NSISDEFINES'][d],env))
 206       ret += ' '
 207   if is_linux:
 208     ret += '-- '
 209   for s in source:
 210     ret += quoteIfSpaced(str(s))
 211   return ret
 212 
 213 def generate(env):
 214   """
 215   This function adds NSIS support to your environment.
 216   """
 217   env['BUILDERS']['Installer'] = SCons.Builder.Builder(generator=runNSIS,
 218                                  src_suffix='.nsi',
 219                                  emitter=nsis_emitter)
 220   env.Append(SCANNERS = SCons.Scanner.Scanner( function = nsis_scanner,
 221              skeys = ['.nsi','.nsh']))
 222   if not env.has_key('NSISDEFINES'):
 223     env['NSISDEFINES'] = {}
 224   env['NSIS'] = find_nsis(env)
 225 
 226 def find_nsis(env):
 227   """
 228   Try and figure out if NSIS is installed on this machine, and if so,
 229   where.
 230   """
 231   if SCons.Util.can_read_reg:
 232     # If we can read the registry, get the NSIS command from it
 233     try:
 234       k = SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
 235                                   'SOFTWARE\\NSIS')
 236       val, tok = SCons.Util.RegQueryValueEx(k,None)
 237       ret = val + os.path.sep + 'makensis.exe'
 238       if os.path.exists(ret):
 239         return '"' + ret + '"'
 240       else:
 241         return None
 242     except:
 243       pass # Couldn't find the key, just act like we can't read the registry
 244 
 245   # Hope it's on the path
 246   return env.WhereIs('makensis' + env['PROGSUFFIX'])
 247 
 248 def exists(env):
 249   """
 250   Is NSIS findable on this machine?
 251   """
 252   if find_nsis(env) != None:
 253     return 1
 254   return 0

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.