#!/usr/bin/env python
import os
import sys
import SCons
import shutil

#TODO:
#-figure out what files actually need what defines and write separate builder lines for them (so that changing a #define doesn't cause a rebuild of everything)
#-
#-

# BIG FAT WARNING:
# Make sure you use TABS for indentation, NOT spaces! (Python likes spaces well enough, but would much prefer to share tea time with tabs)
#
#   ####       ####  ##########  #####    #####  #####    #####  #####    #####
#   ######   ######     ####      #####  #####    #####  #####    #####  #####
#   #### ## ## ####     ####        ########        ########        ########
#   ####   #   ####     ####      #####  #####    #####  #####    #####  #####
#   ####       ####  ##########  #####    #####  #####    #####  #####    #####
#
#  #############################################################################
#    #########################################################################
#

#
#Useful functions
#

print "WE ARE IN:", os.getcwd()

plugins = []

def getSVNRevision(): # GPL code taken from http://trac.zeitherrschaft.org/zzub/browser/trunk/SConstruct
	# if this is a repository, take the string from svnversion
	svnversionpath = env.WhereIs('svnversion', os.environ['PATH'])
	if os.path.isdir('../.svn') and (svnversionpath != None):  # we always start in .obj for some reason, so we must use ../.svn
		rev = os.popen('svnversion ..').readline().strip()
		if rev != "" and rev != "exported":
			return rev
	return ""

def getBZRRevision():
	return os.popen("bzr revno").readline().strip()

def getMixxxVersion():
	defs = File('#src/defs_version.h') #have to handle out-of-tree building, that's why the '#' :(
	#p = os.popen('grep -m 1 "#define VERSION" %s' % defs) #this is not cross-platform
	#version = p.readline()
	#p.close()
	
	for line in open(str(defs)).readlines():
		if line.strip().startswith("#define VERSION"):
			version = line
			break
	else:
		raise ValueError("Version not found")
	
	#given "#define VERSION "...."" extract "....":
	version = version.split()[-1].replace('"', '')
	return version

#Check for FFMPEG support
def CheckFFMPEG(conf, sources):
	flags_ffmpeg = ARGUMENTS.get('ffmpeg', 0)
	if int(flags_ffmpeg):
		if platform == 'linux':
			#Check for libavcodec, libavformat
			#I just randomly picked version numbers lower than mine for this - Albert
			if not conf.CheckForPKG('libavcodec', '51.20.0'):
				print 'libavcodec not found.'
				Exit(1)
			if not conf.CheckForPKG('libavformat', '51.1.0'):
				print 'libavcodec not found.'
				Exit(1)
			else:
				#Grabs the libs and cflags for ffmpeg
				env.ParseConfig('pkg-config libavcodec --silence-errors --cflags --libs')
				env.ParseConfig('pkg-config libavformat --silence-errors --cflags --libs')
				env.Append(CPPDEFINES = '__FFMPEGFILE__')
		else:
			# aptitude install libavcodec-dev libavformat-dev liba52-0.7.4-dev libdts-dev
			env.Append(LIBS = 'avcodec')
			env.Append(LIBS = 'avformat')
			env.Append(LIBS = 'z')
			env.Append(LIBS = 'a52')
			env.Append(LIBS = 'dts')
			env.Append(LIBS = 'gsm')
			env.Append(LIBS = 'dc1394_control')
			env.Append(LIBS = 'dl')
			env.Append(LIBS = 'vorbisenc')
			env.Append(LIBS = 'raw1394')
			env.Append(LIBS = 'avutil')
			env.Append(LIBS = 'vorbis')
			env.Append(LIBS = 'm')
			env.Append(LIBS = 'ogg')
			env.Append(CPPDEFINES = '__FFMPEGFILE__')
		sources += Split("""soundsourceffmpeg.cpp """)
		print "Not working FFMPEG support... enabled"
	else:
		print "Not working FFMPEG support... disabled"
	return	


# Checks for pkg-config on Linux
def CheckForPKGConfig( context, version='0.0.0' ):
	context.Message( "Checking for pkg-config (at least version %s)... " % version )
	ret = context.TryAction( "pkg-config --atleast-pkgconfig-version=%s" %version )[0]
	context.Result( ret )
	return ret

# Uses pkg-config to check for a minimum version
def CheckForPKG( context, name, version="" ):
	if version == "":
		context.Message( "Checking for %s... \t" % name )
		ret = context.TryAction( "pkg-config --exists '%s'" % name )[0]
	else:
		context.Message( "Checking for %s (%s or higher)... \t" % (name,version) )
		ret = context.TryAction( "pkg-config --atleast-version=%s '%s'" % (version,name) )[0]
		context.Result( ret )
	return ret

def getFlags(env, argflag, default=0):
	"""
	* get value passed as an argument to scons as argflag=value
	* if no value is passed to scons use stored value
	* if no value is stored, use default
	Returns the value and stores it in env[argflag]
	"""
	flags = ARGUMENTS.get(argflag, -1)
	if int(flags) < 0:
		if env.has_key(argflag):
			flags = env[argflag]
		else: #default value
			flags = default
	env[argflag] = flags
	return flags

###### MAIN LINE ######
#######################


Import('platform')
Import('machine')	#CPU Architecture for optimizing x64 builds

#Figure out what the QT path is


default_qtdir = {'linux': '/usr/share/qt4',
		 'bsd': '/usr/local/lib/qt4',
		 'osx': '/usr/lib/Qt-4.5', #XXX this should be smarter, we just need qt4 so we should accept the highest version that matches /usr/lib/Qt-4.*.*/
		 'win32': 'C:\\qt\\4.5.1',
		 'win64': 'C:\\qt\\4.5.1'}[platform]	 #ditto

#Read the qtdir flag, if it was set explicitly
flags_qtdir = ARGUMENTS.get('qtdir', os.environ.get('QTDIR', default_qtdir)) #environ['QTDIR'] there is mainly for the benefit of MSVC
if not os.path.exists(flags_qtdir):
	print "Error: QT path does not exist or QT4 is not installed."
	print "Please specify your QT path by running 'scons qtdir=[path]'"
	Exit(1)
elif flags_qtdir.find("qt3") != -1 or flags_qtdir.find("qt/3") != -1:
	print "Error: Mixxx now requires QT4 instead of QT3 - please use your QT4 path with the qtdir build flag."
	Exit(1)
else:
	print "QT path: " + flags_qtdir



#Set up our environment, tell SCONS to use it's QT tools, and set some enviroment variables for it.
#The ENV = os.environ part pulls in your existing environment variables. This is useful for awkward Linux setups
#and on Windows where all the paths are set in the shell.
if platform in ('linux', 'bsd'):
	env = Environment(tools=['default','qt4'], toolpath=['#build/'], QTDIR=flags_qtdir, ENV = os.environ)
	#Whoever hacked this in, it breaks scons for people who've set PKG_CONFIG_PATH in their shell. - Albert
 	#os.environ['PKG_CONFIG_PATH']=flags_qtdir+'lib/pkgconfig'  #Set the PKG_CONFIG_PATH explicitly, handles multiple QT 4.x installations
elif platform == 'osx':
	env = Environment(tools=['default', 'qt4', 'OSConsX'], toolpath=['#build/', '#/build/osx/'], ENV = os.environ)
elif 'win' in platform:
	#Pull in the environment's variables for win32...
	env = Environment(tools=['default','qt4', 'msvs'], toolpath=['#build/'], QTDIR=flags_qtdir, QT_LIB='', VCINSTALLDIR = os.getenv('VCInstallDir'), ENV = os.environ)
else:
	raise Exception("Unknown platform, didn't make a env variable. Crashing")

env['MIXXX_VERSION'] = getMixxxVersion() #should this be in the env?
env['CPPDEFINES'] = [''] #Initialize this as a list, fixes a bug where first CPPDEFINE would get mangled

## Global cache directory
## Put all project files in it so a rm -rf cache will clean up the config
if not env.has_key('CACHEDIR'):
	env['CACHEDIR'] = str(Dir('#cache/'))
if not os.path.isdir(env['CACHEDIR']):
	os.mkdir(env['CACHEDIR'])

## Avoid spreading .sconsign files everywhere
#env.SConsignFile(env['CACHEDIR']+'/scons_signatures')
## WARNING - We found that the above line causes SCons to randomly not find
##           dependencies for some reason. It might not happen right away, but
##           a good number of users found that it caused weird problems - Albert (May 15/08)


