diff --git a/SCons/Config/gnu b/SCons/Config/gnu index dcb8b42e..7bbe0298 100644 --- a/SCons/Config/gnu +++ b/SCons/Config/gnu @@ -94,6 +94,116 @@ util_env.Append(LINKFLAGS = '-s') # strip util_env.Append(LINKFLAGS = '-mwindows') # build windows executables util_env.Append(LINKFLAGS = '$ALIGN_FLAG') # 512 bytes align -# return + +### weird GCC requirements + +# +# 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. +# + +funcs_file = None +funcs_obj = None + +def check_requirement(ctx, func, trigger): + ctx.Message('Checking for %s requirement... ' % func) + + ctx.env.Append(LINKFLAGS = '$NODEFLIBS_FLAG') + ctx.env.Append(LINKFLAGS = '-Wl,-e,___main') + + test = """ + int __main() { + %s + return 0; + } + """ % trigger + + ret = not ctx.TryLink(test, '.c') + ctx.Result(ret) + + return ret + +def replace_emitter(env, builder_name): + builder = env['BUILDERS'][builder_name] + + def new_emitter(target, source, env): + global funcs_file, funcs_obj + res = builder.emitter(target, source, env) + if not funcs_obj: + funcs_obj = env.SharedObject(funcs_file) + res[1].append(funcs_obj) + return res + + env['BUILDERS'][builder_name] = Builder( + action = builder.action, + prefix = builder.prefix, + suffix = builder.suffix, + src_suffix = builder.src_suffix, + target_scanner = builder.target_scanner, + source_scanner = builder.source_scanner, + target_factory = builder.target_factory, + source_factory = builder.source_factory, + emitter = new_emitter, # only thing being replaced + src_builder = builder.src_builder, + single_source = builder.single_source + ) + +def add_func(func): + global funcs_file + + if not funcs_file: + import os + funcs_file = File('#.sconf_temp/funcs.c') + try: + os.unlink(funcs_file.abspath) + except OSError: + pass + + f = file(funcs_file.abspath, 'a') + f.write(func) + f.write('\n') + f.close() + +conf = defenv.Configure(custom_tests = { 'CheckRequirement' : check_requirement }) + +if conf.CheckRequirement('memcpy', 'struct s { char c[128]; } t = { "test" };'): + add_func(""" + #include // for size_t + void *memcpy(void *out, const void *in, size_t len) + { + char *c_out=(char*)out; + char *c_in=(char *)in; + while (len-- > 0) + { + *c_out++=*c_in++; + } + return out; + } + """) + +if conf.CheckRequirement('memset', 'char c[128] = "test";'): + add_func(""" + #include // for size_t + void *memset(void *mem, int c, size_t len) + { + char *p=(char*)mem; + while (len-- > 0) + { + *p++=c; + } + return mem; + } + """) + +if funcs_file: + replace_emitter(stub_env, 'Program') + replace_emitter(plugin_env, 'SharedLibrary') + replace_emitter(util_env, 'Program') + +conf.Finish() + +### return Return('stub_env makensis_env plugin_env util_env')