# vi: syntax=python
Import('context')

import os, ConfigParser
import checks

SConscript("all.scons", exports = ["context"])

context.setLibraryDir("lib/unix")

def getOption(name, default):
    arg = ARGUMENTS.get(name,default)
    if arg == "yes" or arg == "1":
        return 1
    return 0

def OnX86():
    uname = os.uname()
    import re
    return re.match(r"i\d86", uname[4])

def EnableVBEAF():
    if OnX86() and getOption("vbeaf", "no"):
        return 1
    return 0

def EnableVGA():
    if OnX86() and getOption("vga", "no"):
        return 1
    return 0

def writeAutoHeader(filename, platform):
    def defined(name, use):
        if use:
            return "#define " + name + " " + str(use) + "\n"
        else:
            return "/* #undef " + name + " */\n"
    file = open(filename, "w")
    file.write("/* Generated by scons build system. Don't touch */\n")
    for name in platform.keys():
        use, description = platform[ name ]
        file.write("/* " + description + " */\n")
        file.write(defined(name, use))
        file.write("\n")
    file.close()

def readAutoHeader(filename, platform):
    for line in file(filename):
        if line.startswith("#define "):
            name, use = line.split(None, 2)[1:]
            platform[name] = [use,name]

# With the noconfig option, simply re-use the last config if one is available.
# Should this be default?
# 2/19/2006 - Only configure if config=1 is given or the .h/.cfg file is missing
noconfig = False
if not getOption("config",0):
    if os.path.exists("include/allegro/platform/alunixac.h") and \
        os.path.exists("build/settings.cfg"):
        print "Re-using old settings"
        noconfig = True

class SimpleHash:
    def __init__( self ):
        self.hash = dict()

    def __getitem__( self, key ):
        try:
            return self.hash[ key ]
        except KeyError:
            return [False]

    def __setitem__( self, key, value ):
        self.hash[ key ] = value

    def keys( self ):
        return self.hash.keys()

# the settings we cache in settings.cfg
config_settings = ["CCFLAGS", "CPPPATH", "CPPFLAGS", "LIBS", "LIBPATH", "LINKFLAGS"]
platform = SimpleHash()
settings = ConfigParser.ConfigParser()

## The platform variable will hold all configuration things we care about
## so that alunixac.h can be written
if noconfig:
    readAutoHeader("include/allegro/platform/alunixac.h", platform)
    settings.read("build/settings.cfg")
    env = context.getLibraryEnv()
    for setting in config_settings:
        eval("env.Append(%s = %s)" % (setting, settings.get("unix", setting)))
