################################################# -*- python -*-
#
#  SConstruct makefile for Second Life viewer and servers.
#
#  To build everything:
#
#    scons ARCH=all BTARGET=all DISTCC=yes
#
# To build a standalone viewer, you'll need the following packages
# installed, with headers.  We pick up the correct flags to use for
# these libraries using the "pkg-config" command.
#
#    cairo glib-2.0 atk gmobile-2.0 gdk-2.0 gdk-pixbuf-2.0 pango pangoft2 pangox pangoxft gtk+-2.0 sdl vorbis vorbisenc vorbisfile
#
# Then build as follows:
#
#    scons BTARGET=client STANDALONE=yes MOZLIB=no ELFIO=no DISTCC=no
#
#  For help on options:
#
#    scons -h
#
#  Originally written by Tom Yedwab, 6/2006.
#
#################################################


import glob
import os
import random
import re
import sys

platform = sys.platform
if platform == 'linux2':
    platform = 'linux'

######################
# GET VERSION        #
######################

def get_version(type):
    file = open('llcommon/llversion%s.h' % type,"r")
    file_str = file.read()
    file.close()

    m = re.search('const S32 LL_VERSION_MAJOR = (\d+);', file_str)
    VER_MAJOR = m.group(1)
    m = re.search('const S32 LL_VERSION_MINOR = (\d+);', file_str)
    VER_MINOR = m.group(1)
    m = re.search('const S32 LL_VERSION_PATCH = (\d+);', file_str)
    VER_PATCH = m.group(1)
    m = re.search('const S32 LL_VERSION_BUILD = (\d+);', file_str)
    VER_BUILD = m.group(1)
    version = "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s" % locals()

    return version

version_viewer = get_version('viewer')
version_server = get_version('server')


###############
# SYSTEM INFO #
###############

# Debian Sarge has a broken glibc that leads to build failures on
# *non*-Sarge systems (because of prebuilt static libraries built on
# Sarge).

try:
    debian_sarge = open('/etc/debian_version').read().strip() == '3.1'
except:
    debian_sarge = False

#########################
# COMMAND LINE OPTIONS  #
#########################

opts = Options()
opts.AddOptions(
    EnumOption('BUILD', 'Set build type', 'releasefordownload',
        allowed_values=('debug', 'release', 'releasenoopt', 'releasefordownload')),
    EnumOption('ARCH', 'Set architecture', 'i686',
        allowed_values=('i686', 'powerpc', 'x86_64')),
    EnumOption('BTARGET', 'Set build target', 'server',
        allowed_values=('client', 'server', 'all')),
    BoolOption('DISTCC', 'Enabled distcc', True),
    BoolOption('MOZLIB', 'Enabled llmozlib/mozilla support', True),
    BoolOption('FMOD', 'Enabled FMOD audio support', True),
    BoolOption('GSTREAMER', 'Enabled GStreamer support', True),
    BoolOption('COLORGCC', 'Enabled colorgcc', True),
    EnumOption('GRID', 'Client package\'s default grid', 'default',
        allowed_values=('default', 'aditi', 'agni', 'dmz', 'durga', 'ganga', 'shakti', 'siva', 'soma', 'uma', 'vaak')),
    EnumOption('CHANNEL', 'Client package\'s default channel', 'Release',
        allowed_values=('Release', 'Release Candidate', 'WindLight')),
    BoolOption('ELFIO', 'Enabled enhanced backtraces with libELFIO symbol extraction support', True),
    BoolOption('STANDALONE', 'Build using system packages (implies OPENSOURCE)', False),
    BoolOption('OPENSOURCE', 'Build using only non-proprietary dependencies', True) # OPENSOURCE: do not edit this line
)
optenv = Environment(options = opts)
Help(opts.GenerateHelpText(optenv))

build_param = optenv['BUILD']
arch = optenv['ARCH']
target_param = optenv['BTARGET']
enable_distcc = optenv['DISTCC']
enable_mozlib = optenv['MOZLIB']
enable_gstreamer = optenv['GSTREAMER']
enable_colorgcc = optenv['COLORGCC']
grid = optenv['GRID']
channel = optenv['CHANNEL']
standalone = optenv['STANDALONE']
opensource = standalone or optenv['OPENSOURCE']
enable_fmod = not opensource and optenv['FMOD']
elfio = optenv['ELFIO']

