import sys, os
sys.path.append(Dir("BuildTools/SCons").abspath)
import SCons.SConf
################################################################################
# Build variables
################################################################################
vars = Variables(os.path.join(Dir("#").abspath, "config.py"))
vars.Add('ccflags', "Extra C(++) compiler flags")
vars.Add('linkflags', "Extra linker flags")
vars.Add(EnumVariable("test", "Compile and run tests", "none", ["none", "all", "unit", "system"]))
vars.Add(BoolVariable("optimize", "Compile with optimizations turned on", "no"))
vars.Add(BoolVariable("debug", "Compile with debug information", "yes" if os.name != "nt" else "no"))
vars.Add(BoolVariable("warnings", "Compile with warnings turned on",
"yes" if os.name != "nt" else "no"))
vars.Add(BoolVariable("max_jobs", "Build with maximum number of parallel jobs", "no"))
vars.Add(EnumVariable("target", "Choose a target platform for compilation", "native", ["native", "iphone-simulator", "iphone-device"]))
if os.name != "nt" :
vars.Add(BoolVariable("coverage", "Compile with coverage information", "no"))
if os.name == "posix" :
vars.Add(BoolVariable("valgrind", "Run tests with valgrind", "no"))
if os.name == "mac" or (os.name == "posix" and os.uname()[0] == "Darwin"):
vars.Add(BoolVariable("universal", "Create universal binaries", "no"))
vars.Add(BoolVariable("mac105", "Link against the 10.5 frameworks", "no"))
if os.name == "nt" :
vars.Add(PathVariable("vcredist", "MSVC redistributable dir", "", PathVariable.PathAccept))
if os.name == "nt" :
vars.Add(PackageVariable("bonjour", "Bonjour SDK location", "yes"))
vars.Add(PackageVariable("openssl", "OpenSSL location", "yes"))
vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept))
vars.Add(PathVariable("docbook_xml", "DocBook XML", None, PathVariable.PathAccept))
vars.Add(PathVariable("docbook_xsl", "DocBook XSL", None, PathVariable.PathAccept))
################################################################################
# Set up default build & configure environment
################################################################################
env = Environment(CPPPATH = "#", ENV = {'PATH' : os.environ['PATH'], 'LD_LIBRARY_PATH' : os.environ.get("LD_LIBRARY_PATH","")}, variables = vars)
Help(vars.GenerateHelpText(env))
# Default custom tools
env.Tool("Test", toolpath = ["#/BuildTools/SCons/Tools"])
env.Tool("WriteVal", toolpath = ["#/BuildTools/SCons/Tools"])
env.Tool("BuildVersion", toolpath = ["#/BuildTools/SCons/Tools"])
if env["PLATFORM"] == "darwin" :
env.Tool("Nib", toolpath = ["#/BuildTools/SCons/Tools"])
env.Tool("AppBundle", toolpath = ["#/BuildTools/SCons/Tools"])
if env["PLATFORM"] == "win32" :
env.Tool("WindowsBundle", toolpath = ["#/BuildTools/SCons/Tools"])
#So we don't need to escalate with UAC
if "TMP" is os.environ.keys() :
env['ENV']['TMP'] = os.environ['TMP']
# Override SConscript to handle tests
oldSConscript = SConscript
def SConscript(*arguments, **keywords) :
if not keywords.get("test_only", False) or env["TEST"] :
return apply(oldSConscript, arguments, keywords)
# Max out the number of jobs
if env["max_jobs"] :
try :
import multiprocessing
SetOption("num_jobs", multiprocessing.cpu_count())
except NotImplementedError :
pass
# Default compiler flags
env["CCFLAGS"] = env.get("ccflags", [])
env["LINKFLAGS"] = env.get("linkflags", [])
if env["optimize"] :
env.Append(CCFLAGS = "-O2")
if env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["GL"])
env.Append(LINKFLAGS = ["/INCREMENTAL:NO", "/LTCG"])
if env["debug"] :
if env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/Zi", "/MDd"])
env.Append(LINKFLAGS = ["/DEBUG"])
else :
env.Append(CCFLAGS = "-g")
elif env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/MD"])
if env.get("universal", 0) :
assert(env["PLATFORM"] == "darwin")
env.Append(CCFLAGS = [
"-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk",
"-arch", "i386",
"-arch", "ppc"])
env.Append(LINKFLAGS = [
"-mmacosx-version-min=10.4",
"-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk",
"-arch", "i386",
"-arch", "ppc"])
if env.get("mac105", 0) :
assert(env["PLATFORM"] == "darwin")
env.Append(CCFLAGS = [
"-isysroot", "/Developer/SDKs/MacOSX10.5.sdk",
"-arch", "i386"])
env.Append(LINKFLAGS = [
"-mmacosx-version-min=10.5",
"-isysroot", "/Developer/SDKs/MacOSX10.5.sdk",
"-arch", "i386"])
if env["warnings"] :
if env["PLATFORM"] == "win32" :
env.Append(CCFLAGS = ["/Wall"])
else :
env.Append(CXXFLAGS = ["-Wextra", "-Wall", "-Wnon-virtual-dtor", "-Wundef", "-Wold-style-cast", "-Wno-long-long", "-Woverloaded-virtual", "-Wfloat-equal", "-Wredundant-decls"])
gccVersion = env["CCVERSION"].split(".")
if gccVersion >= ["4", "5", "0"] :
env.Append(CCFLAGS = ["-Wlogical-op"])
if env.get("coverage", 0) :
assert(env["PLATFORM"] != "win32")
env.Append(CCFLAGS = ["-fprofile-arcs", "-ftest-coverage"])
env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"])
if env["PLATFORM"] == "win32" :
env.Append(LIBS = ["user32", "dnsapi", "ws2_32", "wsock32"])
env.Append(CCFLAGS = ["/EHsc", "/nologo"])
# FIXME: We should find a decent solution for MSVS 10
if int(env["MSVS_VERSION"].split(".")[0]) < 10 :
env["LINKCOM"] = [env["LINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1']
env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
if env["PLATFORM"] == "darwin" :
env.Append(FRAMEWORKS = ["IOKit", "AppKit"])
# Testing
env["TEST_TYPE"] = env["test"]
if "check" in ARGUMENTS :
env["TEST_TYPE"] = "unit"
env["TEST"] = (env["TEST_TYPE"] != "none") or env.GetOption("clean")
if env.get("valgrind", 0) :
env["TEST_RUNNER"] = "valgrind --suppressions=QA/valgrind.supp -q --leak-check=full --track-origins=yes "
# Packaging
env["DIST"] = "dist" in ARGUMENTS or env.GetOption("clean")
if ARGUMENTS.get("SWIFT_INSTALLDIR", "") :
env["SWIFT_INSTALLDIR"] = Dir(ARGUMENTS["SWIFT_INSTALLDIR"]).abspath
# cross-compiling
target = env["target"]
if target in ("iphone-device", "iphone-simulator"):
if target == "iphone-device":
sdkPart = "iPhoneOS"
env["CC"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/arm-apple-darwin9-gcc-4.0.1"
env["CXX"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/arm-apple-darwin9-g++-4.0.1"
env["PATH"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/"
env["LD"] = env["CC"]
# env["openssl"] = "#/3rdParty/openssl-0.9.8l-arm"
targetIncludesArch = "arm"
if target == "iphone-simulator":
sdkPart = "iPhoneSimulator"
env.Append(CCFLAGS = ["-arch", "i386"])
env.Append(LINKFLAGS = ["-arch", "i386"])
targetIncludesArch = "i686"
sdkVer = "3.0"
sdk = "/Developer/Platforms/" + sdkPart + ".platform/Developer/SDKs/" + sdkPart + sdkVer + ".sdk"
env["FRAMEWORKS"] = ["CoreFoundation", "Foundation", "UIKit", "CoreGraphics"]
env.Append(LINKFLAGS = ["-L\"" + sdk + "/usr/lib\"", "-F\"" + sdk + "/System/Library/Frameworks\"", "-F\"" + sdk + "/System/Library/PrivateFrameworks\""])
env["CPPPATH"] = ["/Users/kismith/devel/swift/iPhone/Swiftly/swift/", "/Developer/Platforms/" + sdkPart + ".platform/Developer/usr/lib/gcc/" + targetIncludesArch + "-apple-darwin9/4.0.1/include/", sdk + "/usr/include", sdk + "/usr/include/c++/4.0.0/" + targetIncludesArch + "-apple-darwin9", sdk + "/usr/include/c++/4.0.0", "/Developer/Platforms/" + sdkPart + ".platform/Developer/usr/include/"]
# end cross compiling stuff
conf_env = env.Clone()
Export("env")
Export("conf_env")
################################################################################
# Extend the default build environment (not affecting the configure env)
#
# Keeping both environments separated mostly because of SCons Issue 2391,
# although it doesn't hurt to separate them (e.g. not have pretty printed
# strings in config.log)
################################################################################
#if env["PLATFORM"] == "win32" :
# env["MSVC_BATCH"] = 1
# Pretty output
def colorize(command, target, color) :
colors = { "red": "31", "green": "32", "yellow": "33", "blue": "34" }
prefix = ""
suffix = ""
if sys.stdout.isatty() and env["PLATFORM"] != "win32":
prefix = "\033[0;" + colors[color] + ";140m"
suffix = "\033[0m"
return " " + prefix + command + suffix + " " + target
if int(ARGUMENTS.get("V", 0)) == 0:
env["CCCOMSTR"] = colorize("CC", "$TARGET", "green")
env["CXXCOMSTR"] = colorize("CXX", "$TARGET", "green")
env["LINKCOMSTR"] = colorize("LINK", "$TARGET", "red")
env["ARCOMSTR"] = colorize("AR", "$TARGET", "red")
env["RANLIBCOMSTR"] = colorize("RANLIB", "$TARGET", "red")
env["QT4_RCCCOMSTR"] = colorize("RCC", "$TARGET", "blue")
env["QT4_UICCOMSTR"] = colorize("UIC", "$TARGET", "blue")
env["QT4_MOCFROMHCOMSTR"] = colorize("MOC", "$TARGET", "blue")
env["QT4_MOCFROMCXXCOMSTR"] = colorize("MOC", "$TARGET", "blue")
env["GENCOMSTR"] = colorize("GEN", "$TARGET", "blue")
env["RCCOMSTR"] = colorize("RC", "$TARGET", "blue")
env["BUNDLECOMSTR"] = colorize("BUNDLE", "$TARGET", "blue")
env["NIBCOMSTR"] = colorize("NIB", "$TARGET", "blue")
env["NSISCOMSTR"] = colorize("NSIS", "$TARGET", "blue")
env["INSTALLSTR"] = colorize("INSTALL", "$TARGET", "blue")
env["TESTCOMSTR"] = colorize("TEST", "$SOURCE", "yellow")
env["FOCOMSTR"] = colorize("FO", "$TARGET", "blue")
env["XSLTCOMSTR"] = colorize("XSLT", "$TARGET", "blue")
env["XMLLINTCOMSTR"] = colorize("XMLLINT", "$SOURCE", "blue")
#Progress(colorize("DEP", "$TARGET", "red")
def checkObjCHeader(context, header) :
context.Message("Checking for Objective-C header " + header + " ... ")
ret = context.TryCompile("#include <Cocoa/Cocoa.h>\n#include <" + header + ">", ".m")
context.Result(ret)
return ret
################################################################################
# Platform configuration
################################################################################
if ARGUMENTS.get("force-configure", 0) :
SCons.SConf.SetCacheMode("force")
conf = Configure(conf_env)
if not conf.CheckCXX() or not conf.CheckCC() :
print "Error: You need a working compiler"
Exit(1)
env["HAVE_ZLIB"] = True
if conf.CheckLib("z") :
env.Append(LIBS = "z")
env["ZLIB_FLAGS"] = ""
else :
env["ZLIB_BUNDLED"] = True
if conf.CheckLib("c") :
env.Append(LIBS = ["c"])
if conf.CheckLib("resolv") :
env.Append(LIBS = ["resolv"])
# Expat
if conf.CheckCHeader("expat.h") and conf.CheckLib("expat") :
env["HAVE_EXPAT"] = 1
env["EXPAT_FLAGS"] = { "LIBS": ["expat"] }
# LibIDN
if conf.CheckCHeader("idna.h") and conf.CheckLib("idn") :
env["LIBIDN_FLAGS"] = { "LIBS": ["idn"] }
else :
env["LIBIDN_BUNDLED"] = 1
# Boost
boostLibs = [("signals", None), ("thread", None), ("regex", None), ("program_options", None), ("filesystem", None), ("system", "system/system_error.hpp"), ("date_time", "date_time/date.hpp")]
allLibsPresent = True
libNames = []
for (lib, header) in boostLibs :
if header :
header = "boost/" + header
else :
header = "boost/" + lib + ".hpp"
if not conf.CheckCXXHeader(header) :
allLibsPresent = False
break
libName = "boost_" + lib
if not conf.CheckLib(libName) :
libName += "-mt"
if not conf.CheckLib(libName) :
allLibsPresent = False
break
libNames.append(libName)
if allLibsPresent :
env["BOOST_FLAGS"] = { "LIBS": libNames }
if not conf.CheckCXXHeader("boost/uuid/uuid.hpp") :
# FIXME: Remove this workaround when UUID is available in most distros
env["BOOST_BUNDLED_UUID_ONLY"] = True
else :
env["BOOST_BUNDLED"] = True
# Avahi
if env["PLATFORM"] != "darwin" :
if conf.CheckCHeader("avahi-client/client.h") and conf.CheckLib("avahi-client") and conf.CheckLib("avahi-common") :
env["HAVE_AVAHI"] = True
env["AVAHI_FLAGS"] = { "LIBS": ["avahi-client", "avahi-common"] }
conf.Finish()
# Xss
env["HAVE_XSS"] = 0
if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
xss_flags = {
"LIBPATH": ["/usr/X11R6/lib"],
"LIBS": ["X11", "Xss"]
}
xss_env = conf_env.Clone()
xss_env.MergeFlags(xss_flags)
conf = Configure(xss_env)
if conf.CheckFunc("XScreenSaverQueryExtension") :
env["HAVE_XSS"] = 1
env["XSS_FLAGS"] = xss_flags
conf.Finish()
# Sparkle
env["HAVE_SPARKLE"] = 0
if env["PLATFORM"] == "darwin" :
sparkle_flags = {
"FRAMEWORKPATH": ["/Library/Frameworks"],
"FRAMEWORKS": ["Sparkle"]
}
sparkle_env = conf_env.Clone()
sparkle_env.MergeFlags(sparkle_flags)
conf = Configure(sparkle_env, custom_tests = { "CheckObjCHeader" : checkObjCHeader })
if conf.CheckObjCHeader("Sparkle/Sparkle.h") :
env["HAVE_SPARKLE"] = 1
env["SPARKLE_FLAGS"] = sparkle_flags
env["SPARKLE_FRAMEWORK"] = "/Library/Frameworks/Sparkle.framework"
conf.Finish()
# LibXML
if not env.get("HAVE_EXPAT", False) :
conf = Configure(conf_env)
if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :
env["HAVE_LIBXML"] = 1
env["LIBXML_FLAGS"] = { "LIBS": ["xml2"] }
conf.Finish()
if not env.get("HAVE_LIBXML", 0) :
libxml_env = conf_env.Clone()
libxml_env.Append(CPPPATH = ["/usr/include/libxml2"])
conf = Configure(libxml_env)
if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") :
env["HAVE_LIBXML"] = 1
env["LIBXML_FLAGS"] = { "CPPPATH": ["/usr/include/libxml2"], "LIBS": ["xml2"] }
conf.Finish()
# Bundled expat
bundledExpat = False
if not env.get("HAVE_EXPAT", 0) :
print "Expat or LibXML not found. Using bundled Expat"
SConscript("#/3rdParty/Expat/SConscript")
env["HAVE_EXPAT"] = 1
env["EXPAT_BUNDLED"] = True
# Qt
if env["qt"] :
env["QTDIR"] = env["qt"]
# OpenSSL
openssl_env = conf_env.Clone()
use_openssl = bool(env["openssl"])
openssl_prefix = env["openssl"] if isinstance(env["openssl"], str) else ""
openssl_flags = {}
if openssl_prefix :
openssl_flags = { "CPPPATH": [os.path.join(openssl_prefix, "include")] }
if env["PLATFORM"] == "win32" :
openssl_flags["LIBPATH"] = [os.path.join(openssl_prefix, "lib", "VC")]
env["OPENSSL_DIR"] = openssl_prefix
else :
openssl_flags["LIBPATH"] = [os.path.join(openssl_prefix, "lib")]
openssl_env.MergeFlags(openssl_flags)
openssl_conf = Configure(openssl_env)
if use_openssl and openssl_conf.CheckCHeader("openssl/ssl.h") :
env["HAVE_OPENSSL"] = 1
env["OPENSSL_FLAGS"] = openssl_flags
if env["PLATFORM"] == "win32" :
env["OPENSSL_FLAGS"]["LIBS"] = ["libeay32MT", "ssleay32MT"]
else:
env["OPENSSL_FLAGS"]["LIBS"] = ["ssl", "crypto"]
else :
env["OPENSSL_FLAGS"] = ""
openssl_conf.Finish()
# Bonjour
if env["PLATFORM"] == "darwin" :
env["HAVE_BONJOUR"] = 1
elif env.get("bonjour", False) :
bonjour_env = conf_env.Clone()
bonjour_conf = Configure(bonjour_env)
bonjour_flags = {}
if env.get("bonjour") != True :
bonjour_prefix = env["bonjour"]
bonjour_flags["CPPPATH"] = [os.path.join(bonjour_prefix, "include")]
bonjour_flags["LIBPATH"] = [os.path.join(bonjour_prefix, "lib", "win32")]
bonjour_env.MergeFlags(bonjour_flags)
if bonjour_conf.CheckCHeader("dns_sd.h") and bonjour_conf.CheckLib("dnssd") :
env["HAVE_BONJOUR"] = 1
env["BONJOUR_FLAGS"] = bonjour_flags
env["BONJOUR_FLAGS"]["LIBS"] = ["dnssd"]
bonjour_conf.Finish()
################################################################################
# DocBook setup
################################################################################
if env.get("docbook_xml") :
env["DOCBOOK_XML_DIR"] = env["docbook_xml"]
if env.get("docbook_xsl") :
env["DOCBOOK_XSL_DIR"] = env["docbook_xsl"]
################################################################################
# Set up git hooks
################################################################################
if env.Dir("#/.git").exists() :
if not env.GetOption("clean") :
env.Install("#/.git/hooks", Glob("#/BuildTools/Git/Hooks/*"))
################################################################################
# Project files
################################################################################
# Modules
modules = []
for dir in os.listdir(Dir("#").abspath) :
full_dir = os.path.join(Dir("#").abspath, dir)
if not os.path.isdir(full_dir) :
continue
sconscript = os.path.join(full_dir, "SConscript")
if os.path.isfile(sconscript) :
modules.append(dir)
for dir in os.listdir(Dir("#/3rdParty").abspath) :
full_dir = os.path.join(Dir("#/3rdParty").abspath, dir)
if not os.path.isdir(full_dir) :
continue
sconscript = os.path.join(full_dir, "SConscript")
if os.path.isfile(sconscript) :
modules.append("3rdParty/" + dir)
# Flags
env["PROJECTS"] = [m for m in modules if m not in ["Documentation", "QA", "SwifTools"] and not m.startswith("3rdParty")]
for stage in ["flags", "build", "test"] :
env["SCONS_STAGE"] = stage
SConscript(dirs = map(lambda x : "#/" + x, modules))
################################################################################
# Print summary
################################################################################
print
print " Build Configuration"
print " -------------------"
parsers = []
if env.get("HAVE_LIBXML", 0):
parsers.append("LibXML")
if env.get("HAVE_EXPAT", 0):
parsers.append("Expat")
if env.get("EXPAT_BUNDLED", False) :
parsers.append("(Bundled)")
print " Projects: " + ' '.join(env["PROJECTS"])
print ""
print " XML Parsers: " + ' '.join(parsers)
print " TLS Support: " + ("OpenSSL" if env.get("HAVE_OPENSSL",0) else "Disabled")
print " DNSSD Support: " + ("Bonjour" if env.get("HAVE_BONJOUR") else ("Avahi" if env.get("HAVE_AVAHI") else "Disabled"))
print