else:
    tests = {}
    tests["CheckAMD64"] = checks.CheckAMD64
    tests["CheckIntel"] = checks.CheckIntel
    tests["CheckSparc"] = checks.CheckSparc
    tests["CheckProcFS"] = checks.CheckProcFS
    tests["CheckProcFSArgCV"] = checks.CheckProcFSArgCV
    tests["CheckASMUnderscores"] = checks.CheckASMUnderscores
    tests["CheckMMX"] = checks.CheckMMX
    tests["CheckSSE"] = checks.CheckSSE
    tests["AlsaVersion"] = checks.AlsaVersion
    tests["CheckBigEndian"] = checks.CheckBigEndian
    tests["CheckLittleEndian"] = checks.CheckLittleEndian
    tests["CheckDarwin"] = checks.CheckDarwin
    tests["CheckLinux"] = checks.CheckLinux
    tests["CheckFBCon"] = checks.CheckFBCon
    tests["CheckSVGALibVersion"] = checks.CheckSVGALibVersion
    tests["CheckConstructor"] = checks.CheckConstructor
    tests["CheckALSADigi"] = checks.CheckALSADigi
    tests["CheckALSAMidi"] = checks.CheckALSAMidi
    tests["CheckARTSDigi"] = checks.CheckARTSDigi
    tests["CheckXCursor"] = checks.CheckXCursor
    tests["CheckMapFailed"] = checks.CheckMapFailed
    tests["CheckESDDigi"] = checks.CheckESDDigi
    tests["CheckJackDigi"] = checks.CheckJackDigi
    tests["CheckForX"] = checks.CheckForX
    tests["CheckOSSDigi"] = checks.CheckOSSDigi
    tests["CheckOSSMidi"] = checks.CheckOSSMidi
    tests["CheckMTune"] = checks.CheckMTune

    config = context.getLibraryEnv().Configure(custom_tests = tests)

    gccArchFlag = "-mcpu="
    machine = "i386"
    useArch = False
    if config.CheckIntel():
        machine = "pentium"
        useArch = True

    if config.CheckAMD64():
        machine = "k8"
        useArch = True

    if config.CheckMTune(machine):
        gccArchFlag = "-mtune=" + machine

    if useArch:
        config.env.Append( CCFLAGS = [gccArchFlag] )

    config.CheckLib("m", "sin")
    platform["ALLEGRO_ALSA_VERSION"] = [config.AlsaVersion(), "Define to the installed ALSA version"]
    platform["ALLEGRO_ASM_PREFIX"] = [config.CheckASMUnderscores(), "Define if compiler prepends underscore to symbols."]
    platform["ALLEGRO_BIG_ENDIAN"] = [config.CheckBigEndian(), "Define if target machine is big endian."]
    platform["ALLEGRO_COLOR16"] = [getOption("color16", "yes"), "Define if you want support for 16 bpp modes."]
    platform["ALLEGRO_COLOR24"] = [getOption("color24", "yes"), "Define if you want support for 24 bpp modes."]
    platform["ALLEGRO_COLOR32"] = [getOption("color32", "yes"), "Define if you want support for 32 bpp modes."]
    platform["ALLEGRO_COLOR8"] = [getOption("color8", "yes"), "Define if you want support for 8 bpp modes."]
    platform["ALLEGRO_DARWIN"] = [config.CheckDarwin(), "Define if target platform is Darwin."]
    platform["ALLEGRO_HAVE_GETEXECNAME"] = [config.CheckFunc("getexecname"), "Define to 1 if you have getexecname"]
    platform["ALLEGRO_HAVE_PROCFS_ARGCV"] = [config.CheckProcFSArgCV(), "Define to 1 if procfs reveals argc and argv"]
    platform["ALLEGRO_LINUX"] = [config.CheckLinux(), "Define if target platform is linux."]
    platform["ALLEGRO_LINUX_FBCON"] = [config.CheckFBCon(), "Define to enable Linux console fbcon driver."]
    platform["ALLEGRO_LINUX_SVGALIB"] = [config.CheckLib("vga", "vga_init"), "Define to enable Linux console SVGAlib driver."]
    platform["ALLEGRO_LINUX_SVGALIB_HAVE_VGA_VERSION"] = [config.CheckSVGALibVersion(), "Define if SVGAlib driver can check vga_version."]
    platform["ALLEGRO_LINUX_VBEAF"] = [EnableVBEAF(), "Define to enable Linux console VBE/AF driver."]
    platform["ALLEGRO_LINUX_VGA"] = [EnableVGA(), "Define to enable Linux console VGA driver."]
    platform["ALLEGRO_LITTLE_ENDIAN"] = [config.CheckLittleEndian(), "Define if target machine is little endian."]
    platform["ALLEGRO_MMX"] = [config.CheckMMX(), "Define if assembler supports MMX."]
    platform["ALLEGRO_NO_ASM"] = [getOption("no_asm", "yes"), "Define for Unix platforms, to use C convention for bank switching."]
    platform["ALLEGRO_SSE"] = [config.CheckSSE(), "Define if assembler supports SSE."]
    platform["ALLEGRO_USE_CONSTRUCTOR"] = [config.CheckConstructor(), "Define if constructor attribute is supported."]
    platform["ALLEGRO_USE_SCHED_YIELD"] = [config.CheckLib(["c", "posix4", "rt"], "sched_yield"), "Define if sched_yield is provided by some library."]
    platform["ALLEGRO_USE_XIM"] = [config.CheckLib("X11", "XOpenIM"), "Define if XIM extension is supported."]
    platform["ALLEGRO_WITH_ALSADIGI"] = [config.CheckALSADigi(), "Define if ALSA DIGI driver is supported."]
    platform["ALLEGRO_WITH_ALSAMIDI"] = [config.CheckALSAMidi(), "Define if ALSA MIDI driver is supported."]
    platform["ALLEGRO_WITH_ARTSDIGI"] = [config.CheckARTSDigi(), "Define if aRts DIGI driver is supported."]
    platform["ALLEGRO_WITH_ESDDIGI"] = [config.CheckESDDigi(), "Define if ESD DIGI driver is supported."]
    platform["ALLEGRO_WITH_JACKDIGI"] = [config.CheckJackDigi(), "Define if JACK DIGI driver is supported."]
    platform["ALLEGRO_WITH_MAGIC_MAIN"] = [getOption("magic_main", "no"), "Define if you need to use a magic main."]

    platform["ALLEGRO_WITH_XWINDOWS"] = [config.CheckForX(), "Define if you need support for X-Windows."]
    platform["ALLEGRO_XWINDOWS_WITH_SHM"] = [config.CheckLib("Xext", "XShmQueryExtension"), "Define if MIT-SHM extension is supported."]
    platform["ALLEGRO_XWINDOWS_WITH_XCURSOR"] = [config.CheckXCursor(), "Define if XCursor ARGB extension is available."]
    platform["ALLEGRO_XWINDOWS_WITH_XF86DGA2"] = [config.CheckLib("Xxf86dga", "XDGAQueryExtension"), "Define if DGA version 2.0 or newer is supported"]
    platform["ALLEGRO_XWINDOWS_WITH_XF86VIDMODE"] = [config.CheckLib("Xxf86vm", "XF86VidModeQueryExtension"), "Define if XF86VidMode extension is supported."]
    platform["ALLEGRO_XWINDOWS_WITH_XPM"] = [config.CheckLib("Xpm", "XpmCreatePixmapFromData"), "Define if xpm bitmap support is available."]
    platform["HAVE_DIRENT_H"] = [config.CheckCHeader("dirent.h"), "Define to 1 if you have the <dirent.h> header file, and it defines \"DIR\". "]
    platform["HAVE_DLFCN_H"] = [config.CheckCHeader("dlfcn.h"), "Define to 1 if you have the <dlfcn.h> header file."]
    platform["HAVE_FCNTL_H"] = [config.CheckCHeader("fcntl.h"), "Define to 1 if you have the <fcntl.h> header file."]
    platform["HAVE_INTTYPES_H"] = [config.CheckCHeader("inttypes.h"), "Define to 1 if you have the <inttypes.h> header file."]
    platform["HAVE_LIBOSSAUDIO"] = [config.CheckLib("ossaudio", "_oss_ioctl"), "Define to 1 if you have the \"ossaudio\" library (-lossaudio)."]
    platform["HAVE_LIBPTHREAD"] = [config.CheckLib("pthread", "pthread_create"), "Define if you have the pthread library."]
    platform["HAVE_LIMITS_H"] = [config.CheckCHeader("limits.h"), "Define to 1 if you have the <limits.h> header file."]
    platform["HAVE_LINUX_AWE_VOICE_H"] = [config.CheckCHeader("linux/awe_voice.h"), "Define to 1 if you have the <linux/awe_voice.h> header file."]
    platform["HAVE_LINUX_INPUT_H"] = [config.CheckCHeader("linux/input.h"), "Define to 1 if you have the <linux/input.h> header file."]
    platform["HAVE_LINUX_JOYSTICK_H"] = [config.CheckCHeader("linux/joystick.h"), "Define to 1 if you have the <linux/joystick.h> header file."]
    platform["HAVE_LINUX_SOUNDCARD_H"] = [config.CheckCHeader("linux/soundcard.h"), "Define to 1 if you have the <linux/soundcard.h> header file."]
    platform["HAVE_MACHINE_SOUNDCARD_H"] = [config.CheckCHeader("machine/soundcard.h"), "Define to 1 if you have the <machine/soundcard.h> header file."]
    platform["HAVE_MEMCMP"] = [config.CheckLib("c", "memcmp"), "Define to 1 if you have the \"memcmp\" function."]
    platform["HAVE_MEMORY_H"] = [config.CheckCHeader("memory.h"), "Define to 1 if you have the <memory.h> header file."]
    platform["HAVE_MKSTEMP"] = [config.CheckLib("c", "mkstemp"), "Define to 1 if you have the \"mkstemp\" function."]
    platform["HAVE_MMAP"] = [config.CheckLib("c", "mmap"), "Define to 1 if you have the \"mmap\" function."]
    platform["HAVE_NDIR_H"] = [config.CheckCHeader("ndir.h"), "Define to 1 if you have the <ndir.h> header file, and it defines \"DIR\"."]
    platform["HAVE_SOUNDCARD_H"] = [config.CheckCHeader("soundcard.h"), "Define to 1 if you have the <soundcard.h> header file."]
    platform["HAVE_STDBOOL_H"] = [config.CheckCHeader("stdbool.h"), "Define to 1 if stdbool.h conforms to C99."]
    platform["HAVE_STDINT_H"] = [config.CheckCHeader("stdint.h"), "Define to 1 if you have the <stdint.h> header file."]
    platform["HAVE_STDLIB_H"] = [config.CheckCHeader("stdlib.h"), "Define to 1 if you have the <stdlib.h> header file."]
    platform["HAVE_STRICMP"] = [config.CheckLib("c", "stricmp"), "Define to 1 if you have the \"stricmp\" function."]
    platform["HAVE_STRINGS_H"] = [config.CheckCHeader("strings.h"), "Define to 1 if you have the <strings.h> header file."]
    platform["HAVE_STRING_H"] = [config.CheckCHeader("string.h"), "Define to 1 if you have the <string.h> header file."]
    platform["HAVE_STRLWR"] = [config.CheckLib("c", "strlwr"), "Define to 1 if you have the \"strlwr\" function."]
    platform["HAVE_STRUPR"] = [config.CheckLib("c", "strup"), "Define to 1 if you have the \"strupr\" function."]
    platform["HAVE_SYS_DIR_H"] = [config.CheckCHeader("sys/dir.h"), "Define to 1 if you have the <sys/dir.h> header file, and it defines \"DIR\"."]
    platform["HAVE_SYS_IO_H"] = [config.CheckCHeader("sys/io.h"), "Define to 1 if you have the <sys/io.h> header file."]
    platform["HAVE_SYS_NDIR_H"] = [config.CheckCHeader("sys/ndir.h"), "Define to 1 if you have the <sys/ndir.h> header file, and it defines \"DIR\"."]
    platform["HAVE_SYS_SOUNDCARD_H"] = [config.CheckCHeader("sys/soundcard.h"), "Define to 1 if you have the <sys/soundcard.h> header file."]
    platform["HAVE_SYS_STAT_H"] = [config.CheckCHeader("sys/stat.h"), "Define to 1 if you have the <sys/stat.h> header file."]
    platform["HAVE_SYS_TIME_H"] = [config.CheckCHeader("sys/time.h"), "Define to 1 if you have the <sys/time.h> header file."]
    platform["HAVE_SYS_TYPES_H"] = [config.CheckCHeader("sys/types.h"), "Define to 1 if you have the <sys/types.h> header file."]
    platform["HAVE_SYS_UTSNAME_H"] = [config.CheckCHeader("sys/utsname.h"), "Define to 1 if you have the <sys/utsname.h> header file."]
    platform["HAVE_UNISTD_H"] = [config.CheckCHeader("unistd.h"), "Define to 1 if you have the <unistd.h> header file."]
    platform["HAVE_VPRINTF"] = [config.CheckLib("c", "vprintf"), "Define to 1 if you have the \"vprintf\" function."]
    platform["HAVE__BOOL"] = [config.CheckCHeader("stdbool.h"), "Define to 1 if the system has the type \"_Bool\"."]
    platform["MAP_FAILED"] = [config.CheckMapFailed(), "Define to (void *)-1, if MAP_FAILED is not defined."]
    platform["ALLEGRO_WITH_OSSDIGI"] = [config.CheckOSSDigi(), "Define if OSS DIGI driver is supported."]
    platform["ALLEGRO_WITH_OSSMIDI"] = [config.CheckOSSMidi(), "Define if OSS MIDI driver is supported."]

    ## Not checked yet
    platform["PACKAGE_BUGREPORT"] = ["", "Define to the address where bug reports for this package should be sent."]
    platform["ALLEGRO_WITH_MODULES"] = ["1", "Define if dynamically loaded modules are supported."]
    platform["PACKAGE_NAME"] = ["", "Define to the full name of this package."]
    platform["PACKAGE_STRING"] = ["", "Define to the full name and version of this package."]
    platform["PACKAGE_TARNAME"] = ["", "Define to the one symbol short name of this package."]
    platform["PACKAGE_VERSION"] = ["", "Define to the version of this package."]
    platform["RETSIGTYPE"] = ["void", "Define as the return type of signal handlers (\"int\" or \"void\")."]
    platform["STDC_HEADERS"] = ["1", "Define to 1 if you have the ANSI C header files."]
    platform["TIME_WITH_SYS_TIME"] = ["1", "Define to 1 if you can safely include both <sys/time.h> and <time.h>."]
    platform["TM_IN_SYS_TIME"] = [False, "Define to 1 if your <sys/time.h> declares \"struct tm\"."]
    platform["ALLEGRO_WITH_SGIALDIGI"] = [False, "Define if SGI AL DIGI driver is supported."]
    platform["WORDS_BIGENDIAN"] = [False, "Define to 1 if your processor stores words with the most significant\n byte first (like Motorola and SPARC, unlike Intel and VAX)."]
    platform["const"] = [False, "Define to empty if \"const\" does not conform to ANSI C."]

    platform["ALLEGRO_HAVE_SV_PROCFS"] = [False, "Define to 1 if you have a System V sys/procfs.h"]

    context.setLibraryEnv(config.Finish())
    env = context.getLibraryEnv()

    ## Write
    writeAutoHeader("include/allegro/platform/alunixac.h", platform)

    settings.add_section("unix")
    for setting in config_settings:
        val = env[setting]
        if hasattr(val, "data"): val = val.data # for CCFLAGS
        if not type(val) == list: val = [val]
        settings.set("unix", setting, str(val))

    settings.write(file("build/settings.cfg", "w"))