#Hijack scons -h and --help
cachefile = str(env['CACHEDIR']) + 'custom.py'
#opts = Options(cachefile)
vars = Variables(cachefile)
vars.Add('prefix', 'Set to your install prefix', '/usr/local')
vars.Add('qtdir', 'Set to your QT4 directory', '/usr/share/qt4')
vars.Add('djconsole', 'Set to 1 to enable Hercules support through libdjconsole', 0)
vars.Add('djconsole_legacy', 'Set to 1 to enable legacy Hercules support (for Hercules MP3 Control only, not MK2', 0)
vars.Add('hifieq', 'Set to 1 to enable high quality EQs', 1)
vars.Add('ipod', 'Set to 1 to enable iPod support through libgpod', 0)
vars.Add('ladspa', '(EXPERIMENTAL) Set to 1 to enable LADSPA plugin support', 1)
vars.Add('ffmpeg', '(EXPERIMENTAL) Set to 1 to enable FFMPEG support', 0)
vars.Add('vinylcontrol', 'Set to 1 to enable vinyl control support', 1)
vars.Add('shoutcast', 'Set to 1 to enable shoutcast support', 0)
vars.Add('cmetrics', 'Set to 1 to enable crash reporting/usage statistics via Case Metrics (This should be disabled on development builds)', 0)
vars.Add('optimize', 'Set to 1 to enable -O3 compiler optimizations. Set to 2 to enable Pentium 4 optimizations. Set to 3 to enable Intel Core optimizations, and set to 4 to enable Intel Core 2 optimizations.', 1)
vars.Add('script', 'Set to 1 to enable MixxxScript/QtScript Studio support.', 0)
vars.Add('midiscript', 'Set to 1 to enable MIDI Scripting support.', 1)
vars.Add('tonal', 'Set to 1 to enable tonal analysis', 0)
vars.Add('portmidi', 'Set to 1 to enable PortMidi unified MIDI backend', 0)
vars.Add('m4a','Set to 1 to enable support for M4A audio (Apple non-drm''d music format)', 0)
vars.Add('qdebug', 'Set to 1 to enable verbose console debug output.', 1)
vars.Add('test', 'Set to 1 to build Mixxx test fixtures.', 0)
if platform == 'linux':
	vars.Add('rawmidi', 'Set to 1 to use ALSA\'s RawMIDI API (instead of the Sequencer API.)', 0)
if not 'win' in platform:
	vars.Add('gprof', '(DEVELOPER) Set to 1 to enable profiling using gprof', 0)
	vars.Add('tuned', '(EXPERIMENTAL) Set to 1 to optimise mixxx for this CPU', 0)
	vars.Add('force32', 'Set to 1 to force GCC to compile a 32-bit binary with the -m32 flag', 0)
else:
	vars.Add('msvshacks', 'Set to 1 to build properly with MS Visual Studio 2005 (Express users should leave this off)', 0)
	vars.Add('msvcdebug', 'Set to 1 to link against MS libraries with debugging info (implies debug=1)', 0)
#env = Environment(options = opts)
vars.Update(env)
Help(vars.GenerateHelpText(env))

for getenv in ['CXXFLAGS', 'CCFLAGS', 'LINKFLAGS', 'LIBPATH', 'CPPPATH']:
	kwargs = {}
	if os.environ.has_key(getenv):
		kwargs[getenv] = SCons.Util.CLVar( os.environ[getenv] )
		env.Append(**kwargs)

#env.Append(CPPDEFINES=[('BUILD_REV', '"%s"' % getBZRRevision())]) #doing this forces a rebuild of everything whenever a commit happens -- not much fun
## instead, embed BZR version into build
## Put version info into a file, so it doesn't force a rebuild of everything :)
f = open("build.h","w")
try:
	f.write('#define BUILD_REV "' + getBZRRevision() + '"\n')
finally:
	f.close()

### embed SVN version into build
### Put version info into a file, so it doesn't force a rebuild of everything :)
#f = open("#.mixxx_version.h","w")
#try:
#	f.write('#define BUILD_REV "' + getSVNRevision() + '"\n')
#finally:
#	f.close()

#Mixxx sources to build
sources = Split("""
                
                input.cpp
                trackplaylistlist.cpp
                mixxxkeyboard.cpp
                configobject.cpp
                controlobjectthread.cpp
                controlobjectthreadwidget.cpp
                controlobjectthreadmain.cpp
                controlevent.cpp
                controllogpotmeter.cpp
                controlobject.cpp
                controlnull.cpp
                controlpotmeter.cpp
                controlpushbutton.cpp
                controlttrotary.cpp
                controlbeat.cpp

                dlgpreferences.cpp
                dlgprefsound.cpp
                dlgprefmidibindings.cpp
                dlgprefplaylist.cpp
                dlgprefnomidi.cpp
                dlgprefcontrols.cpp
                dlgbpmtap.cpp
                dlgprefbpm.cpp
                dlgbpmscheme.cpp
                dlgabout.cpp
                dlgprefeq.cpp
                dlgprefcrossfader.cpp
                dlgmidilearning.cpp

                engine/enginebuffercue.cpp
                engine/enginebuffer.cpp
                engine/enginebufferscale.cpp
		engine/enginebufferscaledummy.cpp
                engine/enginebufferscalelinear.cpp
		engine/enginebufferscalereal.cpp
                engine/engineclipping.cpp
                engine/enginefilterblock.cpp
                engine/enginefilteriir.cpp
                engine/enginefilter.cpp
                engine/engineobject.cpp
                engine/enginepregain.cpp
                engine/enginevolume.cpp
                engine/enginechannel.cpp
                engine/enginemaster.cpp
                engine/enginedelay.cpp
                engine/engineflanger.cpp
                engine/enginespectralfwd.cpp
                engine/enginevumeter.cpp
                engine/enginevinylsoundemu.cpp
                engine/enginesidechain.cpp
                engine/enginefilterbutterworth8.cpp
                engine/enginexfader.cpp
                
                analyserqueue.cpp
		analyserwavesummary.cpp
		analyserbpm.cpp
		analyserwaveform.cpp
                
                main.cpp
                midiobject.cpp
                midimapping.cpp
                midiobjectnull.cpp
                mididevicehandler.cpp
                midiinputmappingtablemodel.cpp
                midioutputmappingtablemodel.cpp
                midichanneldelegate.cpp
                midistatusdelegate.cpp
                midinodelegate.cpp
                midioptiondelegate.cpp
                controlgroupdelegate.cpp
                controlvaluedelegate.cpp
                midimessage.cpp
                mixxxcontrol.cpp
                mixxx.cpp
                mixxxview.cpp
                errordialog.cpp
                upgrade.cpp
                
                soundsource.cpp
                soundsourcemp3.cpp
                soundsourceoggvorbis.cpp

                widget/wwidget.cpp
                widget/wlabel.cpp
                widget/wnumber.cpp
                widget/wnumberpos.cpp
                widget/wnumberrate.cpp
                widget/wnumberbpm.cpp
                widget/wknob.cpp
                widget/wdisplay.cpp
                widget/wvumeter.cpp
                widget/wpushbutton.cpp
                widget/wslidercomposed.cpp
                widget/wslider.cpp
                widget/wstatuslight.cpp
		widget/woverview.cpp
		widget/wskincolor.cpp
		widget/wabstractcontrol.cpp
                widget/wsearchlineedit.cpp
		widget/wpixmapstore.cpp
				widget/hexspinbox.cpp
                
                mathstuff.cpp
                readerextract.cpp
                readerextractwave.cpp
                readerevent.cpp
                rtthread.cpp
                windowkaiser.cpp
                probabilityvector.cpp
                reader.cpp

                peaklist.cpp
                rotary.cpp
                track.cpp
                trackcollection.cpp
                trackplaylist.cpp
                wtracktableview.cpp
                wtracktablemodel.cpp
                wpromotracksmodel.cpp
                proxymodel.cpp
                xmlparse.cpp
                trackimporter.cpp
                parser.cpp
                parserpls.cpp
                parserm3u.cpp

                bpm/bpmscheme.cpp

                soundsourceproxy.cpp

                widget/wvisualsimple.cpp
                widget/wwaveformviewer.cpp
                widget/wglwaveformviewer.cpp
                waveformviewerfactory.cpp
                waveform/waveformrenderer.cpp
		waveform/waveformrenderbackground.cpp
		waveform/waveformrendersignal.cpp
		waveform/waveformrendersignalpixmap.cpp
		waveform/waveformrendermark.cpp	
                waveform/waveformrenderbeat.cpp
                
                
                imginvert.cpp
                imgloader.cpp
                imgcolor.cpp
                
                trackinfoobject.cpp
                midiledhandler.cpp
                sounddevice.cpp
                soundmanager.cpp
                sounddeviceportaudio.cpp
                dlgprefrecord.cpp
                recording/enginerecord.cpp
                recording/writeaudiofile.cpp
                wtracktablefilter.cpp
                wplaylistlistmodel.cpp
                libraryscanner.cpp
                libraryscannerdlg.cpp
                playerinfo.cpp
                
                segmentation.cpp
                """)

#Compile platform specific hardware support
#if platform == 'linux':
#	sources += Split("""powermatelinux.cpp herculeslinux.cpp mouselinux.cpp """)
#elif 'win' in platform:
#	sources += Split("""powermatewin.cpp mousewin.cpp """)

#Compile platform specific MIDI support
#   Linux moved to the flag parsing area since it depends on the rawmidi flag
if 'win' in platform:
	sources += Split("""midiobjectwin.cpp """)	  #Windows MIDI support
	env.Append(CPPDEFINES = '__WINMIDI__')
elif platform == 'osx':
	sources += Split("""midiobjectcoremidi.cpp """) #CoreMidi support for OS X
	env.Append(CPPDEFINES = '__COREMIDI__')
elif platform == 'bsd':
	print 'Warning: Mixxx has no support for BSD midi (yet).' #uuuuhhhh not a very good solution

#Set up the library path on Windows:
if platform == 'win64':
	env.Append(CPPPATH='#/../mixxx-win64lib') #If you add more directories, separate them with a semicolon (;)
	env.Append(LIBPATH='#/../mixxx-win64lib')

