
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@7189 212acab6-be3b-0410-9dea-997c60f758d6
373 lines
11 KiB
Text
373 lines
11 KiB
Text
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 <vector>
|
|
|
|
int main() {
|
|
std::vector<int> 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
|
|
|
|
conf = FlagsConfigure(stub_env)
|
|
conf.CheckCompileFlag('-fno-tree-loop-distribute-patterns') # GCC 10: Don't generate msvcrt!memmove calls (bug #1248)
|
|
conf.Finish()
|
|
|
|
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')
|