summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'BuildTools')
-rw-r--r--BuildTools/CLang/.gitignore4
-rw-r--r--BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp228
-rw-r--r--BuildTools/CLang/SConscript15
-rwxr-xr-xBuildTools/CheckHeaders.py21
-rwxr-xr-xBuildTools/Copyrighter.py2
-rw-r--r--BuildTools/SCons/SConstruct78
-rw-r--r--BuildTools/SCons/Tools/AppBundle.py14
7 files changed, 353 insertions, 9 deletions
diff --git a/BuildTools/CLang/.gitignore b/BuildTools/CLang/.gitignore
new file mode 100644
index 0000000..df682c0
--- /dev/null
+++ b/BuildTools/CLang/.gitignore
@@ -0,0 +1,4 @@
+CLangDiagnosticsFlags
+CLangDiagnosticsFlagsTool.sh
+CLangDiagnosticsFlagsTool
+clang-diagnostics-overview.*
diff --git a/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp
new file mode 100644
index 0000000..82cc902
--- /dev/null
+++ b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2011 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <iostream>
+#include <set>
+#include <vector>
+#include <cassert>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/topological_sort.hpp>
+#include <boost/graph/graphviz.hpp>
+
+// -----------------------------------------------------------------------------
+// Include diagnostics data from CLang
+// -----------------------------------------------------------------------------
+
+#define DIAG(name, a, b, c, d, e, f, g) name,
+
+namespace diag {
+ enum LexKinds {
+#include <clang/Basic/DiagnosticLexKinds.inc>
+#include <clang/Basic/DiagnosticParseKinds.inc>
+#include <clang/Basic/DiagnosticCommonKinds.inc>
+#include <clang/Basic/DiagnosticDriverKinds.inc>
+#include <clang/Basic/DiagnosticFrontendKinds.inc>
+#include <clang/Basic/DiagnosticSemaKinds.inc>
+ };
+}
+
+#define GET_DIAG_ARRAYS
+#include <clang/Basic/DiagnosticGroups.inc>
+#undef GET_DIAG_ARRAYS
+
+struct DiagTableEntry {
+ const char* name;
+ const short* array;
+ const short* group;
+};
+
+static const DiagTableEntry diagnostics[] = {
+#define GET_DIAG_TABLE
+#include <clang/Basic/DiagnosticGroups.inc>
+#undef GET_DIAG_TABLE
+};
+static const size_t diagnostics_count = sizeof(diagnostics) / sizeof(diagnostics[0]);
+
+// -----------------------------------------------------------------------------
+
+using namespace boost;
+
+struct Properties {
+ Properties() : missing(false), redundant(false) {
+ }
+
+ std::string name;
+ bool have;
+ bool implicitHave;
+ bool dontWant;
+ bool implicitDontWant;
+ bool ignored;
+ bool available;
+ bool missing;
+ bool redundant;
+ bool alreadyCovered;
+};
+
+class GraphVizLabelWriter {
+ public:
+ GraphVizLabelWriter(const std::vector<Properties>& properties) : properties(properties) {
+ }
+
+ template <class VertexOrEdge>
+ void operator()(std::ostream& out, const VertexOrEdge& v) const {
+ std::string color;
+ if (properties[v].missing) {
+ color = "orange";
+ }
+ else if (properties[v].redundant) {
+ color = "lightblue";
+ }
+ else if (properties[v].have) {
+ color = "darkgreen";
+ }
+ else if (properties[v].implicitHave) {
+ color = "green";
+ }
+ else if (properties[v].dontWant) {
+ color = "red";
+ }
+ else if (properties[v].implicitDontWant) {
+ color = "pink";
+ }
+ else if (properties[v].ignored) {
+ color = "white";
+ }
+ else if (properties[v].available) {
+ color = "yellow";
+ }
+ else {
+ assert(false);
+ }
+ out << "[label=" << escape_dot_string(properties[v].name) << " fillcolor=\"" << color << "\" style=filled]";
+ }
+
+ private:
+ const std::vector<Properties> properties;
+};
+
+int main(int argc, char* argv[]) {
+ // Parse command-line arguments
+ std::set<std::string> have;
+ std::set<std::string> dontWant;
+ std::string outputDir;
+ for (int i = 1; i < argc; ++i) {
+ std::string arg(argv[i]);
+ if (starts_with(arg, "-W")) {
+ have.insert(arg.substr(2, arg.npos));
+ }
+ else if (starts_with(arg, "-w")) {
+ dontWant.insert(arg.substr(2, arg.npos));
+ }
+ else if (starts_with(arg, "-O")) {
+ outputDir = arg.substr(2, arg.npos) + "/";
+ }
+ }
+
+ // Build the graph and initialize properties
+ typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
+ typedef graph_traits<Graph>::vertex_descriptor Vertex;
+ Graph g(diagnostics_count);
+ std::vector<Properties> properties(num_vertices(g));
+ for (size_t i = 0; i < diagnostics_count; ++i) {
+ std::string name(diagnostics[i].name);
+ properties[i].name = name;
+ properties[i].implicitHave = properties[i].have = have.find(name) != have.end();
+ properties[i].implicitDontWant = properties[i].dontWant = dontWant.find(name) != dontWant.end();
+ properties[i].ignored = diagnostics[i].group == 0 && diagnostics[i].array == 0;
+ properties[i].alreadyCovered = false;
+ properties[i].available = true;
+ for (const short* j = diagnostics[i].group; j && *j != -1; ++j) {
+ add_edge(i, *j, g);
+ }
+ }
+
+ // Sort the diagnostics
+ std::list<Vertex> sortedDiagnostics;
+ boost::topological_sort(g, std::front_inserter(sortedDiagnostics));
+
+ // Propagate dontWant and have properties down
+ for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
+ graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
+ for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
+ properties[*adjacentIt].implicitDontWant = properties[*i].implicitDontWant || properties[*adjacentIt].implicitDontWant;
+ properties[*adjacentIt].implicitHave = properties[*i].implicitHave || properties[*adjacentIt].implicitHave;
+ }
+ }
+
+ // Propagate 'available' property upwards
+ for(std::list<Vertex>::const_reverse_iterator i = sortedDiagnostics.rbegin(); i != sortedDiagnostics.rend(); ++i) {
+ properties[*i].available = properties[*i].available && !properties[*i].implicitDontWant;
+ graph_traits<Graph>::in_edge_iterator edgesIt, edgesEnd;
+ graph_traits<Graph>::edge_descriptor edge;
+ for (tie(edgesIt, edgesEnd) = in_edges(*i, g); edgesIt != edgesEnd; ++edgesIt) {
+ properties[source(*edgesIt, g)].available = properties[source(*edgesIt, g)].available && properties[*i].available;
+ }
+ }
+
+ // Collect missing & redundant flags
+ std::set<std::string> missing;
+ std::set<std::string> redundant;
+ for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) {
+ bool markChildrenCovered = true;
+ if (properties[*i].alreadyCovered) {
+ if (properties[*i].have) {
+ properties[*i].redundant = true;
+ redundant.insert(properties[*i].name);
+ }
+ }
+ else {
+ if (properties[*i].available) {
+ if (!properties[*i].implicitHave && !properties[*i].ignored) {
+ properties[*i].missing = true;
+ missing.insert(properties[*i].name);
+ }
+ }
+ else {
+ markChildrenCovered = false;
+ }
+ }
+ if (markChildrenCovered) {
+ graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd;
+ for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) {
+ properties[*adjacentIt].alreadyCovered = true;
+ }
+ }
+ }
+
+ // Write information
+ if (!missing.empty()) {
+ std::cout << "Missing diagnostic flags: ";
+ for(std::set<std::string>::const_iterator i = missing.begin(); i != missing.end(); ++i) {
+ std::cout << "-W" << *i << " ";
+ }
+ std::cout<< std::endl;
+ }
+
+ if (!redundant.empty()) {
+ std::cout << "Redundant diagnostic flags: ";
+ for(std::set<std::string>::const_iterator i = redundant.begin(); i != redundant.end(); ++i) {
+ std::cout << "-W" << *i << " ";
+ }
+ std::cout<< std::endl;
+ }
+
+ // Write graphviz file
+ if (!outputDir.empty()) {
+ std::ofstream f((outputDir + "clang-diagnostics-overview.dot").c_str());
+ write_graphviz(f, g, GraphVizLabelWriter(properties));
+ f.close();
+ }
+
+ return 0;
+}
diff --git a/BuildTools/CLang/SConscript b/BuildTools/CLang/SConscript
new file mode 100644
index 0000000..850c35c
--- /dev/null
+++ b/BuildTools/CLang/SConscript
@@ -0,0 +1,15 @@
+Import("env")
+
+#myenv = Environment()
+#myenv.Append(CPPPATH = ["."])
+#myenv.Program("CLangDiagnosticsFlagsTool", ["CLangDiagnosticsFlagsTool.cpp"])
+#
+#disabledDiagnostics = ["-wunreachable-code", "-wunused-macros", "-wmissing-noreturn", "-wlong-long", "-wcast-align", "-wglobal-constructors", "-wmissing-prototypes", "-wpadded", "-wshadow"]
+#clangDiagnosticsFlagsToolCommand = "BuildTools/CLang/CLangDiagnosticsFlagsTool -O" + env.Dir(".").abspath + " " + " ".join(disabledDiagnostics) + " "
+#clangDiagnosticsFlagsToolCommand += " ".join([flag for flag in env["CXXFLAGS"] if flag.startswith("-W")])
+#clangDiagnosticsFlagsToolCommand += "\n"
+#clangDiagnosticsFlagsToolCommand += "dot -Tpng " + env.Dir(".").abspath + "/clang-diagnostics-overview.dot > " + env.Dir(".").abspath + "/clang-diagnostics-overview.png\n"
+#v = env.WriteVal("#/BuildTools/CLang/CLangDiagnosticsFlagsTool.sh", env.Value(clangDiagnosticsFlagsToolCommand))
+#env.AddPostAction(v, Chmod(v[0], 0755))
+#
+#
diff --git a/BuildTools/CheckHeaders.py b/BuildTools/CheckHeaders.py
new file mode 100755
index 0000000..73f49db
--- /dev/null
+++ b/BuildTools/CheckHeaders.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+import os, sys
+
+foundBadHeaders = False
+
+for (path, dirs, files) in os.walk(".") :
+ if "3rdParty" in path or ".sconf" in path or ".framework" in path :
+ continue
+ if not "Swiften" in path :
+ continue
+
+ for filename in [os.path.join(path, file) for file in files if file.endswith(".h")] :
+ file = open(filename, "r")
+ for line in file.readlines() :
+ for include in ["iostream", "algorithm", "cassert", "boost/bind.hpp", "boost/filesystem.hpp", "Base/foreach.h", "Base/Log.h", "boost/date_time/date_time.hpp", "boost/filesystem/filesystem.hpp"] :
+ if "#include" in line and include in line and not "Base/Log" in filename :
+ print "Found " + include + " include in " + filename
+ foundBadHeaders = True
+
+sys.exit(foundBadHeaders)
diff --git a/BuildTools/Copyrighter.py b/BuildTools/Copyrighter.py
index a768f0d..8916316 100755
--- a/BuildTools/Copyrighter.py
+++ b/BuildTools/Copyrighter.py
@@ -136,7 +136,7 @@ elif sys.argv[1] == "check-all-copyrights" :
for (path, dirs, files) in os.walk(".") :
if "3rdParty" in path or ".sconf" in path or "Swift.app" in path :
continue
- for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file] :
+ for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file and not "linit.cpp" in file ] :
ok &= check_copyright(filename)
if not ok :
sys.exit(-1)
diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct
index bc7781b..38cb7cc 100644
--- a/BuildTools/SCons/SConstruct
+++ b/BuildTools/SCons/SConstruct
@@ -42,6 +42,9 @@ vars.Add("expat_libname", "Expat library name", "libexpat" if os.name == "nt" el
vars.Add(PathVariable("libidn_includedir", "LibIDN headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("libidn_libdir", "LibIDN library location", None, PathVariable.PathAccept))
vars.Add("libidn_libname", "LibIDN library name", "libidn" if os.name == "nt" else "idn")
+vars.Add(PathVariable("sqlite_includedir", "SQLite headers location", None, PathVariable.PathAccept))
+vars.Add(PathVariable("sqlite_libdir", "SQLite library location", None, PathVariable.PathAccept))
+vars.Add("sqlite_libname", "SQLite library name", "libsqlite3" if os.name == "nt" else "sqlite3")
vars.Add(PathVariable("avahi_includedir", "Avahi headers location", None, PathVariable.PathAccept))
vars.Add(PathVariable("avahi_libdir", "Avahi library location", None, PathVariable.PathAccept))
vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept))
@@ -90,6 +93,8 @@ if env["max_jobs"] :
SetOption("num_jobs", multiprocessing.cpu_count())
except NotImplementedError :
pass
+ except ImportError :
+ pass
# Default compiler flags
if env.get("distcc", False) :
@@ -178,7 +183,14 @@ else :
env.Append(CXXFLAGS = ["-Werror"])
gccVersion = env["CCVERSION"].split(".")
if gccVersion >= ["4", "5", "0"] :
- env.Append(CCFLAGS = ["-Wlogical-op"])
+ env.Append(CXXFLAGS = ["-Wlogical-op"])
+ if "clang" in env["CC"] :
+ env.Append(CXXFLAGS = ["-W#warnings", "-W-Wc++0x-compat", "-Wc++0x-compat", "-Waddress-of-temporary", "-Wambiguous-member-template", "-Wbind-to-temporary-copy", "-Wbuiltin-macro-redefined", "-Wc++-compat", "-Wc++0x-extensions", "-Wcomments", "-Wconstant-logical-operand", "-Wdeclaration-after-statement", "-Wdeprecated", "-Wempty-body", "-Wendif-labels", "-Wformat=2", "-Wfour-char-constants", "-Wgnu", "-Winvalid-noreturn", "-Winvalid-offsetof", "-Winvalid-token-paste", "-Wlocal-type-template-args", "-Wmethod-signatures", "-Wmicrosoft", "-Wmissing-declarations", "-Wnon-pod-varargs", "-Wnonfragile-abi2", "-Wout-of-line-declaration", "-Woverlength-strings", "-Wpacked", "-Wpointer-arith", "-Wpointer-sign", "-Wprotocol", "-Wreadonly-setter-attrs", "-Wselector", "-Wstrict-selector-match", "-Wsuper-class-method-mismatch", "-Wtautological-compare", "-Wtypedef-redefinition", "-Wundeclared-selector", "-Wunknown-attributes", "-Wunknown-warning-option", "-Wunnamed-type-template-args", "-Wunused-exception-parameter", "-Wunused-member-function", "-Wused-but-marked-unused", "-Wvariadic-macros"])
+# To enable:
+# "-Wheader-hygiene"
+# "-Wnon-gcc",
+# "-Wweak-vtables",
+# "-Wlarge-by-value-copy",
if env.get("coverage", 0) :
assert(env["PLATFORM"] != "win32")
@@ -186,7 +198,7 @@ if env.get("coverage", 0) :
env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"])
if env["PLATFORM"] == "win32" :
- env.Append(LIBS = ["user32", "crypt32", "dnsapi", "ws2_32", "wsock32"])
+ env.Append(LIBS = ["user32", "crypt32", "dnsapi", "ws2_32", "wsock32", "Advapi32"])
env.Append(CCFLAGS = ["/EHsc", "/nologo"])
# FIXME: We should find a decent solution for MSVS 10
if int(env["MSVS_VERSION"].split(".")[0]) < 10 :
@@ -194,7 +206,7 @@ if env["PLATFORM"] == "win32" :
env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2']
if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] :
- env.Append(FRAMEWORKS = ["IOKit", "AppKit"])
+ env.Append(FRAMEWORKS = ["IOKit", "AppKit", "SystemConfiguration"])
# Testing
env["TEST_TYPE"] = env["test"]
@@ -205,6 +217,7 @@ 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 "
env["TEST_IGNORE_RESULT"] = "ignore_test_result" in ARGUMENTS
+env["TEST_CREATE_LIBRARIES"] = "create_test_libraries" in ARGUMENTS
# Packaging
env["DIST"] = "dist" in ARGUMENTS or env.GetOption("clean")
@@ -231,12 +244,12 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] :
# Hard code values
env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin"
if target == "iphone-device":
- env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6"]
+ env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6", "-arch", "armv7"]
sdkPart = "iPhoneOS"
else :
env["XCODE_ARCH_FLAGS"] = ["-arch", "i386"]
sdkPart = "iPhoneSimulator"
- sdkVer = "4.0"
+ sdkVer = "4.3"
env["XCODE_SDKROOT"] = "/Developer/Platforms/" + sdkPart + ".platform/Developer/SDKs/" + sdkPart + sdkVer + ".sdk"
# Set the build flags
@@ -244,7 +257,7 @@ if target in ["iphone-device", "iphone-simulator", "xcode"] :
env["CXX"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/g++"
env["OBJCCFLAGS"] = ["-fobjc-abi-version=2", "-fobjc-legacy-dispatch"]
env["LD"] = env["CC"]
- env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"])
+ env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"] + ["-fvisibility=hidden"])
env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"])
env.Append(CPPFLAGS = ["-isysroot", "$XCODE_SDKROOT"])
env.Append(FRAMEWORKS = ["CoreFoundation", "Foundation", "UIKit", "CoreGraphics"])
@@ -320,6 +333,12 @@ def checkObjCHeader(context, header) :
if ARGUMENTS.get("force-configure", 0) :
SCons.SConf.SetCacheMode("force")
+def CheckPKG(context, name):
+ context.Message( 'Checking for package %s... ' % name )
+ ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0]
+ context.Result( ret )
+ return ret
+
conf = Configure(conf_env)
if not conf.CheckCXX() or not conf.CheckCC() :
@@ -404,7 +423,7 @@ env["HAVE_XSS"] = 0
if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
xss_flags = {
"LIBPATH": ["/usr/X11R6/lib"],
- "LIBS": ["X11", "Xss"]
+ "LIBS": ["Xss"]
}
xss_env = conf_env.Clone()
xss_env.MergeFlags(xss_flags)
@@ -414,6 +433,31 @@ if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
env["XSS_FLAGS"] = xss_flags
conf.Finish()
+# GConf
+env["HAVE_GCONF"] = 0
+if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" :
+ gconf_env = conf_env.Clone()
+ conf = Configure(gconf_env, custom_tests = {"CheckPKG": CheckPKG})
+ if conf.CheckPKG("gconf-2.0") :
+ gconf_bare_env = Environment()
+ gconf_bare_env.ParseConfig('pkg-config --cflags gconf-2.0 --libs gconf-2.0')
+ gconf_flags = {
+ "LIBS": gconf_bare_env["LIBS"],
+ "CCFLAGS": gconf_bare_env["CCFLAGS"],
+ "CPPPATH": gconf_bare_env["CPPPATH"],
+ "CPPDEFINES": gconf_bare_env["CPPDEFINES"],
+ }
+ gconf_env.MergeFlags(gconf_flags)
+ if conf.CheckCHeader("gconf/gconf-client.h") and conf.CheckLib("gconf-2") :
+ env["HAVE_GCONF"] = 1
+ env["GCONF_FLAGS"] = {
+ "LIBS": gconf_env["LIBS"],
+ "CCFLAGS": gconf_env["CCFLAGS"],
+ "CPPPATH": gconf_env["CPPPATH"],
+ "CPPDEFINES": gconf_env["CPPDEFINES"],
+ }
+ conf.Finish()
+
# Sparkle
env["HAVE_SPARKLE"] = 0
if env["PLATFORM"] == "darwin" :
@@ -507,6 +551,23 @@ else :
env["LIBIDN_BUNDLED"] = 1
conf.Finish()
+# SQLite
+sqlite_conf_env = conf_env.Clone()
+sqlite_flags = {}
+if env.get("sqlite_libdir", None) :
+ sqlite_flags["LIBPATH"] = [env["sqlite_libdir"]]
+if env.get("sqlite_includedir", None) :
+ sqlite_flags["CPPPATH"] = [env["sqlite_includedir"]]
+sqlite_conf_env.MergeFlags(sqlite_flags)
+conf = Configure(sqlite_conf_env)
+if conf.CheckCHeader("sqlite3.h") and conf.CheckLib(env["sqlite_libname"]) :
+ env["HAVE_SQLITE"] = 1
+ env["SQLITE_FLAGS"] = { "LIBS": [env["sqlite_libname"]] }
+ env["SQLITE_FLAGS"].update(sqlite_flags)
+else :
+ env["SQLITE_BUNDLED"] = 1
+conf.Finish()
+
# Lua
env["LUA_BUNDLED"] = 1
@@ -621,6 +682,9 @@ if env.Dir("#/.git").exists() :
# Project files
################################################################################
+# Build tools
+env.SConscript(dirs = ["#/BuildTools/CLang"])
+
# Modules
modules = []
for dir in os.listdir(Dir("#/3rdParty").abspath) :
diff --git a/BuildTools/SCons/Tools/AppBundle.py b/BuildTools/SCons/Tools/AppBundle.py
index c271575..6a343f6 100644
--- a/BuildTools/SCons/Tools/AppBundle.py
+++ b/BuildTools/SCons/Tools/AppBundle.py
@@ -1,7 +1,7 @@
import SCons.Util, os.path
def generate(env) :
- def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}) :
+ def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}, handlesXMPPURIs = False) :
bundleDir = bundle + ".app"
bundleContentsDir = bundleDir + "/Contents"
resourcesDir = bundleContentsDir + "/Resources"
@@ -32,6 +32,18 @@ def generate(env) :
for key, value in infoDict.items() :
plist += "<key>" + key + "</key>\n"
plist += "<string>" + value.encode("utf-8") + "</string>\n"
+ if handlesXMPPURIs :
+ plist += """<key>CFBundleURLTypes</key>
+<array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>XMPP URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>xmpp</string>
+ </array>
+ </dict>
+</array>\n"""
plist += """</dict>
</plist>
"""