## Maybe setting up the assembler should be in a gcc.scons or something?
import SCons.Tool

AssemblerAction = Action( 'gcc -x assembler-with-cpp $CCFLAGS $_CPPINCFLAGS $SOURCES -c -o $TARGET' )

static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
shared_obj.add_action('.s', AssemblerAction )
shared_obj.add_emitter('.s', SCons.Defaults.SharedObjectEmitter )

flags = ["-g", "-Wall", "-Wno-unused", "-O2", "-funroll-loops", "-ffast-math", "-fomit-frame-pointer"]
includes = ["include", "include/allegro", "."]
defines = ["HAVE_CONFIG_H", "ALLEGRO_NO_ASM", "ALLEGRO_LIB_BUILD", "ALLEGRO_MODULES_PATH=\\\"%s/allegro\\\"" % context.getLibraryDir() ]

env.Append(CCFLAGS = flags)
env.Append(CPPDEFINES = defines)
env.Append(CPPPATH = includes)

context.addFiles('c/', Split("""
cblit16.c
cblit24.c
cblit32.c
cblit8.c
ccpu.c
ccsprite.c
cgfx15.c
cgfx16.c
cgfx24.c
cgfx32.c
cgfx8.c
cmisc.c
cscan15.c
cscan16.c
cscan24.c
cscan32.c
cscan8.c
cspr15.c
cspr16.c
cspr24.c
cspr32.c
cspr8.c
cstretch.c
czscan15.c
czscan16.c
czscan24.c
czscan32.c
czscan8.c
""" ));