if platform == 'win32':
	env.Append(CPPPATH='#/../mixxx-winlib') #If you add more directories, separate them with a semicolon (;)
	env.Append(LIBPATH='#/../mixxx-winlib')

if 'win' in platform:
	env.Append(CPPPATH='../../lib/ladspa') #If you add more directories, separate them with a semicolon (;)
	env.Append(LINKFLAGS = ['/nodefaultlib:libc.lib', '/nodefaultlib:libcd.lib',  '/entry:mainCRTStartup'])
#'/subsystem:windows',

if platform == 'bsd':
	env.Append(CPPPATH=['/usr/include', '/usr/local/include', '/usr/X11R6/include/'])
	env.Append(LIBPATH=['/usr/lib/', '/usr/local/lib', '/usr/X11R6/lib'])
#BSD hacks
#XXX todo: move these into their proper places

	env.Append(LIBS='pthread')
	env.Append(LIBS=['ogg', 'vorbis']) #why do we need to do this on OpenBSD and not on Linux? if we don't then CheckLib("vorbisfile") fails
elif platform == 'osx':	
	#Non-standard libpaths for fink and certain (most?) darwin ports
	env.Append(LIBPATH = ['/sw/lib'])
	env.Append(CPPPATH = ['/sw/include'])

	#Non-standard libpaths for darwin ports
	env.Append(LIBPATH = ['/opt/local/lib'])
	env.Append(CPPPATH = ['/opt/local/include'])


#Check for dependencies if we're not doing a clean...
#if not env.GetOption('clean') and not SCons.Util.containsAny(os.sys.argv, ['-h', '--help']):
conf = Configure(env, custom_tests = { 'CheckForPKGConfig' : CheckForPKGConfig, 'CheckForPKG' : CheckForPKG })


#PortMidi backend support
flags_portmidi = getFlags(env, 'portmidi', 0)
if int(flags_portmidi):
	if not conf.CheckLib(['portmidi', 'libportmidi']):
		print "Did not find portmidi or it\'s development headers, exiting!"
		Exit(1)
	#if not conf.CheckLib(['porttime', 'libporttime']):
	#	print "Did not find porttime or it\'s development headers, exiting!"
	#	Exit(1)
	sources += Split("""midiobjectportmidi.cpp """); 
	env.Append(CPPDEFINES = '__PORTMIDI__')



#TODO: Add all of the other configure checks as custom_tests properly.
	
# On Posix default SCons.LIBPREFIX = 'lib', on Windows default SCons.LIBPREFIX = ''

#XXX all these Exit(1) calls should be turned into a list of libs to look for and then a loop that does the exit if any(conf.CheckLib(lib) for lib in list)
if not conf.CheckLib('portaudio'):
	print 'Did not find libportaudio.a, portaudio.lib, or the PortAudio-v19 development header files - exiting!'
	Exit(1)
	
if not conf.CheckLib(['id3tag','libid3tag-release']):
	print 'Did not find libid3tag.a, libid3tag.lib, or the libid3tag development header files - exiting!'
	Exit(1)

if not conf.CheckLib(['mad','libmad']):
	print 'Did not find libmad.a, libmad.lib, or the libmad development header files - exiting!'
	Exit(1)

#Check for libsndfile
#if not conf.CheckLibWithHeader(['sndfile', 'libsndfile'], 'sndfile.h', 'C'):
if not conf.CheckLib(['sndfile', 'libsndfile']):
	print "Did not find libsndfile or it\'s development headers, exiting!"
	Exit(1)
else:
	#env.Append(LIBS='sndfile') #XXX is this necessary?
	env.Append(CPPDEFINES = '__SNDFILE__')
	sources.append('soundsourcesndfile.cpp') ## TODO: Convert this to a SharedLibrary, so it can be installed without having to run scons twice after a clean


#Check for Ogg and Vorbis
if platform == 'win64':
	if not conf.CheckLib('vorbisfile_static'): # For some reason this has to be checked this way on win64, otherwise it looks for the dll lib which will cause a conflict later (at line 713)
		print 'Did not find vorbisfile_static.lib or the libvorbisfile development headers, exiting!'
		Exit(1)
else:
	if not conf.CheckLib('vorbisfile'):
		print 'Did not find libvorbisfile.a, libvorbisfile.lib, or the libvorbisfile development headers, exiting!'
		Exit(1)

if not conf.CheckLib('vorbis'):
	print 'Did not find libvorbis.a, libvorbis.lib, or the libvorbisfile development headers, exiting!'
	Exit(1)

if not conf.CheckLib('ogg'):
	print 'Did not find libogg.a, libogg.lib, or the libogg development headers, exiting!'
	Exit(1)

#hack: check for these here, before conf.Finish happens
have_m4a = conf.CheckLib('mp4')
have_faad = conf.CheckLib('faad')
have_m4a = have_m4a and have_faad

## Check for OpenGL (it's messy to do it for all three platforms)
## XXX this should *NOT* have hardcoded paths like this
if not conf.CheckLib('GL') and not conf.CheckLib('opengl32') and not conf.CheckCHeader('/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/gl.h') and not conf.CheckCHeader('GL/gl.h'):
	print 'Did not find OpenGL development files, exiting!'
	Exit(1)

if not conf.CheckLib('GLU') and not conf.CheckLib('glu32') and not conf.CheckCHeader('/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/glu.h'):
	print 'Did not find GLU development files, exiting!'
	Exit(1)
	
#Check if FFMPEG was enabled
CheckFFMPEG(conf, sources)


#Platform-specific checks for Linux...
if platform == 'linux':
	#Check for g++ (yeah, SCONS is a bit dumb here)
	if os.system("which g++ > /dev/null"): #Checks for non-zero return code
		print "Did not find g++, exiting!"
		Exit(1)
	
	#Check for pkg-config
	if not conf.CheckForPKGConfig('0.15.0'):
		print 'pkg-config >= 0.15.0 not found.'
		Exit(1)
		
	#Check for QT >= 4.3	
	if not conf.CheckForPKG('QtCore', '4.3'):
		print 'QT >= 4.3 not found.'
		Exit(1)
	else:
		#Grabs the QT4 include paths
		"""
		env.ParseConfig('pkg-config QtCore --silence-errors --cflags --libs')
		env.ParseConfig('pkg-config Qt3Support --silence-errors --cflags') #QT3 support breaks the build
		env.ParseConfig('pkg-config QtGui --silence-errors --cflags --libs')
		env.ParseConfig('pkg-config QtXml --silence-errors --cflags --libs')
		env.ParseConfig('pkg-config QtOpenGL --silence-errors --cflags --libs')
		env.ParseConfig('pkg-config QtScript --silence-errors --cflags --libs')
		"""
		#Try using David's qt4.py's Qt4-module finding thingy instead of pkg-config.
		#(This hopefully respects our qtdir=blah flag while linking now.)
		
		env.EnableQt4Modules([
		'QtCore',
		'QtGui',
		'QtOpenGL',
		'Qt3Support',
		'QtXml',
		'QtSvg',
		'QtScript',
		#'QtUiTools',
		#'QtDesigner',
		#'QtWebKit',
		],
		debug=False,
		)
		

	#Check for libasound (libasound2?) (needed for ALSA seq MIDI support)
	if not conf.CheckLib('asound') and not conf.CheckForPKG('alsa', '1.0.10'):
		print "Did not find libasound (aka. libasound2), exiting!"
		Exit(1)
        #Check for libdjconsole, if it was passed as a flag
	flags_djconsole = getFlags(env, 'djconsole', 0)
	flags_djconsole_legacy = getFlags(env, 'djconsole_legacy', 0)
	if int(flags_djconsole):
		if not conf.CheckLibWithHeader('djconsole', 'libdjconsole/djconsole.h', 'C++'):
			print "Did not find libdjconsole or it\'s development headers, exiting!"
			Exit(1)
		env.ParseConfig('pkg-config libdjconsole --silence-errors --cflags --libs')
		env.Append(CPPDEFINES = '__LIBDJCONSOLE__')
	elif int(flags_djconsole_legacy):
		# legacy support can not be enabled if libDJConsole support is enabled via djconsole=1
		env.Append(CPPDEFINES = '__DJCONSOLE_LEGACY__')

	#Another check for PortAudio-v19 # why? -kousu
	env.ParseConfig('pkg-config --cflags --libs portaudio-2.0')
		#If the above line looks like magic, it's because it really is. (Read about ParseConfig, it's nifty)

#Platform-specific checks for OS X
if platform == 'osx':
	
	env.Append(CPPPATH='/Library/Frameworks/OpenGL.framework/Headers/')
	env.Append(LINKFLAGS='-framework OpenGL')
	
	#QT4
	env.Append(LINKFLAGS = '-framework QtCore -framework QtOpenGL -framework Qt3Support -framework QtGui -framework QtXml -framework QtNetwork -framework QtSql -framework QtScript')
	env.Append(CPPPATH = ['/Library/Frameworks/QtCore.framework/Headers/',
				'/Library/Frameworks/QtOpenGL.framework/Headers/',
				'/Library/Frameworks/Qt3Support.framework/Headers/',
				'/Library/Frameworks/QtGui.framework/Headers/',
				'/Library/Frameworks/QtXml.framework/Headers/',
				'/Library/Frameworks/QtXml.framework/Headers/',
				'/Library/Frameworks/QtScript.framework/Headers/'])
	
	#Non-standard libpaths for fink and darwin ports
	env.Append(LIBPATH = ['/sw/lib'])
	env.Append(CPPPATH = ['/sw/include'])
			
	#Check for CoreMIDI
	if not conf.CheckCXXHeader('/System/Library/Frameworks/CoreMIDI.framework/Headers/CoreMIDI.h'):
		print 'Did not find CoreMIDI framework, exiting! (Please install it)'
		Exit(1)
	else:
		env.Append(LINKFLAGS = '-framework CoreMIDI -framework CoreFoundation -framework CoreAudio -framework Carbon -framework Quicktime -framework AudioToolbox -framework AudioUnit') #Have to add the rest of these frameworks somewhere..



