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:

crossmingw.py

#!python importosimportos.pathimportSCons.ActionimportSCons.BuilderimportSCons.ToolimportSCons.Util# This is what we search for to find mingw:prefixes=SCons.Util.Split(""" mingw32- i386-mingw32msvc- i486-mingw32msvc- i586-mingw32msvc- i686-mingw32msvc- i686-pc-mingw32-""")deffind(env):forprefixinprefixes:# First search in the SCons path and then the OS path:ifenv.WhereIs(prefix+'gcc')orSCons.Util.WhereIs(prefix+'gcc'):returnprefixreturn''defshlib_generator(target,source,env,for_signature):cmd=SCons.Util.CLVar(['$SHLINK','$SHLINKFLAGS'])dll=env.FindIxes(target,'SHLIBPREFIX','SHLIBSUFFIX')ifdll:cmd.extend(['-o',dll])cmd.extend(['$SOURCES','$_LIBDIRFLAGS','$_LIBFLAGS'])implib=env.FindIxes(target,'LIBPREFIX','LIBSUFFIX')ifimplib:cmd.append('-Wl,--out-implib,'+implib.get_string(for_signature))def_target=env.FindIxes(target,'WIN32DEFPREFIX','WIN32DEFSUFFIX')ifdef_target:cmd.append('-Wl,--output-def,'+def_target.get_string(for_signature))return[cmd]defshlib_emitter(target,source,env):dll=env.FindIxes(target,'SHLIBPREFIX','SHLIBSUFFIX')no_import_lib=env.get('no_import_lib',0)ifnotdll:raiseSCons.Errors.UserError,"A shared library should have exactly one target with the suffix: %s"%env.subst("$SHLIBSUFFIX")ifnotno_import_liband \
notenv.FindIxes(target,'LIBPREFIX','LIBSUFFIX'):# Append an import library to the list of targets.target.append(env.ReplaceIxes(dll,'SHLIBPREFIX','SHLIBSUFFIX','LIBPREFIX','LIBSUFFIX'))# Append a def file target if there isn't already a def file target# or a def file source. There is no option to disable def file# target emitting, because I can't figure out why someone would ever# want to turn it off.def_source=env.FindIxes(source,'WIN32DEFPREFIX','WIN32DEFSUFFIX')def_target=env.FindIxes(target,'WIN32DEFPREFIX','WIN32DEFSUFFIX')ifnotdef_sourceandnotdef_target:target.append(env.ReplaceIxes(dll,'SHLIBPREFIX','SHLIBSUFFIX','WIN32DEFPREFIX','WIN32DEFSUFFIX'))return(target,source)shlib_action=SCons.Action.CommandGenerator(shlib_generator)# in Scons 2.1 the line above needs to be replace with:#shlib_action = SCons.Action.Action(shlib_generator, generator=1)res_action=SCons.Action.Action('$RCCOM','$RCCOMSTR')res_builder=SCons.Builder.Builder(action=res_action,suffix='.o',source_scanner=SCons.Tool.SourceFileScanner)SCons.Tool.SourceFileScanner.add_scanner('.rc',SCons.Defaults.CScan)defgenerate(env):mingw_prefix=find(env)ifmingw_prefix:dir=os.path.dirname(env.WhereIs(mingw_prefix+'gcc')orSCons.Util.WhereIs(mingw_prefix+'gcc'))# The mingw bin directory must be added to the path:path=env['ENV'].get('PATH',[])ifnotpath:path=[]ifSCons.Util.is_String(path):path=path.split(os.pathsep)env['ENV']['PATH']=os.pathsep.join([dir]+path)# Most of mingw is the same as gcc and friends...gnu_tools=['gcc','g++','gnulink','ar','gas']fortoolingnu_tools:SCons.Tool.Tool(tool)(env)#... but a few things differ:env['CC']=mingw_prefix+'gcc'env['SHCCFLAGS']=SCons.Util.CLVar('$CCFLAGS')env['CXX']=mingw_prefix+'g++'env['SHCXXFLAGS']=SCons.Util.CLVar('$CXXFLAGS')env['SHLINKFLAGS']=SCons.Util.CLVar('$LINKFLAGS -shared')env['SHLINKCOM']=shlib_actionenv.Append(SHLIBEMITTER=[shlib_emitter])# This line isn't required and breaks C++ linking#env['LINK'] = mingw_prefix + 'g++'env['AS']=mingw_prefix+'as'env['AR']=mingw_prefix+'ar'env['RANLIB']=mingw_prefix+'ranlib'env['WIN32DEFPREFIX']=''env['WIN32DEFSUFFIX']='.def'env['SHOBJSUFFIX']='.o'env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME']=1env['RC']=mingw_prefix+'windres'env['RCFLAGS']=SCons.Util.CLVar('')env['RCINCFLAGS']='$( ${_concat(RCINCPREFIX, CPPPATH, RCINCSUFFIX, __env__, RDirs, TARGET)} $)'env['RCINCPREFIX']='--include-dir 'env['RCINCSUFFIX']=''env['RCCOM']='$RC $RCINCFLAGS $RCINCPREFIX $SOURCE.dir $RCFLAGS -i $SOURCE -o $TARGET'env['BUILDERS']['RES']=res_builder# Some setting from the platform also have to be overridden:env['OBJPREFIX']=''env['OBJSUFFIX']='.o'env['LIBPREFIX']='lib'env['LIBSUFFIX']='.a'env['SHOBJPREFIX']='$OBJPREFIX'env['SHOBJSUFFIX']='$OBJSUFFIX'env['PROGPREFIX']=''env['PROGSUFFIX']='.exe'env['LIBPREFIX']=''env['LIBSUFFIX']='.lib'env['SHLIBPREFIX']=''env['SHLIBSUFFIX']='.dll'env['LIBPREFIXES']=['$LIBPREFIX']env['LIBSUFFIXES']=['$LIBSUFFIX']defexists(env):returnfind(env)