targets = [ target_param ]

if target_param == 'all':
    targets = [ 'client', 'server' ]

# Set this to False if you don't want your source files copied into
# the object directory in /tmp.
duplicate = True

if standalone and platform != 'linux':
    print >> sys.stderr, 'Warning: standalone builds have only been tested on Linux'

standalone_pkgs = [
    'atk',
    'cairo',
    'freetype2',
    'gdk-2.0',
    'gdk-pixbuf-2.0',
    'glib-2.0',
    'gmodule-2.0',
    'gtk+-2.0',
    'libpng',
    'pango',
    'pangoft2',
    'pangox',
    'pangoxft',
    'sdl',
    'vorbis',
    'vorbisenc',
    'vorbisfile',
    ]

standalone_net_pkgs = [
    'apr-1',
    'apr-util-1',
    'libcrypto',
    'libcurl',
    'libssl',
    ]

def pkgconfig(opt, pkgs=None):
    if pkgs is None:
        pkgs = standalone_pkgs + standalone_net_pkgs
    return os.popen('pkg-config %s %s' %
                    (opt, ' '.join(pkgs))).read().strip()

if standalone:
    missing = [pkg for pkg in standalone_pkgs + standalone_net_pkgs
               if os.system('pkg-config --exists ' + pkg)]
    if missing:
        print >> sys.stderr, ('Error: pkg-config cannot find these '
                              'packages: %s' % ' '.join(missing))
        sys.exit(2)

#####################
# ITERATE TARGETS   #
#####################