context.addFiles("unix", Split("""
jack.c
sgial.c
udjgpp.c
udrvlist.c
udummy.c
ufdwatch.c
ufile.c
ugfxdrv.c
ujoydrv.c
ukeybd.c
umain.c
umodules.c
umouse.c
uoss.c
uossmidi.c
usnddrv.c
usystem.c
uthreads.c
utime.c
utimernu.c
uxthread.c
"""));

if platform["ALLEGRO_WITH_ESDDIGI"][0]:
    def buildESD(menv,appendDir,buildDir,libDir):
        esdEnv = menv.Copy()
        esdEnv.ParseConfig('esd-config --libs')
        sources = ["uesd.c"]
        return esdEnv.SharedLibrary(libDir + "/alleg-esddigi",appendDir(buildDir + "/unix/", sources))
    context.addExtra(buildESD)

if platform["ALLEGRO_WITH_ALSADIGI"][0]:
    def buildAlsa(menv,appendDir,buildDir,libDir):
        alsaEnv = menv.Copy()
        alsaEnv.Append(LIBS = "asound")
        sources = ["alsa5.c", "alsa9.c"]
        return alsaEnv.SharedLibrary(libDir + "/alleg-alsadigi",appendDir(buildDir + "/unix/", sources))
    context.addExtra(buildAlsa)