env = conf.Finish()

#Declare the flags for Mixxx's config/track listing files:
#The quotes are necessary, since these are used directly in C code as strings
if platform in ('linux', 'bsd'):
        _mixxx_files = [('SETTINGS_PATH','.mixxx/'), ('BPMSCHEME_FILE','mixxxbpmscheme.xml'), ('SETTINGS_FILE', 'mixxx.cfg'), ('TRACK_FILE', 'mixxxtrack.xml')]
elif platform == 'osx': #right now this is the same as linux and bsd, but these files should really go in ~/Library/Applicationsomething like the rest of OS X apps do
        _mixxx_files = [('SETTINGS_PATH','.mixxx/'), ('BPMSCHEME_FILE', 'mixxxbpmscheme.xml'), ('SETTINGS_FILE', 'mixxx.cfg'), ('TRACK_FILE', 'mixxxtrack.xml')]
elif 'win' in platform:
        _mixxx_files = [('SETTINGS_PATH','Local Settings/Application Data/Mixxx/'), ('BPMSCHEME_FILE', 'mixxxbpmscheme.xml'), ('SETTINGS_FILE', 'mixxx.cfg'), ('TRACK_FILE', 'mixxxtrack.xml')]
_mixxx_files = [(k, r'\"' + v + r'\"') for k,v in _mixxx_files] #escape the filepaths, so that they wind up as C-strings to the C-compiler (the \s are so the shell doesn't eat the ")
env.Append(CPPDEFINES=_mixxx_files)
del _mixxx_files #safety net

# say where to find resources on Unix
# XXX we should replace this with a RESOURCES_PATH and covers Win and OS X too
if platform in ('linux', 'bsd'):
	env.Append(CPPDEFINES=('UNIX_SHARE_PATH', r'\"' + os.path.join(ARGUMENTS.get('prefix', '/usr/local'),'share/mixxx') + r'\"'))

#declare platform specific flags? though we shouldn't really need these, the compilers should Just Know...
#on __APPLE__ it works like that. probably we just need to look into what the default __platform__ #defines are and search and replace in the code
env.Append(CPPDEFINES=machine)

if platform == 'linux':
	env.Append(CPPDEFINES='__LINUX__')
elif platform == 'bsd':
	env.Append(CPPDEFINES='__BSD__')
elif 'win' in platform:
	env.Append(CPPDEFINES='__WINDOWS__')
	env.Append(CPPDEFINES='UNICODE')	# Need this on Windows until we have UTF16 support in Mixxx
	if platform == 'win32':	
		env.Append(CPPDEFINES='WIN32')
	if platform == 'win64':	
		env.Append(CPPDEFINES='WIN64')

if platform in ('linux', 'bsd'): #a define for code that works on unix only can ask for (not sure if this is actually used anywhere)
	env.Append(CPPDEFINES='__UNIX__')

env.Append(CPPDEFINES = '__PORTAUDIO__'); #Turn on PortAudio support in Mixxx
env.Append(CPPPATH = ['.', '../', '../../']) #Fun fun fun with paths


if platform in ('linux', 'bsd'):
	env.Append(LIBS = 'Qt3Support')
	env.Append(LIBS = 'QtXml')
	env.Append(LIBS = 'QtGui')
	env.Append(LIBS = 'QtCore')
	env.Append(LIBS = 'QtOpenGL')
	env.Append(LIBS = 'QtScript')
	env.Append(LIBS = 'sndfile') #? we shouldn't have to do this...
	env.Append(LIBS = 'vorbisfile') #? we shouldn't have to do this...

if 'win' in platform:
	env.Append(LIBS = 'Qt3Support4'); #Win32 needs this instead of 'Qt3Support'
	env.Append(LIBS = 'QtXml4');
	env.Append(LIBS = 'QtGui4');
	env.Append(LIBS = 'QtCore4');
	env.Append(LIBS = 'QtOpenGL4');
	env.Append(LIBS = 'WinMM'); #Needed for Midi stuff
	env.Append(LIBS = 'ogg_static')
	env.Append(LIBS = 'vorbis_static')
	env.Append(LIBS = 'vorbisfile_static')
	env.Append(LIBS = 'imm32')
	env.Append(LIBS = 'wsock32')
	env.Append(LIBS = 'delayimp')
	env.Append(LIBS = 'winspool')
	env.Append(LIBS = 'shell32')

env.Append(CPPDEFINES = ['QT3_SUPPORT', 'QT3_SUPPORT_WARNINGS', 'QT_THREAD_SUPPORT', 'QT_SHARED', 'QT_TABLET_SUPPORT']) #Stolen from Mixxx's build output

if platform in ('linux','bsd') or 'win' in platform:
	env.Append(CPPPATH=['$QTDIR/include/Qt3Support',
			    '$QTDIR/include/QtCore',
			    '$QTDIR/include/QtGui',
			    '$QTDIR/include/QtXml',
			    '$QTDIR/include/QtOpenGL',
			    '$QTDIR/include/Qt'])

if 'win' in platform:
	env.Append(CPPPATH=["$VCINSTALLDIR/include/atl", "C:/Program Files/Microsoft Platform SDK/Include/atl"])

if 'win' in platform:
	env.Append(CPPDEFINES = 'WIN32') #for soundtouch
else:
	env.Append(CCFLAGS = Split(""" -pipe -Wall -W -g """)) # omghax
	env.Append(LINKFLAGS = Split(""" -pipe -Wall -W -g"""))
	if platform != 'osx':
		env.Append(LINKFLAGS = "-Wl,-rpath,$QTDIR/lib")
	env.Append(LINKFLAGS = "-Wl,-rpath,$QTDIR/lib")
	env.Append(CPPDEFINES = "_REENTRANT")

#Uic these guys (they're moc'd automatically after this) - Generates the code for the QT UI forms
env.Uic4('dlgpreferencesdlg.ui')
env.Uic4('dlgprefsounddlg.ui')
env.Uic4('dlgprefmidibindingsdlg.ui')
env.Uic4('dlgprefplaylistdlg.ui')
env.Uic4('dlgprefnomididlg.ui')
env.Uic4('dlgprefcontrolsdlg.ui')
env.Uic4('dlgprefeqdlg.ui')
env.Uic4('dlgprefcrossfaderdlg.ui')
env.Uic4('dlgprefbpmdlg.ui')
env.Uic4('dlgbpmschemedlg.ui')
env.Uic4('dlgbpmtapdlg.ui')
env.Uic4('dlgprefvinyldlg.ui')
env.Uic4('dlgprefrecorddlg.ui')
env.Uic4('dlgaboutdlg.ui')
env.Uic4('dlgmidilearning.ui')

#Add the QRC file which compiles in some extra resources (prefs icons, etc.)
env.Qrc('#res/mixxx.qrc')
sources += Split(""" #res/qrc_mixxx.cc """)

if 'win' in platform:
	env.RES('mixxx.rc')
	sources += Split(""" mixxx.res """)

#Tell SCons to build libraries that are bundled with Mixxx
#===================================================

#SoundTouch
#XXX this should be done with a subsconscript
env.Append(CPPPATH=['#lib/soundtouch-1.4.1'])
sources += Split("""engine/enginebufferscalest.cpp
                    #lib/soundtouch-1.4.1/SoundTouch.cpp
                    #lib/soundtouch-1.4.1/TDStretch.cpp
                    #lib/soundtouch-1.4.1/RateTransposer.cpp
                    #lib/soundtouch-1.4.1/AAFilter.cpp
                    #lib/soundtouch-1.4.1/FIFOSampleBuffer.cpp
                    #lib/soundtouch-1.4.1/FIRFilter.cpp
                    #lib/soundtouch-1.4.1/PeakFinder.cpp
                    #lib/soundtouch-1.4.1/BPMDetect.cpp
                    """)

if 'win' in platform:
	if platform == 'win32':
		sources += Split("""#lib/soundtouch-1.4.1/cpu_detect_x86_win.cpp""")
	if platform == 'win64':
		sources += Split("""#lib/soundtouch-1.4.1/cpu_detect_x64_win.cpp""")
else:
	if machine == 'x86_64':
		sources += Split("""#lib/soundtouch-1.4.1/cpu_detect_x64_gcc.cpp""")
	else:
		sources += Split("""#lib/soundtouch-1.4.1/cpu_detect_x86_gcc.cpp""")


#KissFFT
env.Append(CPPPATH=['#lib/kissfft'])
sources += Split("""#lib/kissfft/kiss_fft.c""")