for build_target in targets:
    buildtype = build_param
    if build_target == 'server' and buildtype == 'releasefordownload':
        buildtype = 'release'

    system_str = arch + '-' + platform

    print 'Building ' + build_target + ' ' + version_server + ' on ' + system_str + ' (' + buildtype + ')'

    system_lib_dir = '../libraries/' + system_str 

    if build_target == 'client':
        system_lib_dir += '/lib_release_client'
    elif buildtype == 'debug':
        system_lib_dir += '/lib_debug'
    else:
        system_lib_dir += '/lib_release'

    lib_dir = './lib_' + buildtype + '_' + build_target + '/' + system_str

    try:
        build_dir_prefix = os.environ['TEMP_BUILD_DIR']
    except:
        build_dir_prefix = '/tmp/' + os.environ['USER']
        
    build_dir = build_dir_prefix + os.getcwd() + '/' + system_str + '-' + build_target + '-' + buildtype

    ### Base include directories ###

    include_dirs = Split("""
        ./llcommon ./llmath ./llwindow ./llaudio ./llcharacter
        ./lldatabase ./llhavok ./llimage ./llinventory ./llmedia ./llmessage
        ./llprimitive ./llrender ./llscene ./llui ./llvfs ./llwindow
        ./llxml ./lscript ./lscript/lscript_compile
        ../libraries/include
        ../libraries/include/havok
        """ +
        '../libraries/' + system_str + '/include' )

    client_external_libs = []
    system_link_flags = ''

    if platform != 'linux' and build_target == 'client' and enable_mozlib:

        ### Mozilla include directories ###

        mozilla_dir = '../libraries/' + system_str + '/include/mozilla'
        include_dirs += Split(
            mozilla_dir + '/include/webbrwsr ' +
            mozilla_dir + '/include/docshell ' +
            mozilla_dir + '/include/dom ' +
            mozilla_dir + '/include/xpcom ' +
            mozilla_dir + '/include/widget ' +
            mozilla_dir + '/include/gfx ' +
            mozilla_dir + '/include/string ' +
            mozilla_dir + '/include/uriloader ' +
            mozilla_dir + '/include/view ' +
            mozilla_dir + '/include/layout ' +
            mozilla_dir + '/include/content ' +
            mozilla_dir + '/include/locale ' +
            mozilla_dir + '/include/profdirserviceprovider ' +
            mozilla_dir + '/include/xulapp ' +
            mozilla_dir + '/include/pref ' +
            mozilla_dir + '/sdk/include')

    ##############
    # CPP Flags  #
    ##############

    # Generic GCC flags
    cflags = '-g -pipe -Wall -Wno-reorder -Wno-trigraphs -Wno-sign-compare -Werror -fexceptions '
    cxxflags = ''
    cppflags = '-D_FORTIFY_SOURCE=2 '
    if standalone:
        cppflags += '-DLL_STANDALONE '

    if build_target == 'server':
        # Server flags
        cppflags += '-D_GNU_SOURCE -DLL_MESA_HEADLESS=1 -DLL_MESA=1 '
        cxxflags += '-ftemplate-depth-60 '
        if arch == 'i686':
            cflags += '-march=pentiumpro '
        if debian_sarge:
            def_server_cppflags = ''
        else:
            def_server_cppflags = '-DCTYPE_WORKAROUND'
        server_cppflags = os.environ.get('SERVER_CPPFLAGS',
                                         def_server_cppflags)
        cppflags += server_cppflags + ' '
    else:
        # Viewer flags
        cflags += '-pthread -D_REENTRANT -fno-math-errno -fsigned-char -fno-strict-aliasing '
        cppflags += '-DLL_MESA_HEADLESS=0 -DLL_MESA=0 '
        try:
            client_cppflags = os.environ['CLIENT_CPPFLAGS']
        except:
            client_cppflags = ''
        cppflags += client_cppflags + ' '


    if platform == 'linux':
        # Linux-only flags
        cppflags += '-DLL_LINUX=1 '
        if build_target == 'client':
            cppflags += '-DAPPID=secondlife -DLL_SDL=1 '
            if arch == 'x86_64' or arch == 'x86_64cross' or not enable_fmod:
                cppflags += '-DLL_FMOD=0 '
            cppflags += '-DLL_X11=1 -DLL_GTK=1 '
            if standalone:
                include_dirs += [d[2:] for d in
                                 pkgconfig('--cflags-only-I').split()]
            else:
                client_external_libs += [ 'gtk-x11-2.0', 'atk-1.0', 'gmodule-2.0', 'gdk-x11-2.0', 'gdk_pixbuf-2.0', 'pango-1.0', 'pangoft2-1.0', 'pangox-1.0', 'pangoxft-1.0', 'Xinerama' ]
                incdirs = [ 'ELFIO', 'atk-1.0', 'glib-2.0', 'gtk-2.0',
                            'llfreetype2', 'pango-1.0' ]
                include_dirs += ['../libraries/' + system_str + '/include/' + d
                                 for d in incdirs]

            if elfio:
                client_external_libs += [ 'ELFIO' ]
            else:
                cppflags += '-DLL_ELFBIN=0 '

            # llmozlib stuff
            if enable_mozlib:
                cppflags += '-DLL_LIBXUL_ENABLED=1 '
                client_external_libs += [ 'llmozlib' ]
                client_external_libs += [ 'mozjs', 'nspr4', 'plc4', 'plds4', 'profdirserviceprovider_s', 'xpcom', 'xul' ]
            else:
                cppflags += '-DLL_LIBXUL_ENABLED=0 '

            # GStreamer stuff
            if enable_gstreamer:
                cppflags += '-DLL_GSTREAMER_ENABLED=1 '
                client_external_libs += [ 'glib-2.0', 'gobject-2.0', 'gthread-2.0' ]
                include_dirs += [ '../libraries/' + system_str + '/include/gstreamer-0.10' ]
                include_dirs += [ '../libraries/' + system_str + '/include/glib-2.0', '../libraries/' + system_str + '/include/glib-2.0/include' ]
                include_dirs += [ '../libraries/' + system_str + '/include/libxml2']
            else:
                cppflags += '-DLL_GSTREAMER_ENABLED=0 '
    else:
        # Mac-only flags
        cflags += '-x c++ -arch ppc -pipe -Wno-trigraphs -fpascal-strings -faltivec -fasm-blocks -g -fmessage-length=0 -mtune=G4 -Wno-deprecated-declarations -Wno-invalid-offsetof -mmacosx-version-min=10.3 -Wmost -Wno-sign-compare -Wno-switch -fconstant-cfstrings -ffor-scope -Wno-reorder -fexceptions '
        cppflags += '-x c++ -DLL_DARWIN=1 -fpch-preprocess -F./newview/build/Deployment -fconstant-cfstrings -isysroot /Developer/SDKs/MacOSX10.3.9.sdk '

    if standalone:
        gcc_bin = 'g++'
    elif build_target != 'client':
        gcc_bin = 'g++-3.3'
    elif arch == 'x86_64cross':
        gcc_bin = '/opt/crosstool/gcc-4.0.2-glibc-2.3.6/x86_64-unknown-linux-gnu/bin/x86_64-unknown-linux-gnu-gcc'
        strip_cmd = '/opt/crosstool/gcc-4.0.2-glibc-2.3.6/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/bin/strip -S -o $TARGET $SOURCE'

    else:
        gcc_bin = 'g++-3.4'

    # Are we using the Intel compiler?
    if gcc_bin.find('icpc') >= 0:
        cflags += '-wr193,654,981,1125 -w1 '
    elif build_target == 'client':
        cflags += '-falign-loops=16 -ffast-math '

    cxxflags += cflags

    ### Build type-specific flags ###

    debug_cflags = cflags + '-fno-inline -O0 '
    debug_cxxflags = cxxflags + '-fno-inline -O0 '
    debug_cppflags = cppflags + '-D_DEBUG -DLL_DEBUG=1 '
    release_cflags = cflags + '-O2 '
    release_cxxflags = cxxflags + '-O2 '
    release_cppflags = cppflags + '-DNDEBUG -DLL_RELEASE=1 '
    releasenoopt_cflags = cflags + '-O0 '
    releasenoopt_cxxflags = cxxflags + '-O0 '
    releasenoopt_cppflags = cppflags + '-DNDEBUG -DLL_RELEASE=1 '
    releasefordownload_cflags = cflags + '-O2 '
    releasefordownload_cxxflags = cxxflags + '-O2 '
    releasefordownload_cppflags = cppflags + '-DNDEBUG -DLL_RELEASE=1 -DLL_RELEASE_FOR_DOWNLOAD=1 '

    ################
    # ENVIRONMENT  #
    ################

    # If you strip more aggressively than -S then the quality of crash-
    # logger backtraces deteriorates.
    strip_cmd = 'strip -S -o $TARGET $SOURCE'

    # hidesyms_cmd is something which copies an executable while 'hiding'
    # all of its exposed symbols except a very few desired ones.  This is
    # used mainly to hide the symbols of the many common libraries we
    # static-link, which otherwise cause hard-to-trace fatal crashes due
    # to clashes in the run-time symbol namespace.
    if platform == 'linux':
        exposed_symbols_file = 'newview/linux_tools/exposed-symbols.txt'
        hidesyms_cmd = 'objcopy --keep-global-symbols ' + exposed_symbols_file + ' $SOURCE $TARGET'
    else:
        hidesyms_cmd = 'cp -f $SOURCE $TARGET'

    compiler = gcc_bin 
    compiler_no_distcc = compiler
    if enable_distcc:
        compiler = 'distcc ' + gcc_bin

    lib_path = [lib_dir] + [system_lib_dir]

    mysql_lib_dir = '/usr/lib/mysql4/mysql'
    if os.path.isdir(mysql_lib_dir):
        lib_path.append(mysql_lib_dir)

    if standalone:
        system_link_flags += pkgconfig('--libs-only-L') + ' '
        system_link_flags += pkgconfig('--libs-only-other') + ' '

    base_env = Environment(CXX = compiler,
            CPPPATH = include_dirs,
            LIBPATH = lib_path,
            LINKFLAGS = system_link_flags + '--no-keep-memory --reduce-memory-overheads ' )

    ### Environments for various build types ###

    env = base_env.Copy(CFLAGS=releasefordownload_cflags,
                        CPPFLAGS=releasefordownload_cppflags,
                        CXXFLAGS=releasefordownload_cxxflags)

    if buildtype == 'debug':
        env = base_env.Copy(CFLAGS=debug_cflags,
                            CPPFLAGS=debug_cppflags,
                            CXXFLAGS=debug_cxxflags)

    if buildtype == 'release':
        env = base_env.Copy(CFLAGS=release_cflags,
                            CPPFLAGS=release_cppflags,
                            CXXFLAGS=release_cxxflags)

    if buildtype == 'releasenoopt':
        env = base_env.Copy(CFLAGS=releasenoopt_cflags,
                            CPPFLAGS=releasenoopt_cppflags,
                            CXXFLAGS=releasenoopt_cxxflags)

    # ccache needs this to be set
    try:
        env['ENV']['CCACHE_DIR'] = os.environ['CCACHE_DIR']
    except:
        print "No CCACHE_DIR set."

    env_no_distcc = env.Copy(CXX = compiler_no_distcc)

    vec_match	= re.compile("_vec\.")
    env_vec = env.Copy()	# _vec is for default vector optimizations or none

    sse_match	= re.compile("_sse\.")
    env_sse = env.Copy()
    env_sse.Append(CPPFLAGS = ' -msse -mfpmath=sse')

    sse2_match	= re.compile("_sse2\.") 
    env_sse2 = env.Copy()
    env_sse2.Append(CPPFLAGS = ' -msse2 -mfpmath=sse')


    ### Distributed build hosts ###

    if enable_distcc:
        hosts = [ 'localhost/2', ]
        if arch == 'i686':
            dead = []
            stations = [s for s in xrange(36) if s not in dead]
            random.shuffle(stations)
            hosts += ['station%d.lindenlab.com/2,lzo' % s for s in stations]
        hosts = ' '.join(hosts)
        print "Distributing to hosts: " + hosts
        env['ENV']['DISTCC_HOSTS'] = hosts
        env['ENV']['USER'] = os.environ['USER']
        env['ENV']['HOME'] = os.environ['HOME']

    if enable_colorgcc:
        env['ENV']['PATH'] = os.environ['PATH']
        env['ENV']['TERM'] = os.environ['TERM']
        env['ENV']['HOME'] = os.environ['HOME']

    ### Configure lex and yacc ###
    env.Append(YACCFLAGS = ["-v", "-d"])
    env.CFile(target=build_dir+'/lscript/lscript_compile/indra.l.cpp', source='lscript/lscript_compile/indra.l')
    env.CFile(target=build_dir+'/lscript/lscript_compile/indra.y.c', source='lscript/lscript_compile/indra.y')
    env.Command(build_dir+'/lscript/lscript_compile/indra.y.cpp',build_dir+'/lscript/lscript_compile/indra.y.c', 
                        [Move('$TARGET','$SOURCE'),Delete(build_dir+'/lscript/lscript_compile/indra.y.output')])

    #####################
    # HELPER FUNCTIONS  #
    #####################

    ## handle special compiler modes

    def file_obj(file):
        if file == 'newsim/lltask.cpp':
            print 'Found lltask!'
            return env_no_distcc.Object(file)
        elif vec_match.search(file) != None:
            return env_vec.Object(file)
        elif sse_match.search(file) != None:
            return env_sse.Object(file)
        elif sse2_match.search(file) != None:
            return env_sse2.Object(file)
        else:
            return file

    ### Load a files.lst and files.PLATFORM.lst for each module ###

    def load_files(module, source_fname):
        new_list = []
        try:
            list_file = open('./' + module + '/' + source_fname, 'r')
            list = Split(list_file.read())
            for x in list:
                if not x.startswith('#'):
                    file = os.path.join(build_dir, x)
                    new_list.append(file_obj(file))
            list_file.close()
        except IOError, val:
            print 'Error: unable to open file list',source_fname,
            print 'for module', module + ":", val
            return []

        try:
            platform_list_file = open('./' + module + '/files.' + platform + '.lst', 'r')
            list = Split(platform_list_file.read())
            for x in list:
                file = os.path.join(build_dir, x)
                new_list.append(file_obj(file))
            platform_list_file.close()
        except IOError:
            return new_list

        return new_list

    ### Create a static library from the module ###

    def create_static_module_from_dir(
        input_dir,
        mod_name,
        local_flags="",
        source_files = 'files.lst',
        extra_depends=None,
        source_env=env):
        files_list = load_files(input_dir, source_files)
        BuildDir(build_dir + '/' + input_dir, input_dir, duplicate=duplicate)
        local_env = source_env.Copy(CPPFLAGS=env['CPPFLAGS'] + ' ' + local_flags)
        if extra_depends:
            for x in files_list:
                Depends(local_env.Object(x), extra_depends)
        tgt = local_env.StaticLibrary(lib_dir + '/' + mod_name, files_list)
        Default(tgt)

    def create_static_module(module, local_flags="", source_env=env,
                             source_files='files.lst', extra_depends=None):
        create_static_module_from_dir(module, module, local_flags,
                                      source_files, extra_depends,
                                      source_env=source_env)

    def create_dynamic_module(
        module,
        local_flags="",
        module_libs = [],
        source_files = 'files.lst'):
	# -Bsymbolic avoids having the lib pull symbols from the app's
	# namespace instead of its own by default.  This avoids some
	# rediculous problems with multiple destruction of the wrong
	# objects, though has some gotchas of its own.
	dyn_link_flags = '-Wl,-Bsymbolic'
        files_list = load_files(module, source_files)
        BuildDir(build_dir + '/' + module, module, duplicate=duplicate)
        local_env = env.Copy(CPPFLAGS = env['CPPFLAGS'] + ' ' + local_flags,
			LINKFLAGS = env['LINKFLAGS'] + ' ' + dyn_link_flags)
        tgt = local_env.SharedLibrary(lib_dir + '/' + module, files_list, LIBS = module_libs)
        Default(tgt)

    # Some libraries need to be built using PIC so that they can be
    # linked into libllkdu.so.  If we're not building libllkdu.so, we
    # don't need to add the PIC flag.
    def create_cond_module(module, module_libs=[]):
        if build_target == 'client' and not opensource:
            shared_env = env.Copy(CFLAGS=env['CFLAGS'] + '-fpic ',
                                  CXXFLAGS=env['CXXFLAGS'] + '-fpic ')
            create_static_module(module=module, source_env=shared_env)
        else:
            create_static_module(module=module, source_env=env)

    ### Create an executable from the module ###

    def create_executable(
        exec_file, module, module_libs, source_files = 'files.lst'):
        files_list = load_files(module, source_files)
        BuildDir(build_dir + '/' + module, module, duplicate=duplicate)
        tgt = env.Program(exec_file, files_list, LIBS = module_libs)
        Default(tgt)


    ### Check the message template for compatibility with the base ###
    tgt = env.Command("template_verifier_output",
                      '../scripts/template_verifier.py',
                      'python $SOURCE  --mode="development" --cache_master 2>&1')
    Default(tgt)
    AlwaysBuild(tgt)

    ####################
    # BUILD LIBRARIES  #
    ####################

    create_cond_module('llcommon')
    create_cond_module('llmath')
    create_cond_module('llvfs')
    create_cond_module('llimagej2coj', module_libs=['openjpeg'])
    create_cond_module('llimage', module_libs=['llimagej2coj', 'jpeg', 'png12'])
    create_static_module('llmessage')
    create_static_module('llinventory')
    create_static_module('llcharacter')
    create_static_module('llprimitive')
    create_static_module('llrender')
    create_static_module('llwindow')
    create_static_module('llxml')
    create_static_module('lscript', extra_depends=build_dir + '/lscript/lscript_compile/indra.y.h')

    if standalone:
        net_external_libs = [d[2:] for d in
                             pkgconfig('--libs-only-l',
                                       standalone_net_pkgs).split()]
    else:
        net_external_libs = [ 'curl', 'ssl', 'crypto', 'aprutil-1', 'apr-1' ]
    net_external_libs += [ 'cares', 'expat' ]

    common_external_libs = net_external_libs + [ 'xmlrpc-epi', 'z' ]

    if build_target == 'client':
        if platform == 'linux':
            #############################
            # BUILD LINUX_CRASH_LOGGER  #
            #############################
            output_crashlogger_bin = 'linux_crash_logger/linux-crash-logger-' + arch + '-bin'
            if standalone:
                external_libs = net_external_libs
                external_libs += [d[2:] for d in
                                  pkgconfig('--libs-only-l', ['gtk+-2.0']).split()]
            else:
                external_libs = net_external_libs + [ 'db-4.2', 'gtk-x11-2.0' ]
            internal_libs = [ 'llvfs', 'llmath', 'llcommon' ]
            create_executable(output_crashlogger_bin + '-globalsyms',
                              'linux_crash_logger',
                              internal_libs + external_libs)
            env.Command(output_crashlogger_bin, output_crashlogger_bin + '-globalsyms', hidesyms_cmd)

        create_static_module('llaudio')
        create_static_module('llmedia')
        create_static_module('llui')

        if not opensource:
            create_dynamic_module('llkdu', '', ['llimage', 'llvfs', 'llmath', 'llcommon', 'apr-1', 'kdu_v42R'])

        ##################
        # BUILD NEWVIEW  #
        ##################
        output_bin = 'newview/secondlife-' + arch + '-bin'

        external_libs = client_external_libs + common_external_libs

        if standalone:
            external_libs += [ d[2:] for d in
                              pkgconfig('--libs-only-l').split() ]
        else:
            external_libs += [ 'freetype', 'SDL', 'vorbisenc',
                               'vorbisfile', 'vorbis', 'ogg', 'db-4.2' ]

        external_libs += [ 'jpeg', 'openjpeg', 'png12', 'GL', 'GLU' ]

        if arch != 'x86_64' and arch != 'x86_64cross':
            if enable_fmod:
                external_libs += [ 'fmod-3.75' ]
            if buildtype == 'debug':
                external_libs += ['tcmalloc', 'stacktrace']

        internal_libs = [ 'lscript', 'llwindow', 'llrender', 'llprimitive',
                 'llmedia', 'llinventory', 
                 'llimage',  'llimagej2coj', 
                 'llcharacter', 'llaudio', 'llui', 'llxml',
                 'llmessage', 'llvfs', 'llmath', 'llcommon' ]

        create_executable(output_bin + '-globalsyms', 'newview', internal_libs + external_libs)
        env.Command(output_bin, output_bin + '-globalsyms', hidesyms_cmd)
        Default(output_bin)

        if buildtype == 'releasefordownload':

            #######################
            # PACKAGE THE CLIENT  #
            #######################

            if platform == 'linux':
                env.Command(output_bin + '-stripped', output_bin, strip_cmd)
                env.Command(output_crashlogger_bin + '-stripped', output_crashlogger_bin, strip_cmd)
                product_name = 'SecondLife_' + arch + '_' + "_".join(version_viewer.split("."))
                if grid not in ['default', 'agni']:
                    product_name += "_" + grid.upper()
                if channel not in ['Release']:
                    product_name += "_" + "".join((channel.upper()).split())
                package_name = product_name + '.tar.bz2'
                complete_channel = 'Second Life ' + channel
                cmd = 'rm -rf newview/%(pn)s* && newview/viewer_manifest.py --grid=%(grid)s --channel=\'%(ch)s\' --installer_name=%(pn)s --arch=%(arch)s' % {
                    'pn': product_name,
                    'grid':grid,
					'ch':complete_channel,
                    'arch':arch}
                env.Command('newview/' + package_name, 'newview/viewer_manifest.py', cmd)
                Depends('newview/' + package_name, output_bin + '-stripped')
                Depends('newview/' + package_name, output_crashlogger_bin + '-stripped')
                Default('newview/' + package_name)

    elif build_target == 'server':
        create_static_module('lldatabase')
        create_static_module('llscene')
        create_static_module('llhavok', '-fno-rtti')
        create_static_module_from_dir('llkdu', 'llkdustatic')


        ##################
        # BUILD SERVERS  #
        ##################
        file_suffix = ''
        if buildtype == 'debug':
            file_suffix = '_debug'

        common_external_libs += [ 'pthread' ]

        # Chatter test application
        external_libs = common_external_libs
        internal_libs = [ 'llmessage', 'llvfs', 'llmath', 'llcommon' ]
        create_executable('test_apps/chatter/chatter', 'test_apps/chatter', 
                            internal_libs + external_libs)

        # Tool to buffer all of standard input to memory.
        create_executable('tools/simbin2xml/buffer_file/buffer_file', 
                          'tools/simbin2xml/buffer_file', "")

        # Simstate binary to XML utility.
        external_libs = common_external_libs
        internal_libs = [ 'llxml', 'llcommon', 'llmath' ]
        create_executable('tools/simbin2xml/simbin2xml', 'tools/simbin2xml', 
                            internal_libs + external_libs)

        # Launcher
        external_libs = common_external_libs
        internal_libs = [ 'llmessage', 'llvfs', 'llmath', 'llcommon' ]
        create_executable('launcher/launcher' + file_suffix, 'launcher', 
                            internal_libs + external_libs)

        # Dataserver
        external_libs = common_external_libs + [
            'boost_regex-gcc-mt', 'mysqlclient', 'tcmalloc', 'stacktrace',
            ]
        internal_libs = [ 'llcharacter', 'lldatabase', 'llimage', 'llimagej2coj', 'llinventory',
                'llscene', 'llmessage', 'llvfs', 'llxml', 'llcommon', 'llmath' ]
        create_executable('dataserver/dataserver' + file_suffix, 'dataserver', 
                            internal_libs + external_libs)

        # Spaceserver
        external_libs = common_external_libs + ['mysqlclient']
        internal_libs = ['llscene', 'lldatabase', 'llmessage', 'llvfs', 
                'llmath', 'llcommon']
        create_executable('newspace/spaceserver' + file_suffix, 'newspace',
                            internal_libs + external_libs)

        # Rpcserver
        external_libs = common_external_libs + ['xmlrpc-epi', 'mysqlclient']
        internal_libs = ['llscene', 'llmessage', 'lldatabase', 'llvfs', 
                'llmath', 'llcommon']
        create_executable('rpcserver/rpcserver' + file_suffix, 'rpcserver',
                            internal_libs + external_libs)

        # Mapserver
        external_libs = common_external_libs + ['OSMesa16', 'kdu', 
                'boost_regex-gcc-mt', 'iconv', 'jpeg', 'openjpeg', 'GL',
                'mysqlclient', 'pthread', 'dl']
        internal_libs = ['llrender', 'llwindow', 'llimage', 'llimagej2coj', 'lldatabase', 'llprimitive', 'llmessage', 'llkdustatic',
                'llxml', 'llvfs', 'llmath', 'llcommon']
        create_executable('mapserver/mapserver' + file_suffix, 'mapserver',
                            internal_libs + external_libs)
        
        # Simulator
        external_libs = common_external_libs + [
            'hkdynamics', 'hkgeometry', 'hkmath', 'hkbase', 'hkcollide',
            'hkactions', 'boost_regex-gcc-mt', 'openjpeg', 'dl', 'kdu',
            'mysqlclient', 'iconv', 'tcmalloc', 'stacktrace',
            ]
        internal_libs = [ 'lscript', 'llprimitive',
                 'llscene', 'llhavok', 'llinventory', 'llimage', 'llimagej2coj',
                 'llcharacter', 'llxml', 'lldatabase', 'llkdustatic',
                 'llmessage', 'llvfs', 'llmath', 'llcommon' ]
        create_executable('newsim/simulator' + file_suffix, 'newsim', 
                            internal_libs + external_libs)

        # texture upload verifier
        external_libs = common_external_libs + [ 'kdu', 'openjpeg', 'dl' ]
        internal_libs = [
            'llimage',
            'llimagej2coj',
            'llkdustatic',
            'llinventory',
            'llmessage',
            'llvfs',
            'llxml',
            'llcommon',
            'llmath' ]
        create_executable(
            'web/doc/asset-upload/plugins/verify-texture',
            'web/doc/asset-upload/plugins',
            internal_libs + external_libs,
            'verify-texture.lst')

        # notecard upload verifier
        create_executable(
            'web/doc/asset-upload/plugins/verify-notecard',
            'web/doc/asset-upload/plugins',
            internal_libs + external_libs,
            'verify-notecard.lst')

        # LSL compiler plugin for asset upload CGI.
        external_libs = common_external_libs
        internal_libs = ['lscript', 'llmath', 'llcommon']
        create_executable('web/doc/asset-upload/plugins/lsl_compiler/lslc' + file_suffix, 'web/doc/asset-upload/plugins/lsl_compiler/', internal_libs + external_libs);

        # Test
        Depends('test/test', 'newsim/simulator' + file_suffix)
        external_libs = common_external_libs + ['mysqlclient']
        internal_libs = [ 'lldatabase', 'llinventory', 'llmessage', 'llxml',
                'llvfs', 'llcharacter', 'llmath', 'llcommon' ]
        test_executable = 'test/test' + file_suffix
        create_executable(test_executable, 'test', 
                            internal_libs + external_libs)

        # Run tests
        test_results_file = 'test/test_results' + file_suffix + '.txt'
        env.Command(test_results_file,
                    test_executable,
                    "$SOURCE 2>&1")  # tee masks segfaults
        Depends(test_results_file, test_executable)
        Default(test_results_file)

        test_script = 'test/test.py'
        script_test_results = 'test/script_test_result' + file_suffix + '.txt'
        env.Command(script_test_results,
                    test_script,
                    "$SOURCE 2>&1")  # tee masks segfaults

        Depends(script_test_results, test_results_file)
        Default(script_test_results)

#########
# DONE  #
#########