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 
   4 import SCons.Action
   5 import SCons.Builder
   6 import SCons.Tool
   7 import SCons.Util
   8 
   9 # This is what we search for to find mingw:
  10 prefixes = SCons.Util.Split("""
  11   mingw32-
  12   i386-mingw32msvc-
  13   i486-mingw32msvc-
  14   i586-mingw32msvc-
  15   i686-mingw32msvc-
  16   i686-pc-mingw32-
  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 \
  51      not env.FindIxes(target, 'LIBPREFIX', 'LIBSUFFIX'):
  52 
  53     # Append an import library to the list of targets.
  54     target.append(env.ReplaceIxes(dll,
  55                     'SHLIBPREFIX', 'SHLIBSUFFIX',
  56                     'LIBPREFIX', 'LIBSUFFIX'))
  57 
  58   # Append a def file target if there isn't already a def file target
  59   # or a def file source. There is no option to disable def file
  60   # target emitting, because I can't figure out why someone would ever
  61   # want to turn it off.
  62   def_source = env.FindIxes(source, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')
  63   def_target = env.FindIxes(target, 'WIN32DEFPREFIX', 'WIN32DEFSUFFIX')
  64   if not def_source and not def_target:
  65     target.append(env.ReplaceIxes(dll,
  66                   'SHLIBPREFIX', 'SHLIBSUFFIX',
  67                   'WIN32DEFPREFIX', 'WIN32DEFSUFFIX'))
  68 
  69   return (target, source)
  70 
  71 
  72 shlib_action = SCons.Action.CommandGenerator(shlib_generator)
  73 # in Scons 2.1 the line above needs to be replace with:
  74 #shlib_action = SCons.Action.Action(shlib_generator, generator=1)
  75 
  76 res_action = SCons.Action.Action('$RCCOM', '$RCCOMSTR')
  77 
  78 res_builder = SCons.Builder.Builder(action=res_action, suffix='.o',
  79                   source_scanner=SCons.Tool.SourceFileScanner)
  80 SCons.Tool.SourceFileScanner.add_scanner('.rc', SCons.Defaults.CScan)
  81 
  82 def generate(env):
  83   mingw_prefix = find(env)
  84 
  85   if mingw_prefix:
  86     dir = os.path.dirname(env.WhereIs(mingw_prefix + 'gcc') or SCons.Util.WhereIs(mingw_prefix + 'gcc'))
  87 
  88     # The mingw bin directory must be added to the path:
  89     path = env['ENV'].get('PATH', [])
  90     if not path:
  91       path = []
  92     if SCons.Util.is_String(path):
  93       path = path.split(os.pathsep)
  94 
  95     env['ENV']['PATH'] = os.pathsep.join([dir] + path)
  96 
  97   # Most of mingw is the same as gcc and friends...
  98   gnu_tools = ['gcc', 'g++', 'gnulink', 'ar', 'gas']
  99   for tool in gnu_tools:
 100     SCons.Tool.Tool(tool)(env)
 101 
 102   #... but a few things differ:
 103   env['CC'] = mingw_prefix + 'gcc'
 104   env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
 105   env['CXX'] = mingw_prefix + 'g++'
 106   env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
 107   env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared')
 108   env['SHLINKCOM']   = shlib_action
 109   env.Append(SHLIBEMITTER = [shlib_emitter])
 110   # This line isn't required and breaks C++ linking
 111   #env['LINK'] = mingw_prefix + 'g++'
 112   env['AS'] = mingw_prefix + 'as'
 113   env['AR'] = mingw_prefix + 'ar'
 114   env['RANLIB'] = mingw_prefix + 'ranlib'
 115   env['WIN32DEFPREFIX']    = ''
 116   env['WIN32DEFSUFFIX']    = '.def'
 117   env['SHOBJSUFFIX'] = '.o'
 118   env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
 119 
 120   env['RC'] = mingw_prefix + 'windres'
 121   env['RCFLAGS'] = SCons.Util.CLVar('')
 122   env['RCINCFLAGS'] = '$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)'
 123   env['RCINCPREFIX'] = '--include-dir '
 124   env['RCINCSUFFIX'] = ''
 125   env['RCCOM'] = '$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET'
 126   env['BUILDERS']['RES'] = res_builder
 127 
 128   # Some setting from the platform also have to be overridden:
 129   env['OBJPREFIX']    = ''
 130   env['OBJSUFFIX']    = '.o'
 131   env['LIBPREFIX']    = 'lib'
 132   env['LIBSUFFIX']    = '.a'
 133   env['SHOBJPREFIX']  = '$OBJPREFIX'
 134   env['SHOBJSUFFIX']  = '$OBJSUFFIX'
 135   env['PROGPREFIX']   = ''
 136   env['PROGSUFFIX']   = '.exe'
 137   env['LIBPREFIX']    = ''
 138   env['LIBSUFFIX']    = '.lib'
 139   env['SHLIBPREFIX']  = ''
 140   env['SHLIBSUFFIX']  = '.dll'
 141   env['LIBPREFIXES']  = [ '$LIBPREFIX' ]
 142   env['LIBSUFFIXES']  = [ '$LIBSUFFIX' ]
 143 
 144 def exists(env):
 145   return find(env)

CrossCompilingMingw (last edited 2011-11-25 14:04:03 by MarcinWojdyr)