#libsamplerate - Getting rid of this out of our source tree since we don't use it. 
#env.Append(CPPPATH='#lib/libsamplerate')
#sources += Split("""engine/enginebufferscalesrc.cpp #lib/libsamplerate/samplerate.c #lib/libsamplerate/src_linear.c #lib/libsamplerate/src_sinc.c #lib/libsamplerate/src_zoh.c""")

#fidlib (for EQs)
#XXX this should be a SharedLib() line
env.Append(CPPPATH='#lib/fidlib-0.9.9/')
sources += Split("""#lib/fidlib-0.9.9/fidlib.c """)

## Platform-specific compile/link flags needed for fidlib
if 'win' in platform:
	env.Append(CPPDEFINES = 'T_MSVC')
	#env.Append(CXXFLAGS = '-DT_MSVC') #is this still needed?
	env.Append(LINKFLAGS = ['/nodefaultlib:LIBCMT.lib', '/nodefaultlib:LIBCMTD.lib'])
	env.Append(CXXFLAGS = '/Zc:wchar_t-') #Ugh, MSVC-only hack :( see http://www.qtforum.org/article/17883/problem-using-qstring-fromstdwstring.html
else:
	env.Append(CPPDEFINES = 'T_LINUX') #so maybe "T_LINUX" isn't really accurate for an else case, but the only platforms really in existence are Unix and Win right now, and that's all we're targetting


#Parse command-line build flags
build_flags = ""

print "\nFeatures Summary:\n================"


#Hercules support through libdjconsole on Linux
#(handled somewhere else above this in the file...
# just printing the summary here)
flags_djconsole = getFlags(env, 'djconsole', 0)
if int(flags_djconsole) == 0:
	print "libdjconsole support... disabled"
else:
	print "libdjconsole support... enabled"
	build_flags += 'djconsole '

#High quality EQs
flags_hifieq = getFlags(env, 'hifieq', 1)
if int(flags_hifieq) == 0:
	env.Append(CPPDEFINES = ['__LOFI__', '__NO_INTTYPES__']) #Enables old crappy EQs
	print "High quality EQs... disabled"
else:
	print "High quality EQs... enabled"
	build_flags += 'hifieq '

#Experimental IPOD support
flags_ipod = getFlags(env, 'ipod', 0)
if int(flags_ipod):
	env.Append(CPPDEFINES = '__IPOD__')

	if 'win' in platform:
		env.Append(LIBS = 'gpod');
		# You must check v-this-v directory out from http://publicsvn.songbirdnest.com/vendor-binaries/trunk/windows-i686-msvc8/libgpod/
		env.Append(LIBPATH='../../../windows-i686-msvc8/libgpod/release/lib')
		# Following building the following must be added to the dist folder in order for mixxx to run with ipod support on Win32
		# \windows-i686-msvc8\libgpod\release\lib\libgpod.dll
		# \windows-i686-msvc8\glib\release\bin\libgobject-2.0-0.dll
		# \windows-i686-msvc8\glib\release\bin\libglib-2.0-0.dll
		# \windows-i686-msvc8\libiconv\release\bin\iconv.dll
		# \windows-i686-msvc8\gettext\release\binintl.dll
	if platform == 'linux' or platform == 'osx':
		# env.Append(LIBS = 'libgpod-1.0')
		# env.Append(LIBS = 'glib-2.0')
		env.ParseConfig('pkg-config libgpod-1.0 --silence-errors --cflags --libs')
		env.ParseConfig('pkg-config glib-2.0 --silence-errors --cflags --libs')
		
	sources += Split("""wipodtracksmodel.cpp """) #IPOD
	print "iPod support... enabled"
	build_flags += 'ipod '
else:
	print "iPod support... disabled"

#Experimental Shoutcast
flags_shoutcast = getFlags(env, 'shoutcast', 0)

if int(flags_shoutcast):
	shoutmp3 = 0
	shoutogg = 0
	
	conf = Configure(env, custom_tests = { 'CheckForPKGConfig' : CheckForPKGConfig, 'CheckForPKG' : CheckForPKG })
	conf.CheckLib('shout')
	
	env.Append(CPPDEFINES = '__SHOUTCAST__')
	
	sources += Split(""" dlgprefshoutcast.cpp engine/engineshoutcast.cpp encoder.cpp """ )
	build_flags += 'shoutcast '
	
	
	if conf.CheckLib('mp3lame'):
		env.Append(CPPDEFINES = '__SHOUTCAST_LAME__')
		sources += Split(""" encodermp3.cpp """)
		shoutmp3 = 1
	
	if conf.CheckLib('vorbisenc'):
		env.Append(CPPDEFINES = '__SHOUTCAST_VORBIS__')
		sources += Split("""  encodervorbis.cpp """)
		shoutogg = 1
	
	
	if shoutmp3 and shoutogg:
		print "Shoutcast support (OGG/MP3)... enabled"
	elif shoutmp3:
		print "Shoutcast support (MP3)... enabled"
	elif shoutogg:
		print "Shoutcast support (OGG)... enabled"
	else:
		print "Shoutcast support... enabled"
	
	env.Uic4('dlgprefshoutcastdlg.ui')
	
else:
	print "Shoutcast support... disabled"

#LADSPA
flags_ladspa = 1; #Forcing ladspa on always now #= getFlags(env, 'ladspa', 0)
if int(flags_ladspa):
	env.Append(CPPPATH=['#lib/ladspa']) #If you add more directories, separate them with a semicolon (;)
	env.Append(CPPDEFINES = '__LADSPA__')
	sources += Split("""engine/engineladspa.cpp
                            ladspa/ladspaloader.cpp
                            ladspa/ladspalibrary.cpp
                            ladspa/ladspaplugin.cpp
                            ladspa/ladspainstance.cpp
                            ladspa/ladspacontrol.cpp
                            ladspa/ladspainstancestereo.cpp
                            ladspa/ladspainstancemono.cpp
                            ladspaview.cpp
                            ladspa/ladspapreset.cpp
                            ladspa/ladspapresetmanager.cpp
                            ladspa/ladspapresetknob.cpp
                            ladspa/ladspapresetinstance.cpp
                            dlgladspa.cpp
                            ladspa/ladspapresetslot.cpp
                            """)
	plugins += SConscript(File('#lib/ladspa/SConscript'))
	env.Alias('plugins', plugins)
	print "LADSPA support... enabled"
	build_flags += 'ladspa '
else:
	print "LADSPA support... disabled"

#Vinyl Control
flags_vinylcontrol = getFlags(env, 'vinylcontrol', 1)
if int(flags_vinylcontrol):
	env.Append(CPPDEFINES = '__VINYLCONTROL__')
	sources += Split(""" vinylcontrol.cpp vinylcontrolproxy.cpp vinylcontrolscratchlib.cpp vinylcontrolxwax.cpp dlgprefvinyl.cpp vinylcontrolsignalwidget.cpp engine/enginevinylcontrol.cpp """)
	env.Append(CPPPATH='#lib/xwax')
	if 'win' in platform:
		sources += Split("""#lib/xwax/timecoder_win32.c """)
	else:
		sources += Split("""#lib/xwax/timecoder.c """)
	env.Append(CPPPATH='#lib/scratchlib')
	sources += Split("""#lib/scratchlib/DAnalyse.cpp """)
	print "Vinyl Control... enabled"
	build_flags += 'vinylcontrol '
else:
	print "Vinyl Control... disabled"

flags_msvcdebug = getFlags(env, 'msvcdebug', 0)
if 'win' in platform:
	if int(flags_msvcdebug):
		env.Append(CCFLAGS = '/MDd') # required for sndfile w/ flac support on windows
		env.Append(LINKFLAGS = '/DEBUG')
		if platform == 'win64':
			env.Append(CXXFLAGS = '/Zi')
			env.Append(LINKFLAGS = '/NODEFAULTLIB:MSVCRT')
		else:
			env.Append(CXXFLAGS = '/ZI')
		print "MSVC Debugging... enabled"
		build_flags += 'msvcdebug '
	else:
		env.Append(LINKFLAGS = '/subsystem:windows')
		env.Append(CCFLAGS = '/MD') # required for sndfile w/ flac support on windows
		print "MSVC Debugging... disabled"


flags_tonal = getFlags(env, 'tonal', 0)
if int(flags_tonal):
	print "Tonal analysis... enabled"
	build_flags += 'tonal '
	sources += Split("""tonal/FourierTransform.cxx tonal/Segmentation.cxx
			tonal/tonalanalyser.cpp tonal/ConstantQTransform.cxx
			tonal/ConstantQFolder.cxx""")
else:
	print "Tonal analysis... disabled"


flags_m4a = getFlags(env, 'm4a', 0)
if int(flags_m4a):
	print "Apple M4A audio file support...",
	if have_m4a:
		print "enabled"
	#	env.ParseConfig('pkg-config libmp4v2-dev --silence-errors --cflags --libs') # no pkg-config data for libmp4v2-dev
	#	FIXME: should do conf.CheckCHeader('mp4.h') or something...
		env.Append(CPPDEFINES = '__M4A__')
		build_flags += 'm4a '
		sources += Split("""soundsourcem4a.cpp m4a/mp4-mixxx.cpp""");  # MP4/M4A Support
		env.Append(LIBS = 'libmp4v2')
		env.Append(LIBS = 'libfaad')
	else:
		print "not found (did you install libmp4v2 and libfaad?)"
else:
	print "Apple M4A audio file support... disabled"


