print("Using GNU tools configuration") Import('defenv') ### imports Import('FlagsConfigure GetOptionOrEnv GetStdSysEnvVarList') ### HACKS! if GetOptionOrEnv('NSIS_SCONS_GNU_ENVPATHHACK'): import os defenv['ENV']['PATH'] = os.getenv('PATH') # Major hack! import_env = GetStdSysEnvVarList(path=True, temp=True) for var in import_env: if var in os.environ: defenv['ENV'][var] = os.environ.get(var, '') #print(defenv.Dump()) ### cross compiling def cross_env(env): if env['PLATFORM'] != 'win32': env.Tool('crossmingw', toolpath = [Dir('../Tools').rdir()]) ### flags def entry(x,u): if defenv['TARGET_ARCH'] == 'x86': if x == 'NSISWinMainNOCRT': x = '_' + x 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['SUBSYS_WIN'] = '-Wl,--subsystem,windows' defenv['MSVCRT_FLAG'] = '' defenv['STDCALL'] = '"__attribute__((__stdcall__))"' # Don't allow mingw to link with LIBGCC*.DLL and LIBSTDC++-*.DLL if defenv['PLATFORM'] == 'win32': defenv.Append(LINKFLAGS = ['-static-libgcc']) defenv.Append(LINKFLAGS = ['-static-libstdc++']) ### 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') ### unicode tdefenv = defenv.Clone() if tdefenv['UNICODE']: tdefenv.Append(CPPDEFINES = ['_UNICODE', 'UNICODE']) ### 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 = ['$MAP_FLAG']) # generate map file stub_uenv = stub_env.Clone() stub_uenv.Append(CPPDEFINES = ['_UNICODE', 'UNICODE']) ### makensis environment makensis_env = tdefenv.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 makensis_env['STDCALL'] = '' # avoid 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 plugin_env.Append(LINKFLAGS = ['-static-libstdc++']) # remove libstdc++*.dll dependency plugin_uenv = plugin_env.Clone() plugin_uenv.Append(CPPDEFINES = ['_UNICODE', 'UNICODE']) ### cross-platform util environment if defenv['PLATFORM'] == 'win32': cp_util_env = tdefenv.Clone() else: cp_util_env = defenv.Clone() cp_util_env.Append(CPPPATH = ['#$BUILD_CONFIG']) if cp_util_env['PLATFORM'] == 'win32': cp_util_env.Append(LINKFLAGS = ['$ALIGN_FLAG']) # 512 bytes align 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 = tdefenv.Clone() cross_env(util_env) util_env.Append(CPPPATH = ['#$BUILD_CONFIG']) if not defenv['DEBUG']: util_env.Append(CCFLAGS = ['-O2']) # optimize util_env.Append(CCFLAGS = ['-Wall']) # all warnings util_env.Append(CCFLAGS = ['-fno-strict-aliasing']) # not safe for strict aliasing 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['STDCALL'] = '' # avoid warnings 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. # petype = 'pei-i386' if defenv['TARGET_ARCH'] == 'amd64': petype = 'pei-x86-64' stub_env.Append(LINKFLAGS = ['-B', petype]) # --oformat petype also works in GCC 4.5.2 stub_uenv.Append(LINKFLAGS = ['-B', petype]) stub_env.Append(LINKFLAGS = ['-T', File('linker_script').rfile()]) stub_uenv.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) add_file_to_emitter(stub_uenv, 'PROGEMITTER', file) add_file_to_emitter(plugin_uenv, '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() ### print version info stub_env.Execute('$CC --version') makensis_env.Execute('$CXX --version') ### return Return('stub_env makensis_env plugin_env util_env cp_util_env test_env stub_uenv plugin_uenv')