if platform["ALLEGRO_WITH_ALSAMIDI"][0]:
    def buildAlsa(menv,appendDir,buildDir,libDir):
        alsaEnv = menv.Copy()
        alsaEnv.Append(LIBS = "asound")
        sources = ["alsamidi.c"]
        return alsaEnv.SharedLibrary(libDir + "/alleg-alsamidi",appendDir(buildDir + "/unix/", sources))
    context.addExtra(buildAlsa)

# This might be broken. asmdefs.inc isnt generated until after svgalibs.s
# is compiled, but svgalib.s depends on asmdefs.inc. Either this dependancy
# needs to be fixed from scons or asmdefs.inc should be moved/generated elsewhere
if platform["ALLEGRO_LINUX_SVGALIB"][0]:
    def buildSVGA(menv,appendDir,buildDir,libDir):
        vgaEnv = menv.Copy()
        vgaEnv.Append(LIBS = "vga")
        vgaEnv.Depends(buildDir + '/linux/svgalibs.s','obj/unix/asmdef.inc')
        sources = ["svgalib.c","svgalibs.s"]
        lib = vgaEnv.SharedLibrary(libDir + "/alleg-svgalib",appendDir(buildDir + "/linux/", sources))
        vgaEnv.Cat('obj/unix/asmdef.inc', 'src/i386/asmdefs.inc')
        return lib
    context.addExtra(buildSVGA)