def build_gtest():
	gtest_dir = env.Dir("#lib/gtest-1.3.0")
	gtest_dir.addRepository(env.Dir('#lib/gtest-1.3.0'))
	#env['EXE_OUTPUT'] = '#/lib/gtest-1.3.0/bin'  # example, optional
	env['LIB_OUTPUT'] = '#/lib/gtest-1.3.0/lib'
	Export('env')
	env.SConscript(env.File('scons/SConscript', gtest_dir))

	env.Append(LIBPATH="#lib/gtest-1.3.0/lib")
	env.Append(LIBS = 'gtest')
	env.Append(CPPPATH="#lib/gtest-1.3.0/include")
	
def build_tests():
	test_sources = (Glob('test/*.cpp', strings=True) + [x for x in sources if x != "main.cpp"])
	env.Program(target='mixxx-test', source=test_sources)
	Command("../mixxx-test", "./mixxx-test", Copy("$TARGET", "$SOURCE"))

def run_tests():
	ret = Execute("./mixxx-test")
	if ret != 0:
		print "WARNING: Not all tests pass. See mixxx-test output."
		Exit(ret)

flags_test = getFlags(env, 'test', 0) or 'test' in BUILD_TARGETS

if int(flags_test):
	print "Test suite... enabled"
	build_gtest()
	build_flags += 'test '
else:
	print "Test suite... disabled"

# Script Studio
flags_script = getFlags(env, 'script', 0)
if int(flags_script):
	if 'win' in platform:
		env.Append(LIBS = 'QtScript4')
	elif platform == 'linux':
		env.Append(LIBS = 'QtScript')
	elif platform == 'osx':
		#XXX put in logic here to add a -framework QtScript
		#env.Append(
		pass
	print "MixxxScript Studio... enabled"

	build_flags += 'script '
	sources += Split("""script/scriptengine.cpp script/scriptcontrolqueue.cpp
			script/scriptstudio.cpp script/scriptrecorder.cpp
			script/playinterface.cpp script/macro.cpp
			script/scriptcontrolevent.cpp script/trackcontrolevent.cpp
			script/numbercontrolevent.cpp script/numberrecorder.cpp
			script/macrolist.cpp script/trackrecorder.cpp
			script/sdatetime.cpp script/signalrecorder.cpp
			script/macrolistitem.cpp script/qtscriptinterface.cpp""")
	env.Append(CPPPATH = '$QTDIR/include/QtScript')
	env.Append(CPPDEFINES = '__SCRIPT__')
	
	env.Uic4('script/scriptstudio.ui')
else:
	flags_script = 0
	print "MixxxScript Studio... disabled"

# MIDI Scripting
flags_midiscript = getFlags(env, 'midiscript', 0)
if int(flags_midiscript):
	if 'win' in platform:
		env.Append(LIBS = 'QtScript4')
	elif platform == 'linux':
		env.Append(LIBS = 'QtScript')
	elif platform == 'osx':
		#XXX put in logic here to add a -framework QtScript
		#env.Append(
		pass
	print "MIDI Scripting... enabled"

	build_flags += 'midiscript '
	sources += Split("""script/midiscriptengine.cpp""")
	env.Append(CPPPATH = '$QTDIR/include/QtScript')
	env.Append(CPPDEFINES = '__MIDISCRIPT__')
else:
	flags_midiscript = 0
	print "MIDI Scripting... disabled"

