print "Using GNU tools configuration" Import('defenv') ### imports Import('FlagsConfigure') ### cross compiling def cross_env(env): if env['PLATFORM'] != 'win32': env.Tool('crossmingw', toolpath = [Dir('../Tools').rdir()]) ### flags def entry(x): if x == 'WinMain': x = '_WinMain@16' elif x == 'DllMain': x = '_DllMain@12' return '-Wl,-e%s' % x defenv['ENTRY_FLAG'] = entry defenv['MAP_FLAG'] = '-Wl,-Map,${TARGET.base}.map' defenv['EXCEPTION_FLAG'] = '' defenv['NODEFLIBS_FLAG'] = '-nostdlib -Wl,--exclude-libs,msvcrt.a' defenv['C_FLAG'] = '-xc' defenv['CPP_FLAG'] = '-xc++' defenv['ALIGN_FLAG'] = '-Wl,--file-alignment,512' defenv['CPP_REQUIRES_STDLIB'] = 1 defenv['SUBSYS_CON'] = '-Wl,--subsystem,console' defenv['MSVCRT_FLAG'] = '' defenv['STDCALL'] = ' __attribute__((__stdcall__))' ### defines defenv.Append(CPPDEFINES = [('NSISCALL', '$STDCALL')]) ### helper functions # on Mac OS X, programs built with g++ 4.0, stl and -s error out: # dyld: lazy symbol binding failed: lazy pointer not found # dyld: lazy pointer not found # # to avoid this, this function checks if -s works def TestStrip(ctx): c = """ #include int main() { std::vector v; return 0; } """ ctx.CheckLinkFlag('-s', run = 1, extension = '.cpp', code = c) ### debug if defenv['DEBUG']: defenv.Append(CCFLAGS = '-g') ### stub environment stub_env = defenv.Clone() cross_env(stub_env) stub_env.Append(CPPPATH = ['#$BUILD_CONFIG']) if not defenv['DEBUG']: stub_env.Append(CCFLAGS = ['-Os']) # optimize for size stub_env.Append(CCFLAGS = ['-Wall']) # all warnings stub_env.Append(CCFLAGS = ['-xc']) # force compile as c stub_env.Append(CCFLAGS = ['-fno-strict-aliasing']) # not safe for strict aliasing if not defenv['DEBUG'] and defenv['STRIP'] and defenv['STRIP_W32']: stub_env.Append(LINKFLAGS = ['-s']) # strip stub_env.Append(LINKFLAGS = ['-mwindows']) # build windows executables stub_env.Append(LINKFLAGS = ['$NODEFLIBS_FLAG']) # no standard libraries stub_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align stub_env.Append(LINKFLAGS = ['-Wl,-e,_WinMain@16']) # entry point stub_env.Append(LINKFLAGS = ['$MAP_FLAG']) # generate map file ### makensis environment makensis_env = defenv.Clone() makensis_env.Append(CPPPATH = ['#$BUILD_CONFIG']) if not defenv['DEBUG']: makensis_env.Append(CCFLAGS = ['-O2']) # optimize makensis_env.Append(CFLAGS = ['-Wall']) # all warnings makensis_env.Append(CXXFLAGS = ['-Wno-non-virtual-dtor']) # ignore virtual dtor warnings makensis_env.Append(CXXFLAGS = ['-Wall']) # all warnings conf = FlagsConfigure(makensis_env) conf.CheckLinkFlag('$MAP_FLAG') # generate map file if not defenv['DEBUG'] and defenv['STRIP'] and defenv['STRIP_CP']: TestStrip(conf) # strip conf.Finish() ### plugin environment plugin_env = defenv.Clone() cross_env(plugin_env) if not defenv['DEBUG']: plugin_env.Append(CCFLAGS = ['-Os']) # optimize for size plugin_env.Append(CCFLAGS = ['-Wall']) # level 3 warnings plugin_env.Append(CCFLAGS = ['-fno-strict-aliasing']) # not safe for strict aliasing if not defenv['DEBUG'] and defenv['STRIP'] and defenv['STRIP_W32']: plugin_env.Append(LINKFLAGS = ['-s']) # strip plugin_env.Append(LINKFLAGS = ['-mwindows']) # build windows executables plugin_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align plugin_env.Append(LINKFLAGS = ['$MAP_FLAG']) # generate map file plugin_env.Append(LINKFLAGS = ['-static-libgcc']) # remove libgcc*.dll dependency ### cross-platform util environment cp_util_env = defenv.Clone() cp_util_env.Append(CPPPATH = ['#$BUILD_CONFIG']) if not defenv['DEBUG']: cp_util_env.Append(CCFLAGS = ['-O2']) # optimize cp_util_env.Append(CCFLAGS = ['-Wall']) # all warnings cp_util_env.Append(CCFLAGS = ['-fno-strict-aliasing']) # not safe for strict aliasing conf = FlagsConfigure(cp_util_env) conf.CheckLinkFlag('$MAP_FLAG') # generate map file conf.Finish() ### util environment util_env = cp_util_env.Clone() cross_env(util_env) util_env.Append(LINKFLAGS = ['-mwindows']) # build windows executables util_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align conf = FlagsConfigure(util_env) if not defenv['DEBUG'] and defenv['STRIP'] and defenv['STRIP_W32']: util_env.Append(LINKFLAGS = ['-s']) # strip conf.Finish() ### cross-platform util environment adjustments conf = FlagsConfigure(cp_util_env) if not defenv['DEBUG'] and defenv['STRIP'] and defenv['STRIP_CP']: TestStrip(conf) # strip conf.Finish() ### test environment test_env = defenv.Clone() test_env.Append(CPPPATH = ['#$BUILD_CONFIG']) conf = FlagsConfigure(test_env) conf.Finish() ### weird GCC requirements # # GCC puts new PE sections, added by code, between other sections. # This is not good for the .ndata section because makensis changes # its size dynamically. This is not good if RVAs to sections below # it are saved in other places. The RVAs will point to garbage. # # To fix this, a linker script is provided. The linker script makes # sure the sections will be written in the correct order. # stub_env.Append(LINKFLAGS = ['-T', File('linker_script').rfile()]) # # GCC requires some functions from the CRT to be present, if certain # operations are done. For example, if a small string is assigned to # a larger buffer, GCC 3.4+ uses memset to fill the remaining of the # buffer with zeros. # def check_requirement(ctx, func, trigger): ctx.Message('Checking for %s requirement... ' % func) flags = ctx.env['LINKFLAGS'] ctx.env.Append(LINKFLAGS = ['$NODEFLIBS_FLAG']) ctx.env.Append(LINKFLAGS = ['-Wl,-e,___main']) test = """ int __main() { %s return 0; } """ % trigger result = not ctx.TryLink(test, '.c') ctx.Result(result) ctx.env['LINKFLAGS'] = flags return result def add_file_to_emitter(env, emitter_name, file): try: original_emitter = env[emitter_name] if type(original_emitter) == list: original_emitter = original_emitter[0] except KeyError: original_emitter = None def emitter(target, source, env): if original_emitter: target, source = original_emitter(target, source, env) if '$NODEFLIBS_FLAG' not in env['LINKFLAGS']: return target, source return target, source + [file] env[emitter_name] = emitter def add_file(file): file = File(file) add_file_to_emitter(stub_env, 'PROGEMITTER', file) add_file_to_emitter(util_env, 'PROGEMITTER', file) add_file_to_emitter(plugin_env, 'SHLIBEMITTER', file) cenv = defenv.Clone() cross_env(cenv) conf = cenv.Configure(custom_tests = { 'CheckRequirement' : check_requirement }) memcpy_test = """ struct s // gcc 3 { char c[128]; } t = { "test" }; char a[] = // gcc 4 {'/', 'F', 'I' ,'L', 'L', 'S', 'C', 'R', 'E', 'E', 'N', 0}; int i; for (i = 0; i < 100; i++) // avoid a and t being optimized out { i += a[i] ^ t.c[i]; } return i; """ memset_test = """ char c[128] = "test"; c[0] = '6'; // avoid c being optimized out return c[1]; // avoid c being optimized out """ if conf.CheckRequirement('memcpy', memcpy_test): add_file('memcpy.c') if conf.CheckRequirement('memset', memset_test): add_file('memset.c') conf.Finish() # # Some platforms, like FreeBSD, require -pthread flag to be passed # instead of -lpthread. # conf = FlagsConfigure(makensis_env) conf.CheckLinkFlag('-pthread') conf.Finish() # # GCC doesn't define __BIG_ENDIAN__ or __LITTLE_ENDIAN__, so manually check # for the endianess and define __BIG_ENDIAN__ if needed. # def check_big_endian(ctx): ctx.Message('Checking for __BIG_ENDIAN__... ') test = """ int main() { #ifdef __BIG_ENDIAN__ // already defined, no need to define again return 0; #else int i = 1; char *c = (char *) &i; return c[0] != 1; #endif } """ result = not ctx.TryRun(test, '.c')[0] ctx.Result(result) return result conf = defenv.Configure(custom_tests = { 'CheckBigEndian' : check_big_endian }) if conf.CheckBigEndian(): makensis_env.Append(CPPDEFINES = ['__BIG_ENDIAN__']) test_env.Append(CPPDEFINES = ['__BIG_ENDIAN__']) conf.Finish() if makensis_env['PLATFORM'] == 'hpux': makensis_env.Append(CPPDEFINES = ['NSIS_HPUX_ALLOW_UNALIGNED_DATA_ACCESS']) makensis_conf = makensis_env.Configure() makensis_conf.CheckLib("unalign") makensis_conf.CheckLib("hppa") makensis_conf.Finish() ### return Return('stub_env makensis_env plugin_env util_env cp_util_env test_env')