I wanted to write a scons build system which can build my project on both Windows and POSIX platforms. Since my project ultimately builds Windows executables, it needs some cross-compiling. Since SCons doesn't have built-in support for it, I had to add it myself. For this purpose, I wrote this tool definition for MinGW. It's based on the original MinGW tool definition which comes with SCons 0.96.90. My windres patch is also applied.

On top of what the original tool definition does, this tool searches for MinGW using more than one common prefixes and sets Windows prefixes and suffixes for output files.

To use it, save crossmingw.py in a directory called scons-tools and use:

   1 env.Tool('crossmingw', toolpath = ['scons-tools'])

A complete usage example can be found in NSIS CVS repository. The tool is located under SCons/Tools. It's used in SCons/Config/gnu.

crossmingw.py

   1 import os
   2 import os.path
   3 import string
   4 
   5 import SCons.Action
   6 import SCons.Builder
   7 import SCons.Tool
   8 import SCons.Util
   9 
  10 # This is what we search for to find mingw:
  11 prefixes = SCons.Util.Split("""
  12   mingw32-
  13   i386-mingw32msvc-
  14   i486-mingw32msvc-
  15   i586-mingw32msvc-
  16   i686-mingw32msvc-
  17 """)
  18 
  19 def find(env):
  20   for prefix in prefixes:
  21     # First search in the SCons path and then the OS path:
  22     if env.WhereIs(prefix + 'gcc') or SCons.Util.WhereIs(prefix + 'gcc'):
  23       return prefix
  24 
  25   return ''
  26 
  27 def shlib_generator(target, source, env, for_signature):
  28   cmd = SCons.Util.CLVar(['$SHLINK', '$SHLINKFLAGS'])
  29 
  30   dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
  31   if dll: cmd.extend(['-o', dll])
  32 
  33   cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
  34 
  35   implib = env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX')
  36   if implib: cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature))
  37 
  38   def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')
  39   if def_target: cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature))
  40 
  41   return [cmd]
  42 
  43 def shlib_emitter(target, source, env):
  44   dll = env.FindIxes(target, 'SHLIBPREFIX', 'SHLIBSUFFIX')
  45   no_import_lib = env.get('no_import_lib', 0)
  46 
  47   if not dll:
  48     raise SCons.Errors.UserError, "A shared library should have exactly one target with the suffix: %s" % env.subst("$SHLIBSUFFIX")
  49 
  50   if not no_import_lib and \
     not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
  51 
  52     # Append an import library to the list of targets.
  53     target.append(env.ReplaceIxes(dll,
  54                     'SHLIBPREFIX', 'SHLIBSUFFIX',
  55                     'LIBPREFIX', 'LIBSUFFIX'))
  56 
  57   # Append a def file target if there isn't already a def file target
  58   # or a def file source. There is no option to disable def file
  59   # target emitting, because I can't figure out why someone would ever
  60   # want to turn it off.
  61   def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')
  62   def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')
  63   if not def_source and not def_target:
  64     target.append(env.ReplaceIxes(dll,
  65                   'SHLIBPREFIX', 'SHLIBSUFFIX',
  66                   'WIN32DEFPREFIX', 'WIN32DEFSUFFIX'))
  67 
  68   return (target, source)
  69 
  70 
  71 shlib_action = SCons.Action.CommandGenerator(shlib_generator)
  72 
  73 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
  74 
  75 res_builder = SCons.Builder.Builder(action=res_action, suffix='.o',
  76                   source_scanner=SCons.Tool.SourceFileScanner)
  77 SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
  78 
  79 def generate(env):
  80   mingw_prefix = find(env)
  81 
  82   if mingw_prefix:
  83     dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc'))
  84 
  85     # The mingw bin directory must be added to the path:
  86     path = env['ENV'].get('PATH', [])
  87     if not path:
  88       path = []
  89     if SCons.Util.is_String(path):
  90       path = string.split(path, os.pathsep)
  91 
  92     env['ENV']['PATH'] = string.join([dir] + path, os.pathsep)
  93 
  94   # Most of mingw is the same as gcc and friends...
  95   gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas']
  96   for tool in gnu_tools:
  97     SCons.Tool.Tool(tool)(env)
  98 
  99   #... but a few things differ:
 100   env['CC'] = mingw_prefix + 'gcc'
 101   env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
 102   env['CXX'] = mingw_prefix + 'g++'
 103   env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
 104   env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
 105   env['SHLINKCOM']   = shlib_action
 106   env.Append(SHLIBEMITTER = [shlib_emitter])
 107   # This line isn't required and breaks C++ linking
 108   #env['LINK'] = mingw_prefix + 'g++'
 109   env['AS'] = mingw_prefix + 'as'
 110   env['AR'] = mingw_prefix + 'ar'
 111   env['RANLIB'] = mingw_prefix + 'ranlib'
 112   env['WIN32DEFPREFIX']    = ''
 113   env['WIN32DEFSUFFIX']    = '.def'
 114   env['SHOBJSUFFIX'] = '.o'
 115   env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
 116 
 117   env['RC'] = mingw_prefix + 'windres'
 118   env['RCFLAGS'] = SCons.Util.CLVar('')
 119   env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)'
 120   env['RCINCPREFIX'] = '--include-dir '
 121   env['RCINCSUFFIX'] = ''
 122   env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET'
 123   env['BUILDERS']['RES'] = res_builder
 124 
 125   # Some setting from the platform also have to be overridden:
 126   env['OBJPREFIX']    = ''
 127   env['OBJSUFFIX']    = '.o'
 128   env['LIBPREFIX']    = 'lib'
 129   env['LIBSUFFIX']    = '.a'
 130   env['SHOBJPREFIX']  = '$OBJPREFIX'
 131   env['SHOBJSUFFIX']  = '$OBJSUFFIX'
 132   env['PROGPREFIX']   = ''
 133   env['PROGSUFFIX']   = '.exe'
 134   env['LIBPREFIX']    = ''
 135   env['LIBSUFFIX']    = '.lib'
 136   env['SHLIBPREFIX']  = ''
 137   env['SHLIBSUFFIX']  = '.dll'
 138   env['LIBPREFIXES']  = [ '$LIBPREFIX' ]
 139   env['LIBSUFFIXES']  = [ '$LIBSUFFIX' ]
 140 
 141 def exists(env):
 142   return find(env)

CrossCompilingMingw (last edited 2008-03-12 02:47:09 by localhost)