if platform["ALLEGRO_WITH_ARTSDIGI"][0]:
    def buildAlsa(menv,appendDir,buildDir,libDir):
        artsEnv = menv.Copy()
        artsEnv.ParseConfig("artsc-config --libs")
        sources = ["arts.c"]
        return artsEnv.SharedLibrary(libDir + "/alleg-artsdigi",appendDir(buildDir + "/unix/", sources))
    context.addExtra(buildAlsa)

if platform["ALLEGRO_LINUX_FBCON"][0]:
    def buildFBCon(menv,appendDir,buildDir,libDir):
        sources = ["fbcon.c"]
        return menv.SharedLibrary(libDir + "/alleg-fbcon",appendDir(buildDir + "/linux/", sources))
    context.addExtra(buildFBCon)

if platform["ALLEGRO_WITH_XWINDOWS"][0]:
    context.addFiles("x/", Split("""
    xgfxdrv.c
    xkeyboard.c
    xmouse.c
    xsystem.c
    xvtable.c
    xwin.c
    """));

    def tools(tenv,appendDir,buildDir,libDir):
        tools = []
        def addTool(name,files):
            tool = tenv.Program("tools/" + name, appendDir(buildDir + "/tools/", files))
            Alias(name, tool)
            tools.append(tool)
        addTool("x11/xf2pcx", ["x11/xf2pcx.c"])
        Alias("tools", tools)
        return tools

    context.addExtra(tools)

def pruneLibs(libs):
    import sets # needed for Python 2.3 compatibility
    return list(sets.Set(libs))

env.Replace(LIBS = pruneLibs(env["LIBS"]))

cat = Builder(action = "cat $SOURCES > $TARGET")
env.Append(BUILDERS = {"Cat" : cat})
    
context.setExampleEnv(env.Copy())