#Optimization
flags_optimize = getFlags(env, 'optimize', 1)
if int(flags_optimize):
	if 'win' in platform:
		if platform == 'win64':
			env.Append(LINKFLAGS = '/MACHINE:X64')
		if int(flags_msvcdebug):
			print "Optimizations... DISABLED DUE TO DEBUG"
		else:
			print "Optimizations... enabled"
			env.Append(CXXFLAGS = '/O2 /GL')
			env.Append(LINKFLAGS = '/LTCG:STATUS')
			if platform == 'win64':	# In addition
				if 'makerelease' in COMMAND_LINE_TARGETS:
					# env.Append(CXXFLAGS = '/Ox /favor:blend /MP')
					# AMD64 architecture is used by all consumer 64-bit CPUs, even Intel ones.
					# IA64 is the Itanium processors, which we don't expect anyone to be using for DJing. :)
					env.Append(CXXFLAGS = '/Ox /favor:AMD64 /MP')
				else:
					env.Append(CXXFLAGS = '/Ox /favor:' + machine + ' /MP')
	else:
		print "Optimizations... enabled"
		build_flags += 'optimize=' + str(flags_optimize) + ' '
		env.Replace(CFLAGS = '') # replace CFLAGS and CXXFLAGS with our own optimizations.
		if flags_optimize=='1':
			env.Replace(CXXFLAGS = '-O3')
		elif flags_optimize=='2':
			print "  P4 MMX/SSE optimizations enabled."
			env.Replace(CXXFLAGS = '-O3 -march=pentium4 -mmmx -msse2 -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		elif flags_optimize=='3':
			print "  Intel Core Solo/Duo optimizations enabled."
			env.Replace(CXXFLAGS = '-O3 -march=prescott -mmmx -msse3 -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		elif flags_optimize=='4':
			print "  Intel Core 2 optimizations enabled."
			env.Replace(CXXFLAGS = '-O3 -march=nocona -mmmx -msse3 -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		elif flags_optimize=='5':
			print "  Athlon 3dnow/SSE optimizations enabled (Athlon-4/XP/MP)."
			env.Replace(CXXFLAGS = '-O3 -march=athlon-4 -mmmx -msse -m3dnow -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		elif flags_optimize=='6':
			print "  Athlon 3dnow/SSE/SSE2 optimizations enabled (K8/Opteron/AMD64)."
			env.Replace(CXXFLAGS = '-O3 -march=k8 -mmmx -msse2 -m3dnow -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		elif flags_optimize=='7':
			print "  Athlon 3dnow/SSE/SSE2/SSE3 optimizations enabled (K8/Opteron/AMD64 w/ SSE3)."
			env.Replace(CXXFLAGS = '-O3 -march=k8-sse3 -mmmx -msse2 -msse3 -m3dnow -mfpmath=sse -fomit-frame-pointer -ffast-math -funroll-loops')
		env.Append(CXXFLAGS = ' ') # add a space to the end of CXXFLAGS
else:
	print "Optimizations... disabled"

# SoundTouch Optimizations -- turn them on only if we have SSE or MMX
# enabled. It's dumb that they appear here, but they make the most sense next to
# the optimization stuff. It's safe to assume that if opt > 1, then MMX and SSE
# are enabled.
if int(flags_optimize) > 1:
    sources += Split("""#lib/soundtouch-1.4.1/mmx_optimized.cpp #lib/soundtouch-1.4.1/sse_optimized.cpp""")
    env.Append(CPPDEFINES='ALLOW_X86_OPTIMIZATIONS')
    
# Enable SoundTouch Windows 3dNow optimizations if we're on AMD
if 'win' in platform and int(flags_optimize) in (5,6,7):
    sources += Split("""#lib/soundtouch-1.4.1/3dnow_win.cpp""")


# Profiling and Optimization
if not 'win' in platform:
	flags_gprof = getFlags(env, 'gprof', 0)
	if int(flags_gprof):
		env.Append(CCFLAGS = '-pg')
		env.Append(LINKFLAGS = '-pg')
		print "gprof profiling support... enabled"
		build_flags += 'gprof '
	else:
		print "gprof profiling support... disabled"
	flags_tuned = getFlags(env, 'tuned', 0)
	if int(flags_tuned):
		ccv = env['CCVERSION'].split('.')
		if int(ccv[0]) >= 4 and int(ccv[1]) >= 2:
			env.Append(CCFLAGS = '-march=native')
			env.Append(LINKFLAGS = '-march=native')
			print "Optimizing for this CPU... yes"
			build_flags += 'tuned '
		else:
			print "Optimizing for this CPU... no (requires gcc >= 4.2.0)"
	else:
		print "Optimizing for this CPU... no"

#Debugging output
flags_qdebug = getFlags(env, 'qdebug', 0)
if 'win' in platform:
	if int(flags_msvcdebug):
		flags_qdebug = 1		# Turn general debugging flag on too if msvcdebug is specified

if int(flags_qdebug):
	build_flags += 'qdebug '
	print "Debugging message output... enabled"
else:
	env.Append(CPPDEFINES = 'QT_NO_DEBUG_OUTPUT')
	print "Debugging message output... disabled"

#ALSA API selection
if platform == 'linux':
	flags_rawmidi = getFlags(env, 'rawmidi', 0)
	if int(flags_rawmidi):
		build_flags += 'rawmidi '
		sources += Split("""midiobjectalsa.cpp """)  #ALSA RawMIDI support for Linux
		env.Append(CPPDEFINES = '__ALSAMIDI__')
		print "ALSA API... RawMIDI"
	else:
		sources += Split("""midiobjectalsaseq.cpp """)  #ALSA Sequencer MIDI support for Linux
		env.Append(CPPDEFINES = '__ALSASEQMIDI__')
		print "ALSA API... Sequencer"

#Visual Studio 2005 hacks (MSVS Express Edition users shouldn't enable this)
flags_msvshacks = getFlags(env, 'msvshacks', 0)
if int(flags_msvshacks):
	env.Append(CPPDEFINES = '__MSVS2005__')
	print "MSVS 2005 hacks... enabled"
	build_flags += 'msvshacks '
else:
	print "MSVS 2005 hacks... disabled"

#force 32-bit compile on GCC
flags_force32 = getFlags(env, 'force32', 0)
if int(flags_force32):
	env.Append(CCFLAGS = '-m32')
	env.Append(CXXFLAGS = '-m32')
	print "Force 32-bit GCC compile... enabled"
else:
	print "Force 32-bit GCC compile... disabled"


#Case Metrics
if 'win' in platform or platform == 'linux':
	flags_cmetrics = getFlags(env, 'cmetrics', 1)
else:
	flags_cmetrics = getFlags(env, 'cmetrics', 0) # Off on OS X for now...
if int(flags_cmetrics):
	env.Append(CPPDEFINES = '__C_METRICS__')
	if 'win' in platform:
		env.Append(LIBS = 'cmetrics')
	else:
		client = 'MIXXX'
		server = 'metrics.mixxx.org' # mixxx metrics collector
		Export('env platform client server flags_force32')
		env.Append(CPPPATH='#lib/cmetrics')
		sources += SConscript('#lib/cmetrics/SConscript')
	print "Case Metrics profiling... enabled"
	build_flags += 'cmetrics '
else:
	print "Case Metrics profiling... disabled"

#env.Append(CPPDEFINES=[('BUILD_FLAGS', "'%s'" % build_flags)])

### Put flags info into a file
f = open("build.h","a")
try:
	f.write('#define BUILD_FLAGS "' + build_flags + '"\n')
finally:
	f.close()
	
# Print the build flags (useful if the flags have been cached, ie. if you just run "scons"
# and want to see the flags that you used last time)
print "================"
print "Building with flags: " + build_flags
print "================\n"

#Save the options to cache
vars.Save(cachefile, env)

#Tell SCons to build Mixxx
#=========================
if 'win' in platform:
	mixxx_bin = env.Program('mixxx', sources, LINKCOM  = [env['LINKCOM'], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'])
else:
	mixxx_bin = env.Program('mixxx', sources)

#Tell SCons to build tests
if int(flags_test):
	print "Building tests."
	build_tests()

if 'test' in BUILD_TARGETS:
	print "Running tests."
	run_tests()

#Set up the MSVC target to build a Visual Studio project/solution file
if 'msvc' in COMMAND_LINE_TARGETS:
	includes = map(str, Glob('#src/*.h'))
	includes += map(str, Glob('#src/visual/*.h'))
	#Make the project file aware of any command-line arguments that were passed...
	cmdargs = ""
	for k in SCons.Script.ARGUMENTS:
		cmdargs += " " + k + "=" + SCons.Script.ARGUMENTS[k]
	env.Append(MSVSSCONSFLAGS = cmdargs)
	#env.Append(MSVSSCONSFLAGS = ' qtdir=' + flags_qtdir)

	# This is the right way to do it but scons is stupid and doesn't copy flags in... Adam
	# Set up environment for debug target
	# TODO Handle lib versions ie /MDd /Md etc...
	#debugenv = env.Clone()
	#debugenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:dist/mixxx.pdb']) # Generate MS VC Program Debug Database
	#debugenv.Append(CXXFLAGS = '/ZI')

	msvc = env.MSVSProject(target = 'mixxx' + env['MSVSPROJECTSUFFIX'], srcs = sources, incs = includes, variant = 'Debug', runfile = '../dist/mixxx')

	# Reenable this once bug in scons is fixed...
	#msvc = env.MSVSProject(target = 'mixxx' + env['MSVSPROJECTSUFFIX'], srcs = sources, incs = includes, variant = 'Release', runfile = '../dist/mixxx')

	env.Alias('msvc', msvc)

#Set up the install target
#=========================
"""
flags_prefix = ARGUMENTS.get('prefix', '/usr/local')
if not os.path.exists(flags_prefix):
	print "Error: Prefix path does not exist!"
	Exit(1)
else:
	unix_share_path = flags_prefix + "/share"
	unix_bin_path   = flags_prefix + "/bin"
"""

#Mixxx binary
binary_files = mixxx_bin;

#Skins
skin_files = Glob('#res/skins/*')

#MIDI mappings
midimappings_files = Glob('#res/midi/*')

#Keyboard mapping(s)
keyboardmappings_files = Glob('#res/keyboard/*')

#Promo tracks
promotracks_files = Glob('#promo/*')

#LADSPA shizzle
ladspapresets_files = Glob('#res/ladspa_presets/*')

#Documentation
docs_files = Glob('#LICENSE')
docs_files += Glob('#README')
docs_files += Glob('#Mixxx-Manual.pdf')

#.desktop file for KDE/GNOME menu
dotdesktop_files = Glob('#src/mixxx.desktop') #XXX why is this in images/?

#Icon file for menu entry
icon_files = Glob('#res/images/mixxx-icon.png')

#Images for preferences dialog
image_files = Glob('#res/images/preferences/*')  # These are compiled in to the "mixxx" binary through mixxx.qrc

#Windows DLLs
if platform == 'win64':
	dll_files = Glob('#/../mixxx-win64lib/[!"msvc"]*.dll') # TODO: Use reference to SharedLibrary for libsndfile and others, glob only gets all files on 2+ builds after a clean.
else:
	dll_files = Glob('#/../mixxx-winlib/[!"msvc"]*.dll') # TODO: Use reference to SharedLibrary for libsndfile and others, glob only gets all files on 2+ builds after a clean.
# dll_files = libsndfile
dll_files += Split("""$QTDIR/lib/Qt3Support4.dll $QTDIR/lib/QtCore4.dll $QTDIR/lib/QtGui4.dll $QTDIR/lib/QtNetwork4.dll $QTDIR/lib/QtOpenGL4.dll $QTDIR/lib/QtSql4.dll $QTDIR/lib/QtXml4.dll $QTDIR/lib/QtSVG4.dll""")

if int(flags_script):
	dll_files += Split("""$QTDIR/lib/QtScript4.dll""")
if int(flags_midiscript):
	dll_files += Split("""$QTDIR/lib/QtScript4.dll""")

if platform in ('linux', 'bsd'):
	flags_prefix = ARGUMENTS.get('prefix', '/usr/local')
	if not os.path.exists(flags_prefix):
		print "Error: Prefix path does not exist!"
		Exit(1)
	else:
		#install_root is used in Debian/Ubuntu packaging (check the debian/rules file in the Ubuntu package)
		#Basically, the flags_prefix is compiled into strings in Mixxx, whereas the install_root is not. When you're
		#building a Debian package, pbuilder wants to install Mixxx to a temporary directory, but you still need
		#the compiled-in strings using /usr as the prefix. That's why we have install_root and flags_prefix.
		install_root = ARGUMENTS.get('install_root', flags_prefix)
		print "Install root: " + install_root
		if install_root != flags_prefix:
			unix_share_path = install_root + "/share"
			unix_bin_path   = install_root + "/bin"			
		else:
			unix_share_path = flags_prefix + "/share"
			unix_bin_path   = flags_prefix + "/bin"

		binary = env.Install(unix_bin_path, binary_files)
		skins = env.Install(unix_share_path + "/mixxx/skins", skin_files)
		midimappings = env.Install(unix_share_path + "/mixxx/midi", midimappings_files)
		keyboardmappings = env.Install(unix_share_path + "/mixxx/keyboard", keyboardmappings_files)
		ladspapresets = env.Install(unix_share_path + "/mixxx/ladspa_presets", ladspapresets_files)
		dotdesktop = env.Install(unix_share_path + "/applications", dotdesktop_files)
		docs = env.Install(unix_share_path + "/doc/mixxx", docs_files)
		icon = env.Install(unix_share_path + "/pixmaps", icon_files)
		promotracks = env.Install(unix_share_path + "/mixxx/promo", promotracks_files)

		#Makes each of those Install builders get fired off when you run "scons install" :)
		env.Alias('install', binary)
		env.Alias('install', skins)
		env.Alias('install', midimappings)
		env.Alias('install', keyboardmappings)
		env.Alias('install', ladspapresets)
		env.Alias('install', docs)
		env.Alias('install', dotdesktop)
		env.Alias('install', icon)
		env.Alias('install', promotracks)
		
		#Delete the old Mixxx installation (because SCONS won't overwrite it)
		#if 'install' in COMMAND_LINE_TARGETS:
			#os.system('scons -c install')
			#Delete(unix_share_path + "/mixxx/skins")
			#print "Copying skins..."
			#env.Command(unix_share_path + "/mixxx/skins", skin_files, Copy("$TARGET", "$SOURCE"), source_scanner = DirScanner)
			#Copy(unix_share_path + "/.ixxx/skins", skin_files)
			#Delete(unix_bin_path + "mixxx")
			
			#Delete(unix_share_path + "/mixxx/midi")
			#Delete(unix_share_path + "/mixxx/keyboard")

#Build the Mixxx.app bundle
if platform == 'osx':
	#Mixxx build variables
	VOLNAME="Mixxx" #tmp tmp tmp, it's unclean to pass this into build_dmg this way. perhaps pass it in the env?
	ARCH="macintel" #XXX should get this from scons or the system somehow?
	DMG_ICON="#res/osx/VolumeIcon.icns"
	
	#this is a BIG HACK to support Qt's plugins (since Qt *requires* that it's plugins be in specific subdirectories, which OS X doesn't really play nice with)
	qt_plugins = [("iconengines", e) for e in ["libqsvgicon.dylib"]] + \
			 [("imageformats", e) for e in ["libqgif.dylib", "libqjpeg.dylib", "libqsvg.dylib"]] #Left out libqmng and libqtiff to save space.
	
	bundle = env.App("Mixxx", [mixxx_bin, '#res/osx/application.icns',
		Dir('#res/skins/'),
		Dir('#res/midi/'), Dir('#res/keyboard/'),
		Dir('#res/ladspa_presets'), Dir('#res/doc/'), Dir('#res/promo/')],
		 PLUGINS=plugins, ##XXX test what happens if we don't pass any plugins
			#Qt plugins ((Qt *NEEDS* its plugins in specific locations or it refuses to find them, however this is clearly awkward to write out like this.. maybe))
		 QT_HACK = [(p_tgt_dir, os.path.join("/Developer/Applications/Qt/plugins/", p_tgt_dir, p)) for p_tgt_dir, p in qt_plugins] #sigh :(
		 ,
		 STRIP=True,
		 #STRIP=(type == 'RELEASE')
		 )
	#env.Default(mixxx_bin) #todo: make the Default() just the program itself *globally* (not just for OS X); bundle should be a separate target
	env.Alias('bundle', bundle)
	dmg = env.Dmg('Mixxx-'+env['MIXXX_VERSION']+'-'+ARCH, [bundle, ] + docs_files, VOLNAME=VOLNAME, ICON = DMG_ICON)
	env.Alias('package', dmg)
		
if 'win' in platform:
	skins = env.Install("#dist/skins", skin_files)
	midimappings = env.Install("#dist/midi", midimappings_files)
	keyboardmappings = env.Install("#dist/keyboard", keyboardmappings_files)
	ladspapresets = env.Install("#dist/ladspa_presets", ladspapresets_files)
	docs = env.Install("#dist/doc/", docs_files)
	promotracks = env.Install("#dist/promo/", promotracks_files)
	#icon = env.Install("#dist", icon_files)
	dlls = env.Install("#dist/", dll_files)
	binary = env.Install("#dist/", binary_files)

	#Always trigger these install builders when compiling on Windows
	env.Alias('mixxx', skins)
	env.Alias('mixxx', midimappings)
	env.Alias('mixxx', keyboardmappings)
	env.Alias('mixxx', ladspapresets)
	env.Alias('mixxx', promotracks)
	env.Alias('mixxx', docs)
	env.Alias('mixxx', dlls)
	#env.Alias('mixxx', icon)
	env.Alias('mixxx', binary)

	def cleanSVNDirsFromDist():
		if os.path.exists("dist"):
			print "Cleaning .svn directories from dist... ",
			os.system('cmd.exe /c @FOR /F "tokens=*" %D IN (\'dir /b /ad /s dist\*.svn*\') do @(rd /s /q "%D") 2> NUL')
			print "Done."
	import atexit
	atexit.register(cleanSVNDirsFromDist)
	
def BuildRelease(target, source, env):
	print
	print "==== Mixxx Post-Build Checks ===="
	print
	print "You have built version ", env['MIXXX_VERSION']
	print
	if int(flags_msvcdebug):
		print "YOU ARE ABOUT TO PACKAGE A DEBUG BUILD!!"
		print
	print "Binary has size ",
	os.system('ls -lh dist/mixxx.exe | cut -d \' \' -f 5')
	print
	print "Installer file ",
	os.system('grep OutFile Mixxx.nsi | cut -d \' \' -f 2')
	print
	print "Top line of README, check version:"
	os.system('head -n 1 README')
	print
	print "Top 2 lines of LICENSE, check version and copyright dates:"
	os.system('head -n 2 LICENSE')
	print
	print "More checks here soon... :)"
	print

	if (raw_input("Go ahead and build installer (yes/[no])? ") == "yes"):
		print "\nNow building installer..."
		
		buildwin64 = ""
		type(buildwin64) == str
		
		# Windows registry access to find where NSIS is installed
		import _winreg
		hklm = _winreg.ConnectRegistry( None, _winreg.HKEY_LOCAL_MACHINE )
		nsis_location_handle = ""
		try:
			nsis_location_handle = _winreg.OpenKey(hklm, "SOFTWARE\\NSIS", 0, _winreg.KEY_READ)
		except WindowsError:
			nsis_location_handle = None
		
		if not nsis_location_handle:
			try:
				nsis_location_handle = _winreg.OpenKey(hklm, "SOFTWARE\\Wow6432Node\\NSIS", 0, _winreg.KEY_READ)
			except WindowsError:
				nsis_location_handle = None

		if not nsis_location_handle:
			print "Cannot find NSIS. Do you have it installed?"
		else:
			if platform == 'win64':
				buildwin64 = "/Dx64=1"
			nsis_location = _winreg.QueryValue(nsis_location_handle, None)
			_winreg.CloseKey(hklm)
		
			# Call the NSIS build
			command = '\"%(path)s\\makensis.exe\" /DPRODUCT_VERSION=%(version)s %(64bit)s Mixxx.nsi' % {'path':nsis_location, \
'version':env['MIXXX_VERSION'], '64bit':buildwin64}
			type(command) == str
			print "Using command:" + command
			os.system(command)
	else:
		print "Aborted building installer"

# Do release things
versionbld = Builder(action = BuildRelease, suffix = '.foo', src_suffix = '.bar')
env.Append(BUILDERS = {'BuildRelease' : versionbld})

if 'makerelease' in COMMAND_LINE_TARGETS:
	makerelease = env.BuildRelease('', binary_files)
	env.Alias('makerelease', makerelease)
	
#Build the Ubuntu package
def BuildUbuntuPackage(target, source, env):
	print
	print "==== Mixxx Post-Build Checks ===="
	print
	print "You have built version ", env['MIXXX_VERSION']
	print
	print
	print "Top line of README, check version:"
	os.system('head -n 1 README')
	print
	print "Top 2 lines of LICENSE, check version and copyright dates:"
	os.system('head -n 2 LICENSE')
	print
	print "Top line of debian/ubuntu changelog, check version:"
	os.system('head -n 1 build/debian/changelog')
	print

	if ("yes" == "yes"):
		print "Now building DEB package..."
		print
		mixxx_dir = 'mixxx-' + env['MIXXX_VERSION']
		mixxx_tarball = 'mixxx_' + env['MIXXX_VERSION'] + '.orig.tar.gz' #The underscore is super important here to make the deb package work
		
		if not os.path.exists('ubuntu'):
			os.mkdir('ubuntu')

		if os.path.exists('ubuntu/'+mixxx_dir):
			print "* Cleaning up ubuntu/"+mixxx_dir + " (cwd: " + os.getcwd() + ")"
			print
			os.system('rm -rf ubuntu/'+mixxx_dir)

		# TODO: make a get flags arg to accept a revision which can override this and checkout of a specific SVN rev for the package

		# Export the source folder
		print "* Exporting source folder from current workspace (bzr rev: " + getBZRRevision() + ")"
		print
		os.system('bzr export ubuntu/'+mixxx_dir + ' .')

		# Copy a patch to be included in the exported build sources (this can also be something like src/SConscript, /build/debian/rules)
		if os.path.exists('post-export-patch'):
			print "* Applying post export patch"
			print
			os.system('cp --dereference -r post-export-patch/* ubuntu/'+mixxx_dir)

		os.chdir('ubuntu')
		# Tar the source code
		print "* Tarring source directory to "+ os.getcwd() +"/mixxx_" + env['MIXXX_VERSION'] + ".orig.tar.gz ... (this can take a couple minutes)"
		print
		os.system("rm -f mixxx_" + env['MIXXX_VERSION'] + ".orig.tar.gz") #Remove old tarball
		os.system('tar --exclude=debian --exclude=debian/* -czf  mixxx_' + env['MIXXX_VERSION'] + '.orig.tar.gz ' + mixxx_dir)

		os.chdir(mixxx_dir)
		# Copy the debian folder from /build/debian to exported source folder root
		print "* Copying Debian build directory from build/debian to debian (cwd: " + os.getcwd() + ")"
		print
		os.system('cp -r build/debian .')
		
		#Run pbuilder
		print "* Starting pbuilder ...  (cwd: " + os.getcwd() + ")"
		print
		os.system('pdebuild')

		# Return back to the starting directory, otherwise you'll get a .sconsign.dblite error!
		os.chdir('../..')
		print "* Returning to starting working directory ...  (cwd: " + os.getcwd() + ")"
		print
		
		#/var/cache/pbuilder/result
		print
		# print "Signing the .deb changes file..."
		# os.system('sudo debsign /var/cache/pbuilder/result/*.changes')
		
		print "Done! Package and tarballs are in /var/cache/pbuilder/result"
		
	else:
		print "Aborted building installer"

#Build the Ubuntu package if "makeubuntu" was passed as an argument
versiondebbld = Builder(action = BuildUbuntuPackage, suffix = '.foo', src_suffix = '.bar')
env.Append(BUILDERS = {'BuildUbuntuPackage' : versiondebbld})

if 'makeubuntu' in COMMAND_LINE_TARGETS:
	makeubuntu = env.BuildUbuntuPackage('', binary_files)
	env.Alias('makeubuntu', makeubuntu)
