configure.py
changeset 6 c3690ec91ef8
parent 5 627c4a0fd0e7
child 7 923ff622b8b9
--- a/configure.py	Fri Jun 11 13:58:22 2010 +0300
+++ b/configure.py	Wed Jun 23 18:33:25 2010 +0300
@@ -45,6 +45,10 @@
 HB_MAKE_PARTS = [ "tutorials" ]
 HB_NOMAKE_PARTS = [ "tests", "performance", "localization" ]
 
+QMAKE = None
+MAKE = None
+BUILDENV = None
+
 # ============================================================================
 # Utils
 # ============================================================================
@@ -61,6 +65,24 @@
         if not part in HB_NOMAKE_PARTS:
             HB_NOMAKE_PARTS.append(part)
 
+def run_system(args, cwd=None):
+    old_epocroot = None
+    env = os.environ.copy()
+    if "EPOCROOT" in env:
+        epocroot = env.get("EPOCROOT")
+        if not (epocroot.endswith("\\") or epocroot.endswith("/")):
+            os.putenv("EPOCROOT", "%s/" % epocroot)
+            old_epocroot = epocroot
+
+    if type(args) is list:
+        args = " ".join(args)
+    result = os.system(args)
+
+    if old_epocroot != None:
+        os.putenv("EPOCROOT", old_epocroot)
+
+    return result
+
 def run_process(args, cwd=None):
     code = 0
     output = ""
@@ -104,6 +126,19 @@
         print(e)
     return content
 
+def write_file(filepath, content):
+    try:
+        path = os.path.split(filepath)[0]
+        if not os.path.exists(path):
+            os.makedirs(path)
+        file = open(filepath, "w")
+        file.write(content)
+        file.close()
+    except Exception, e:
+        print(e)
+        return False
+    return True
+
 def grep(path, pattern, include = [], exclude = []):
     result = {}
     expr = re.compile(pattern)
@@ -130,19 +165,19 @@
 # OptionParser
 # ============================================================================
 class OptionParser(optparse.OptionParser):
-    def __init__(self, platform, make, prefix):
+    def __init__(self):
         optparse.OptionParser.__init__(self, formatter=optparse.TitledHelpFormatter())
         self.add_option("-v", "--verbose", action="store_true", dest="verbose",
                         help="Print verbose information during the configure.")
         self.set_defaults(verbose=False)
 
-        if platform != "symbian":
+        if QMAKE.platform() != "symbian":
             group = optparse.OptionGroup(self, "Installation options")
             group.add_option("--prefix", dest="prefix", metavar="dir",
                              help="Install everything relative to <dir>. The default value is '%s'. "
                                   "NOTE: Use '--prefix .' to configure a local setup. A local "
                                   "setup will install nothing else than the qmake "
-                                  "feature file." % prefix)
+                                  "feature file." % BUILDENV.default_prefix())
             group.add_option("--bin-dir", dest="bindir", metavar="dir",
                              help="Install executables to <dir>. The default value is 'PREFIX/bin'.")
             group.add_option("--lib-dir", dest="libdir", metavar="dir",
@@ -153,19 +188,19 @@
                              help="Install headers to <dir>. The default value is 'PREFIX/include'.")
             group.add_option("--plugin-dir", dest="plugindir", metavar="dir",
                              help="Install plugins to <dir>. The default value is 'PREFIX/plugins'.")
-            group.add_option("--resource-dir", dest="resourcedir", metavar="dir",
+            group.add_option("--features-dir", dest="featuresdir", metavar="dir",
+                             help="Install qmake feature files to <dir>. The default value is 'QTDIR/mkspecs/features'.")
+            group.add_option("--resources-dir", dest="resourcesdir", metavar="dir",
                              help="Install resources to <dir>. The default value is 'PREFIX/resources'.")
-            group.add_option("--feature-dir", dest="featuredir", metavar="dir",
-                             help="Install qmake feature files to <dir>. The default value is 'QTDIR/mkspecs/features'.")
             self.add_option_group(group)
         self.set_defaults(prefix=None)
         self.set_defaults(bindir=None)
         self.set_defaults(libdir=None)
         self.set_defaults(docdir=None)
         self.set_defaults(includedir=None)
-        self.set_defaults(plugindir=None)
-        self.set_defaults(resourcedir=None)
-        self.set_defaults(featuredir=None)
+        self.set_defaults(pluginsdir=None)
+        self.set_defaults(featuresdir=None)
+        self.set_defaults(resourcesdir=None)
 
         group = optparse.OptionGroup(self, "Configure options")
         group.add_option("--platform", dest="platform", metavar="platform",
@@ -175,7 +210,7 @@
         group.add_option("--make-bin", dest="makebin", metavar="path",
                          help="Specify the make tool (make, nmake, mingw32-make, gmake...). "
                               "The one detected in PATH is used by default if not specified.")
-        if platform == "win32" and make == "nmake":
+        if QMAKE.platform() == "win32" and MAKE.bin() == "nmake":
             group.add_option("--msvc", action="store_true", dest="msvc",
                              help="Generate a MSVC solution.")
         group.add_option("--release", action="store_const", dest="config", const="release",
@@ -188,7 +223,7 @@
                          help="Do not suppress debug and warning output (suppressed by default in release mode).")
         group.add_option("--no-debug-output", action="store_true", dest="no_debug_output",
                          help="Suppress debug and warning output (not supporessed by default in debug mode).")
-        if platform != "symbian":
+        if QMAKE.platform() != "symbian":
             group.add_option("--silent", action="store_true", dest="silent",
                              help="Suppress verbose compiler output.")
             group.add_option("--fast", action="store_true", dest="fast",
@@ -201,6 +236,12 @@
         group.add_option("--defines", dest="defines", metavar="defines",
                          help="Define compiler macros for selecting features "
                               "and debugging purposes eg. --defines HB_FOO_DEBUG,HB_BAR_ENABLED")
+        if QMAKE.platform() == "unix":
+            group.add_option("--rpath", action="store_true", dest="rpath",
+                             help="Link Hb libraries and executables using the library install "
+                                  "path as a runtime library path.")
+            group.add_option("--no-rpath", action="store_false", dest="rpath",
+                             help="Do not use the library install path as a runtime library path.")
         self.add_option_group(group)
         self.set_defaults(platform=None)
         self.set_defaults(makebin=None)
@@ -209,6 +250,7 @@
         self.set_defaults(silent=False)
         self.set_defaults(fast=False)
         self.set_defaults(defines=None)
+        self.set_defaults(rpath=None)
 
         group = optparse.OptionGroup(self, "Host options")
         group.add_option("--host-qmake-bin", dest="hostqmakebin", metavar="path",
@@ -228,8 +270,6 @@
                          help="Additional qmake options "
                               "eg. --qmake-options \"CONFIG+=foo DEFINES+=BAR\".")
         self.add_option_group(group)
-        self.set_defaults(qmakebin=None)
-        self.set_defaults(qmakespec=None)
         self.set_defaults(qmakeopt=None)
 
         group = optparse.OptionGroup(self, "Feature options")
@@ -243,198 +283,296 @@
                          help="Do not build gestures.")
         group.add_option("--no-text-measurement", action="store_false", dest="textMeasurement",
                          help="Do not build text measurement support (needed for localization).")
-        group.add_option("--no-inputs", action="store_false", dest="inputs",
-                         help="DEPRECATED: Use --nomake hbinput.")
-        group.add_option("--no-feedback", action="store_false", dest="feedback",
-                         help="DEPRECATED: Use --nomake hbfeedback.")
-        group.add_option("--no-tutorials", action="store_false", dest="tutorials",
-                         help="DEPRECATED: Use --nomake tutorials.")
         self.add_option_group(group)
         self.set_defaults(make=None)
         self.set_defaults(nomake=None)
         self.set_defaults(effects=True)
         self.set_defaults(gestures=True)
         self.set_defaults(textMeasurement=True)
-        self.set_defaults(inputs=None)
-        self.set_defaults(feedback=None)
-        self.set_defaults(tutorials=None)
 
         group = optparse.OptionGroup(self, "Qt options")
         group.add_option("--qt-mobility", action="store_true", dest="qtmobility",
                          help="Assumes that Qt Mobility is available without performing a compilation test.")
         group.add_option("--no-qt-mobility", action="store_false", dest="qtmobility",
                          help="Assumes that Qt Mobility is not available without performing a compilation test.")
-        group.add_option("--qt-animation", action="store_true", dest="qtanimation",
-                         help="DEPRECATED: Qt 4.6 includes the animation framework.")
-        group.add_option("--no-qt-animation", action="store_false", dest="qtanimation",
-                         help="DEPRECATED: Qt 4.6 includes the animation framework.")
-        group.add_option("--qt-gestures", action="store_true", dest="qtgestures",
-                         help="DEPRECATED: Qt 4.6 includes the gestures framework.")
-        group.add_option("--no-qt-gestures", action="store_false", dest="qtgestures",
-                         help="DEPRECATED: Qt 4.6 includes the gestures framework.")
-        if platform == "symbian" or platform == None:
-            group.add_option("--qt-symbian-eventfilter", action="store_false", dest="s60eventfilter",
-                             help="DEPRECATED: Qt 4.6 includes QApplication::symbianEventFilter().")
-            group.add_option("--qt-s60-eventfilter", action="store_true", dest="s60eventfilter",
-                             help="DEPRECATED: Qt 4.6 includes QApplication::symbianEventFilter().")
-        group.add_option("--dui", action="store_true", dest="dui",
-                         help="Assumes that Maemo Direct UI is available without performing a compilation test.")
-        group.add_option("--no-dui", action="store_false", dest="dui",
-                         help="Assumes that Maemo Direct UI is not available without performing a compilation test.")
+        group.add_option("--meegotouch", action="store_true", dest="meegotouch",
+                         help="Assumes that MeeGoTouch UI is available without performing a compilation test.")
+        group.add_option("--no-meegotouch", action="store_false", dest="meegotouch",
+                         help="Assumes that MeeGoTouch UI is not available without performing a compilation test.")
         self.add_option_group(group)
         self.set_defaults(qtmobility=None)
-        self.set_defaults(qtanimation=None)
-        self.set_defaults(qtgestures=None)
-        self.set_defaults(qts60eventfilter=None)
 
         group = optparse.OptionGroup(self, "Developer options")
         group.add_option("--developer", action="store_true", dest="developer",
-                         help="Enables the developer mode ie. builds tests and exports necessary symbols. "
-                              "NOTE: The developer mode implies a local setup by default.")
-        if platform != "symbian":
+                         help="Enables the developer mode. The developer mode implies "
+                         "a local setup, enables tests and exports extra symbols for "
+                         "testing purposes. NOTE: this is equal to: --prefix . --make tests "
+                         "--developer-export")
+        group.add_option("--developer-export", action="store_true", dest="developerexport",
+                         help="Enables developer exports ie. extra symbols for testing purposes.")
+        if QMAKE.platform() != "symbian":
             group.add_option("--coverage", action="store_true", dest="coverage",
                              help="Builds with test coverage measurement support. "
                                   "This implies the developer mode.")
-        group.add_option("--tests", action="store_true", dest="tests",
-                         help="DEPRECATED: Use --make tests.")
-        group.add_option("--performance", action="store_true", dest="performance",
-                         help="DEPRECATED: Use --make performance.")
-        group.add_option("--localization", action="store_true", dest="localization",
-                         help="DEPRECATED: Use --make localization.")
         self.add_option_group(group)
         self.set_defaults(developer=False)
+        self.set_defaults(developerexport=None)
         self.set_defaults(coverage=False)
-        self.set_defaults(tests=None)
-        self.set_defaults(performance=None)
-        self.set_defaults(localization=None)
 
 # ============================================================================
-# Platform
+# Make
 # ============================================================================
-class Platform:
-    def __init__(self, qmake):
+class Make:
+    def __init__(self):
+        self._bin = None
+
+    def init(self, cmdline):
+        match = re.search("--make-bin[=\s](\S+)", cmdline)
+        if match:
+            self._bin = match.group(1)
+        else:
+            self._bin = self._detect_make()
+
+    def command(self, target=None):
+        _args = [self._bin]
+        if target:
+            _args += [target]
+        return _args
+
+    def bin(self):
+        return self._bin
+
+    def _detect_make(self):
+        if QMAKE.platform() == "win32" and self._test_make("nmake", "/?"):
+            return "nmake"
+        if self._test_make("make", "-v"):
+            return "make"
+        if self._test_make("gmake", "-v"):
+            return "gmake"
+        if QMAKE.platform() == "win32" and self._test_make("mingw32-make", "-v"):
+            return "mingw32-make"
+        return "make"
+
+    def _test_make(self, command, param):
+        try:
+            return run_process([command, param])[0] == 0
+        except:
+            return False
+
+# ============================================================================
+# QMake
+# ============================================================================
+class QMake:
+    def __init__(self):
+        self._bin = "qmake"
         self._platform = None
-        self._make = None
         self._error = None
-        self._qmake = qmake
         self._spec = None
-        self._version = None
         self._features = None
         self._qtdir = None
+        self._qtversion = None
+        self._args = []
 
-    def name(self):
-        if not self._platform:
-            self._detect_qt()
+    def init(self, cmdline):
+        match = re.search("--qmake-bin[=\s](\S+)", cmdline)
+        if match:
+            self._bin = match.group(1)
+        match = re.search("--platform[=\s](\S+)", cmdline)
+        if match:
+            self._platform = match.group(1)
+        match = re.search("--qmake-spec[=\s](\S+)", cmdline)
+        if match:
+            self._spec = match.group(1)
+        return self._run_qmake()
+
+    def command(self, profile=None):
+        _args = [self._bin]
+        if self._spec:
+            _args += ["-spec", self._spec]
+        if len(self._args):
+            _args += self._args
+        if profile:
+            _args += [profile]
+        return _args
+
+    def add_args(self, args):
+        self._args += args
+
+    def platform(self):
         return self._platform
 
-    def make(self):
-        if not self._make:
-            self._make = self._detect_make()
-        return self._make
-
-    def qmake(self):
-        if not self._qmake:
-            self._detect_qt()
-        return self._qmake
+    def bin(self):
+        return self._bin
 
     def error(self):
         return self._error
 
     def spec(self):
-        if not self._spec:
-            self._detect_qt()
         return self._spec
 
-    def version(self):
-        if not self._version:
-            self._detect_qt()
-        return self._version
-
     def features(self):
-        if not self._features:
-            self._detect_qt()
         return self._features
 
     def qtdir(self):
-        if not self._qtdir:
-            self._detect_qt()
         return self._qtdir
 
-    def _detect_qt(self):
-        lines = list()
-        lines.append("symbian:message(platform:symbian)\n")
-        lines.append("else:macx:message(platform:macx)\n")
-        lines.append("else:unix:message(platform:unix)\n")
-        lines.append("else:win32:message(platform:win32)\n")
-
-        lines.append("message(version:$$[QT_VERSION])\n")
-        lines.append("message(libraries:$$[QT_INSTALL_LIBS])\n")
-        lines.append("message(features:$$[QMAKE_MKSPECS]/features)\n")
+    def qtversion(self):
+        return self._version
 
-        try:
-            if not os.path.exists("tmp"):
-                os.makedirs("tmp")
-            fd, filepath = tempfile.mkstemp(dir="tmp", text=True, suffix=".pro")
-            file = os.fdopen(fd, "w+")
-            file.writelines(lines)
-            file.close()
-        except Exception, e:
-            print(e)
-            self._error = "Unable to write a temporary file. Make sure to configure in a writable directory."
-            return
+    def _run_qmake(self):
+        # write .pro
+        content = """
+                  symbian:message(platform:symbian)
+                  symbian:message(platform:symbian)
+                  else:macx:message(platform:macx)
+                  else:unix:message(platform:unix)
+                  else:win32:message(platform:win32)
+                  message(features:$$[QMAKE_MKSPECS]/features)
+                  message(qtversion:$$[QT_VERSION])
+                  message(qtdir:$$[QT_INSTALL_LIBS])
+                  """
+        if not write_file("tmp/qmake.pro", content):
+            self._error = "Unable to write 'tmp/qmake.pro'. Make sure to configure in a writable directory."
+            return False
 
-        # do not use .qmake.cache when detecting the platform
-        args = [self._qmake, "-nocache", os.path.split(filepath)[1]]
+        # run qmake
+        args = [self._bin, "-nocache", "qmake.pro"]
         if self._spec:
             args += ["-spec", self._spec]
         (code, output) = run_process(args, "tmp")
+
+        # cleanup & check return
         shutil.rmtree("tmp", ignore_errors=True)
         if code != 0:
-            self._error = "Unable to execute %s" % self._qmake
-            if self._qmake == "qmake":
+            self._error = "Unable to execute %s" % self._bin
+            if self._bin == "qmake":
                 self._error += ". Add qmake to PATH or pass --qmake-bin <path/to/qmake>."
+            return False
 
+        # parse output
         try:
-            self._platform = re.search("Project MESSAGE: platform:(\S+)", output).group(1)
-            self._version = re.search("Project MESSAGE: version:(\S+)", output).group(1)
-            self._qtdir = re.search("Project MESSAGE: libraries:(\S+)", output).group(1)
+            if not self._platform:
+                self._platform = re.search("Project MESSAGE: platform:(\S+)", output).group(1)
             self._features = re.search("Project MESSAGE: features:(\S+)", output).group(1)
+            self._version = re.search("Project MESSAGE: qtversion:(\S+)", output).group(1)
+            self._qtdir = re.search("Project MESSAGE: qtdir:(\S+)", output).group(1)
         except:
             self._error = "Unable to parse qmake output (%s)" % output.strip()
             if output.find("QMAKESPEC") != -1:
                 self._error += ". Set QMAKESPEC environment variable or pass --qmake-spec <spec>."
-        return None
+            return False
+        return True
+
+# ============================================================================
+# BuildEnvironment
+# ============================================================================
+class BuildEnvironment:
+    def __init__(self):
+        self._blddir = os.path.abspath(os.getcwd())
+        self._srcdir = os.path.abspath(sys.path[0])
+        self._prefix = None
+        self._bindir = None
+        self._libdir = None
+        self._docdir = None
+        self._includedir = None
+        self._pluginsdir = None
+        self._featuresdir = None
+        self._resourcesdir = None
+
+    def init(self, options):
+        # prefix
+        if options.prefix:
+            # explicit
+            self._prefix = options.prefix
+        elif options.developer:
+            # developer mode implies a "local" build
+            self._prefix = self._blddir
+        else:
+            # fall back to default
+            self._prefix = self.default_prefix()
+        if QMAKE.platform() != "symbian":
+            self._prefix = os.path.abspath(self._prefix)
+
+        self._bindir = self._dir_option(options.bindir, self._prefix + "/bin")
+        self._libdir = self._dir_option(options.libdir, self._prefix + "/lib")
+        self._docdir = self._dir_option(options.docdir, self._prefix + "/doc")
+        self._includedir = self._dir_option(options.includedir, self._prefix + "/include")
+        self._pluginsdir = self._dir_option(options.pluginsdir, self._prefix + "/plugins")
+        self._featuresdir = self._dir_option(options.featuresdir, QMAKE.features())
+        self._resourcesdir = self._dir_option(options.resourcesdir, self._prefix + "/resources")
+
+        # symbian specific adjustments
+        if QMAKE.platform() == "symbian":
+            # TODO: fix to "$${EPOCROOT}resource/hb/plugins"
+            self._pluginsdir = "$${EPOCROOT}resource/qt/plugins/hb"
+
+            if not options.developer:
+                if os.path.isdir("/s60"):
+                    self._includedir = self._prefix + "/include/hb"
+                else:
+                    self._includedir = self._prefix + "/include/mw/hb"
 
-    def _detect_make(self):
-        if self.name() == "win32" and Platform._test_make("nmake", "/?"):
-            return "nmake"
-        if Platform._test_make("make", "-v"):
-            return "make"
-        if Platform._test_make("gmake", "-v"):
-            return "gmake"
-        if self.name() == "win32" and Platform._test_make("mingw32-make", "-v"):
-            return "mingw32-make"
-        return "(n)make"
+    def builddir(self):
+        return self._blddir
+
+    def sourcedir(self):
+        return self._srcdir
+
+    def prefix(self):
+        return self._prefix
+
+    def bindir(self):
+        return self._bindir
+
+    def libdir(self):
+        return self._libdir
+
+    def docdir(self):
+        return self._docdir
+
+    def includedir(self):
+        return self._includedir
+
+    def pluginsdir(self):
+        return self._pluginsdir
+
+    def featuresdir(self):
+        return self._featuresdir
 
-    def _test_make(command, param):
-        try:
-            return run_process([command, param])[0] == 0
-        except:
-            return False
+    def resourcesdir(self):
+        return self._resourcesdir
+
+    def exportdir(self, category=None):
+        if os.path.isdir("/s60"):
+            if category:
+                return "hb/%1/" + category + "/%2"
+            return "hb/%1/%2"
+        else:
+            if category:
+                return "$${EPOCROOT}epoc32/include/mw/hb/%1/" + category + "/%2"
+            return "$${EPOCROOT}epoc32/include/mw/hb/%1/%2"
 
-    _test_make = staticmethod(_test_make)
+    def default_prefix(self):
+        prefixes = { "symbian" : "$${EPOCROOT}epoc32",
+                     "unix"    : "/usr/local/hb",
+                     "macx"    : "/usr/local/hb",
+                     "win32"   : "C:/hb" }
+        return prefixes.get(QMAKE.platform(), self._blddir)
+
+    def local(self):
+        prefix = self.prefix()
+        return os.path.isdir(prefix) and (prefix == self._blddir)
+
+    def _dir_option(self, explicit, default):
+        if explicit:
+            return explicit
+        return default
 
 # ============================================================================
 # ConfigTest
 # ============================================================================
 class ConfigTest:
-    def __init__(self, platform):
-        self._make = platform.make()
-        self._qmake = platform.qmake()
-        self._platform = platform.name()
-        self._spec = platform.spec()
-
-    def setup(self, sourcedir, builddir):
+    def __init__(self, sourcedir=os.getcwd(), builddir=os.getcwd()):
         self._sourcedir = sourcedir
         self._builddir = builddir
 
@@ -453,14 +591,11 @@
             os.chdir(builddir)
 
             # run qmake & make
-            args = [self._qmake, filepath]
-            if self._spec:
-                args += ["-spec", self._spec]
-            run_process(args)
-            (code, output) = run_process([self._make])
+            run_process(QMAKE.command(filepath))
+            (code, output) = run_process(MAKE.command())
 
             # make return value is not reliable
-            if self._platform == "symbian":
+            if QMAKE.platform() == "symbian":
                 # on symbian, check that no error patterns such as '***' can be found from build output
                 patterns = ["\\*\\*\\*", "Errors caused tool to abort"]
                 for pattern in patterns:
@@ -475,7 +610,7 @@
                     code = -1
 
             # clean
-            run_process([self._make, "clean"])
+            run_process(MAKE.command("clean"))
 
         except:
             code = -1
@@ -520,168 +655,90 @@
 # main()
 # ============================================================================
 def main():
-    global HB_MAKE_PARTS, HB_NOMAKE_PARTS
-
-    qmake = "qmake"
-    cmdline = " ".join(sys.argv[1:])
-    match = re.search("--qmake-bin[=\s](\S+)", cmdline)
-    if match:
-        qmake = match.group(1)
-
-    # detect platform
-    platform = Platform(qmake)
-    match = re.search("--platform[=\s](\S+)", cmdline)
-    if match:
-        platform._platform = match.group(1)
-
-    match = re.search("--qmake-spec[=\s](\S+)", cmdline)
-    if match:
-        platform._spec = match.group(1)
+    global QMAKE, MAKE, BUILDENV, HB_MAKE_PARTS, HB_NOMAKE_PARTS
 
     help = False
+    cmdline = " ".join(sys.argv[1:])
     match = re.search("--help\s*", cmdline)
     if match or re.search("-h\s*", cmdline):
         help = True
 
-    if not help and not platform.name():
-        print("ERROR: %s" % platform.error())
-        return
+    QMAKE = QMake()
+    QMAKE.init(cmdline)
 
-    # detect make
-    match = re.search("--make-bin[=\s](\S+)", cmdline)
-    if match:
-        platform._make = match.group(1)
-    if not platform.make():
-        print("ERROR: %s" % platform.error())
+    if not help and not QMAKE.platform():
+        print("ERROR: %s" % QMAKE.error())
         return
 
-    currentdir = os.path.abspath(os.getcwd())
-    sourcedir = os.path.abspath(sys.path[0])
+    MAKE = Make()
+    MAKE.init(cmdline)
 
-    # default prefixes
-    prefixes = { "symbian" : "$${EPOCROOT}epoc32",
-                 "unix"    : "/usr/local/hb",
-                 "macx"    : "/usr/local/hb",
-                 "win32"   : "C:/hb" }
+    BUILDENV = BuildEnvironment()
 
     # parse command line options
-    parser = OptionParser(platform.name(), platform.make(), prefixes.get(platform.name(), currentdir))
+    parser = OptionParser()
     (options, args) = parser.parse_args()
 
+    BUILDENV.init(options)
+
     # coverage implies developer mode
     if options.coverage:
         options.developer = True
 
-    print("Configuring Hb...")
-    print("INFO: Platform: %s" % platform.name())
-    print("INFO: Make: %s" % platform.make())
-    print("INFO: Qt: %s in %s" % (platform.version(), platform.qtdir()))
+    # developer mode implies tests, including perf & loc
+    if options.developer:
+        add_remove_part("tests", True)
+        add_remove_part("performance", True)
+        add_remove_part("localization", True)
 
-    # warn about deprecated options
-    if options.qtanimation != None:
-        print("WARNING: --qt-animation and --qt-no-animation are DEPRECATED. Qt 4.6 includes the animation framework.")
-    if options.qtgestures != None:
-        print("WARNING: --qt-gestures and --qt-no-gestures are DEPRECATED. Qt 4.6 includes the gestures framework.")
-    if options.qts60eventfilter != None:
-        print("WARNING: --qt-symbian-eventfilter and --qt-s60-eventfilter are DEPRECATED. Qt 4.6 includes QApplication::symbianEventFilter().")
-    if options.inputs != None:
-        print("WARNING: --no-inputs is DEPRECATED. Use --nomake hbinput.")
-        add_remove_part("hbinput", options.inputs)
-    if options.feedback != None:
-        print("WARNING: --no-feedback is DEPRECATED. Use --nomake hbfeedback.")
-        add_remove_part("hbfeedback", options.feedback)
-    if options.tutorials != None:
-        print("WARNING: --no-tutorials is DEPRECATED. Use --nomake tutorials.")
-        add_remove_part("tutorials", options.tutorials)
-    if options.tests != None:
-        print("WARNING: --tests is DEPRECATED. Use --make tests.")
-        add_remove_part("tests", options.tests)
-    if options.performance != None:
-        print("WARNING: --performance is DEPRECATED. Use --make performance.")
-        add_remove_part("performance", options.performance)
-    if options.localization != None:
-        print("WARNING: --localization is DEPRECATED. Use --make localization.")
-        add_remove_part("localization", options.localization)
+    # developer mode implies developer exports
+    if options.developer:
+        options.developerexport = True
 
-    # sort out directories
-    if not options.prefix:
-        # developer mode implies local setup
-        if options.developer:
-            options.prefix = currentdir
-        else:
-            options.prefix = prefixes.get(platform.name(), currentdir)
-    basedir = options.prefix
-    if platform.name() != "symbian":
-        basedir = os.path.abspath(basedir)
-    local = os.path.isdir(basedir) and (basedir == currentdir)
+    print("Configuring Hb...")
+    print("INFO: Platform: %s" % QMAKE.platform())
+    print("INFO: Make: %s" % MAKE.bin())
+    print("INFO: Qt: %s in %s" % (QMAKE.qtversion(), QMAKE.qtdir()))
 
     # compilation tests to detect available features
     config = ConfigFile()
-    test = ConfigTest(platform)
-    test.setup(sourcedir, currentdir)
+    test = ConfigTest(BUILDENV.sourcedir(), BUILDENV.builddir())
     print("\nDetecting available features...")
     if options.qtmobility == None:
         options.qtmobility = test.compile("config.tests/all/mobility")
     if options.qtmobility:
         config.add_value("DEFINES", "HB_HAVE_QT_MOBILITY")
     print("INFO: Qt Mobility:\t\t\t%s" % options.qtmobility)
-    if platform.name() == "symbian":
+    if QMAKE.platform() == "symbian":
         sgimagelite_result = test.compile("config.tests/symbian/sgimagelite")
         if sgimagelite_result:
             config.add_value("CONFIG", "sgimage")
         print("INFO: SgImage-Lite:\t\t\t%s" % sgimagelite_result)
-    if options.dui == None:
-        options.dui = test.compile("config.tests/maemo/dui")
-    if options.dui:
-        config.add_value("CONFIG", "hb_maemo_dui")
-        config.add_value("DEFINES", "HB_MAEMO_DUI")
-    print("INFO: Direct UI:\t\t\t%s" % options.dui)
+        tchunkcreateinfo_result = test.compile("config.tests/symbian/tchunkcreateinfo")
+        if tchunkcreateinfo_result:
+            config.add_value("DEFINES", "HB_HAVE_PROTECTED_CHUNK")
+        touchfeedback_result = test.compile("config.tests/symbian/touchfeedback")
+        if touchfeedback_result:
+            config.add_value("DEFINES", "HB_TOUCHFEEDBACK_TYPE_IS_LONGPRESS")
+        print("INFO: ETouchFeedbackLongPress:\t\t%s" % touchfeedback_result)
+    if options.meegotouch == None:
+        options.meegotouch = test.compile("config.tests/meego/meegotouch")
+    if options.meegotouch:
+        config.add_value("CONFIG", "hb_meegotouch")
+        config.add_value("DEFINES", "HB_MEEGOTOUCH")
+    print("INFO: MeeGo Touch:\t\t\t%s" % options.meegotouch)
 
-    # directories
-    if options.bindir == None:
-        # TODO: symbian
-        options.bindir = basedir + "/bin"
-    if options.libdir == None:
-        # TODO: symbian
-        options.libdir = basedir + "/lib"
-    if options.docdir == None:
-        # TODO: symbian
-        options.docdir = basedir + "/doc"
-    if options.includedir == None:
-        if platform.name() == "symbian" and not options.developer:
-            if os.path.isdir("/s60"):
-                options.includedir = basedir + "/include/hb"
-            else:
-                options.includedir = basedir + "/include/mw/hb"
-        else:
-            options.includedir = basedir + "/include"
-    if options.plugindir == None:
-        if platform.name() == "symbian":
-            # TODO: fix to "$${EPOCROOT}resource/hb/plugins"
-            options.plugindir = "$${EPOCROOT}resource/qt/plugins/hb"
-        else:
-            options.plugindir = basedir + "/plugins"
-    if options.featuredir == None:
-        options.featuredir = platform.features()
-    if options.resourcedir == None:
-        # TODO: fix this, some components want to write resources...
-        #       thus, cannot point to the source tree!
-        if not local:
-            options.resourcedir = basedir + "/resources"
-        else:
-            options.resourcedir = sourcedir + "/src/hbcore/resources"
-
-    config.set_value("HB_INSTALL_DIR", ConfigFile.format_dir(basedir))
-    config.set_value("HB_BIN_DIR", ConfigFile.format_dir(options.bindir))
-    config.set_value("HB_LIB_DIR", ConfigFile.format_dir(options.libdir))
-    config.set_value("HB_DOC_DIR", ConfigFile.format_dir(options.docdir))
-    config.set_value("HB_INCLUDE_DIR", ConfigFile.format_dir(options.includedir))
-    config.set_value("HB_PLUGINS_DIR", ConfigFile.format_dir(options.plugindir))
-    config.set_value("HB_RESOURCES_DIR", ConfigFile.format_dir(options.resourcedir))
-    config.set_value("HB_FEATURES_DIR", ConfigFile.format_dir(options.featuredir))
+    config.set_value("HB_INSTALL_DIR", ConfigFile.format_dir(BUILDENV.prefix()))
+    config.set_value("HB_BIN_DIR", ConfigFile.format_dir(BUILDENV.bindir()))
+    config.set_value("HB_LIB_DIR", ConfigFile.format_dir(BUILDENV.libdir()))
+    config.set_value("HB_DOC_DIR", ConfigFile.format_dir(BUILDENV.docdir()))
+    config.set_value("HB_INCLUDE_DIR", ConfigFile.format_dir(BUILDENV.includedir()))
+    config.set_value("HB_PLUGINS_DIR", ConfigFile.format_dir(BUILDENV.pluginsdir()))
+    config.set_value("HB_FEATURES_DIR", ConfigFile.format_dir(BUILDENV.featuresdir()))
+    config.set_value("HB_RESOURCES_DIR", ConfigFile.format_dir(BUILDENV.resourcesdir()))
 
     # TODO: get rid of this!
-    if platform.name() == "symbian":
+    if QMAKE.platform() == "symbian":
         config.set_value("HB_PLUGINS_EXPORT_DIR", ConfigFile.format_dir("$${EPOCROOT}epoc32/winscw/c/resource/qt/plugins/hb"))
 
     if options.gestures:
@@ -690,12 +747,14 @@
         config.add_value("DEFINES", "HB_EFFECTS")
     if options.textMeasurement:
         config.add_value("DEFINES", "HB_TEXT_MEASUREMENT_UTILITY")
-	if platform.name() != "symbian" and options.developer:
-		config.add_value("DEFINES", "HB_CSS_INSPECTOR")
+    if QMAKE.platform() != "symbian" and options.developer:
+        config.add_value("DEFINES", "HB_CSS_INSPECTOR")
     if options.defines:
         config.add_value("DEFINES", " ".join(options.defines.split(",")))
-    if options.developer:
+    if options.developerexport:
         config.add_value("DEFINES", "HB_DEVELOPER")
+    if options.rpath == None or options.rpath == True:
+        config.add_value("QMAKE_RPATHDIR", "$${HB_LIB_DIR}")
 
     if options.verbose:
         print("INFO: Writing hb_install.prf")
@@ -703,22 +762,11 @@
         print("ERROR: Unable to write hb_install_prf.")
         return
 
-    config.set_value("HB_BUILD_DIR", ConfigFile.format_dir(currentdir))
-    config.set_value("HB_SOURCE_DIR", ConfigFile.format_dir(sourcedir))
-    config.set_value("HB_MKSPECS_DIR", ConfigFile.format_dir(basedir + "/mkspecs"))
-
-    if platform.name() == "symbian":
-        if os.path.isdir("/s60"):
-            config.set_value("HB_EXPORT_DIR", "hb/%1/%2")
-            config.set_value("HB_RESTRICTED_EXPORT_DIR", "hb/%1/restricted/%2")
-        else:
-            config.set_value("HB_EXPORT_DIR", "$${EPOCROOT}epoc32/include/mw/hb/%1/%2")
-            config.set_value("HB_RESTRICTED_EXPORT_DIR", "$${EPOCROOT}epoc32/include/mw/hb/%1/restricted/%2")
-
-    if options.developer:
-        add_remove_part("tests", True)
-        add_remove_part("performance", True)
-        add_remove_part("localization", True)
+    config.set_value("HB_BUILD_DIR", ConfigFile.format_dir(BUILDENV.builddir()))
+    config.set_value("HB_SOURCE_DIR", ConfigFile.format_dir(BUILDENV.sourcedir()))
+    if QMAKE.platform() == "symbian":
+        config.set_value("HB_EXPORT_DIR", ConfigFile.format_dir(BUILDENV.exportdir()))
+        config.set_value("HB_RESTRICTED_EXPORT_DIR", ConfigFile.format_dir(BUILDENV.exportdir("restricted")))
 
     if options.make:
         for part in options.make:
@@ -737,7 +785,7 @@
         for qmakeopt in options.qmakeopt.split():
             config._lines.append(qmakeopt + "\n")
 
-    if local:
+    if BUILDENV.local():
         config.add_value("CONFIG", "local")
     if options.silent:
         config.add_value("CONFIG", "silent")
@@ -781,7 +829,7 @@
     config.add_value("DEFINES", "QT_QCHAR_CONSTRUCTOR")
 
     # TODO: is there any better way to expose functions to the whole source tree?
-    config._lines.append("include(%s)\n" % (os.path.splitdrive(sourcedir)[1] + "/mkspecs/hb_functions.prf"))
+    config._lines.append("include(%s)\n" % (os.path.splitdrive(BUILDENV.sourcedir())[1] + "/mkspecs/hb_functions.prf"))
 
     if options.verbose:
         print("INFO: Writing .qmake.cache")
@@ -812,76 +860,66 @@
     if options.verbose:
         print("INFO: Running %s" % synchb)
         synchb = "%s -v" % synchb
-    os.system("python %s/%s -i %s -o %s" % (sourcedir, synchb, sourcedir, currentdir))
+    os.system("python %s/%s -i %s -o %s" % (BUILDENV.sourcedir(), synchb, BUILDENV.sourcedir(), BUILDENV.builddir()))
 
     # generate a qrc for resources
     print("INFO: Qt resource collection")
-    args = [os.path.join(sourcedir, "bin/resourcifier.py")]
+    args = [os.path.join(BUILDENV.sourcedir(), "bin/resourcifier.py")]
     args += ["-i", "%s" % os.path.join(sys.path[0], "src/hbcore/resources")]
-    # TODO: make it currentdir
-    args += ["-o", "%s" % os.path.join(sourcedir, "src/hbcore/resources/resources.qrc")]
+    # TODO: make it BUILDENV.builddir()
+    args += ["-o", "%s" % os.path.join(BUILDENV.sourcedir(), "src/hbcore/resources/resources.qrc")]
     args += ["--exclude", "\"*distribution.policy.s60\""]
     args += ["--exclude", "\"*readme.txt\""]
     args += ["--exclude", "\"*.pr?\""]
     args += ["--exclude", "\"*.qrc\""]
     args += ["--exclude", "\"*~\""]
     args += ["--exclude", "variant/*"]
-    args += ["--exclude", "\"*css.bin\""]
+    args += ["--exclude", "\"*hbdefault.cssbin\""]
+
+    if QMAKE.platform() != "symbian":
+        args += ["--exclude", "\"*symbian*\""]
+    if QMAKE.platform() != "macx":
+        args += ["--exclude", "\"*macx*\""]
+    if QMAKE.platform() != "unix":
+        args += ["--exclude", "\"*unix*\""]
+    if QMAKE.platform() != "win32":
+        args += ["--exclude", "\"*win32*\""]
+
     if options.verbose:
         print("INFO: Running %s" % " ".join(args))
     os.system("python %s" % " ".join(args))
 
     # build host tools
-    if platform.name() == "symbian" or options.hostqmakebin != None or options.hostmakebin != None:
+    if QMAKE.platform() == "symbian" or options.hostqmakebin != None or options.hostmakebin != None:
         print("\nBuilding host tools...")
         if options.hostqmakebin != None and options.hostmakebin != None:
-            profile = "%s/src/hbtools/hbtools.pro" % sourcedir
+            profile = "%s/src/hbtools/hbtools.pro" % BUILDENV.sourcedir()
             if os.path.exists(profile):
-                toolsdir = os.path.join(currentdir, "src/hbtools")
+                toolsdir = os.path.join(BUILDENV.builddir(), "src/hbtools")
                 if not os.path.exists(toolsdir):
                     os.makedirs(toolsdir)
                 os.chdir(toolsdir)
                 os.system("\"%s\" -config silent %s" % (options.hostqmakebin, profile))
                 os.system("\"%s\"" % (options.hostmakebin))
-                os.chdir(currentdir)
+                os.chdir(BUILDENV.builddir())
         else:
             print("WARNING: Cannot build host tools, because no --host-qmake-bin and/or")
             print("         --host-make-bin was provided. Hb will attempt to run host")
             print("         tools from PATH.")
 
     # run qmake
-    if options.qmakebin:
-        qmake = options.qmakebin
-    
-    profile = os.path.join(sourcedir, "hb.pro")
-    cachefile = os.path.join(currentdir, ".qmake.cache")
+    profile = os.path.join(BUILDENV.sourcedir(), "hb.pro")
+    QMAKE.add_args(["-cache", os.path.join(BUILDENV.builddir(), ".qmake.cache")])
     if options.msvc:
-        qmake = "%s -tp vc" % qmake
+        QMAKE.add_args(["-tp", "vc"])
     if not options.fast:
-        qmake = "%s -r" % qmake
-    if options.qmakespec:
-        qmake = "%s -spec %s" % (qmake, options.qmakespec)
-    if options.qmakeopt:
-        qmake = "%s \\\"%s\\\"" % (qmake, options.qmakeopt)
+        QMAKE.add_args(["-r"])
     if options.verbose:
-        print("\nRunning %s -cache %s %s" % (qmake, cachefile, profile))
+        print("\nRunning %s" % QMAKE.command(profile))
     else:
         print("\nRunning qmake...")
     try:
-
-        # modify epocroot for symbian to have compatibility between qmake and raptor
-        env = os.environ.copy()
-        if "EPOCROOT" in env:
-            epocroot = env.get("EPOCROOT")
-            if not (epocroot.endswith("\\") or epocroot.endswith("/")):
-                os.putenv("EPOCROOT", "%s/" % epocroot)
-                ret = os.system("%s -cache %s %s" % (qmake, cachefile, profile))
-                os.putenv("EPOCROOT", epocroot)
-            else:
-                ret = os.system("%s -cache %s %s" % (qmake, cachefile, profile))
-        else:
-            ret = os.system("%s -cache %s %s" % (qmake, cachefile, profile))
-    
+        ret = run_system(QMAKE.command(profile))
     except KeyboardInterrupt:
         ret = -1
     if ret != 0:
@@ -892,40 +930,28 @@
 
     if "tests" not in HB_NOMAKE_PARTS:
         # run qmake for tests
-        profile = "%s/tsrc/tsrc.pro" % sourcedir
+        profile = "%s/tsrc/tsrc.pro" % BUILDENV.sourcedir()
         if os.path.exists(profile):
-            tsrcdir = os.path.join(currentdir, "tsrc")
+            tsrcdir = os.path.join(BUILDENV.builddir(), "tsrc")
             if not os.path.exists(tsrcdir):
                 os.makedirs(tsrcdir)
             os.chdir(tsrcdir)
             if options.verbose:
-                print("\nRunning %s %s" % (qmake, profile))
+                print("\nRunning %s" % QMAKE.command(profile))
             else:
                 print("\nRunning qmake in tsrc...")
-            
-            # epocroot cecking also for tests
-            env = os.environ.copy()
-            if "EPOCROOT" in env:
-                epocroot = env.get("EPOCROOT")
-                if not (epocroot.endswith("\\") or epocroot.endswith("/")):
-                    os.putenv("EPOCROOT", "%s/" % epocroot)
-                    os.system("%s %s" % (qmake, profile))
-                    os.putenv("EPOCROOT", epocroot)
-                else:
-                    os.system("%s %s" % (qmake, profile))
-            else:
-                os.system("%s %s" % (qmake, profile))
-            os.chdir(currentdir)
+            run_system(QMAKE.command(profile))
+            os.chdir(BUILDENV.builddir())
 
             # create output dirs
-            outputdir = os.path.join(currentdir, "autotest")
+            outputdir = os.path.join(BUILDENV.builddir(), "autotest")
             if not os.path.exists(outputdir):
                 os.makedirs(outputdir)
-            outputdir = os.path.join(currentdir, "coverage")
+            outputdir = os.path.join(BUILDENV.builddir(), "coverage")
             if not os.path.exists(outputdir):
                 os.makedirs(outputdir)
         # nag about tests that are commented out
-        result = grep(sourcedir + "/tsrc", "#\s*SUBDIRS\s*\+=\s*(\S+)", ["*.pr?"])
+        result = grep(BUILDENV.sourcedir() + "/tsrc", "#\s*SUBDIRS\s*\+=\s*(\S+)", ["*.pr?"])
         maxlen = 0
         for profile in result:
             maxlen = max(maxlen, len(profile))
@@ -952,40 +978,37 @@
 
     # print summary
     print("")
-    if platform.make() == "nmake" and options.msvc:
+    if MAKE.bin() == "nmake" and options.msvc:
         conf = "MSVC"
         act = "open 'hb.sln'"
     elif options.coverage:
         conf = "test coverage measurement"
-        act = "run '%s coverage'" % platform.make()
+        act = "run '%s coverage'" % MAKE.bin()
     elif options.developer:
         conf = "development"
-        act = "run '%s'" % platform.make()
+        act = "run '%s'" % MAKE.bin()
     else:
         conf = "building"
-        act = "run '%s'" % platform.make()
+        act = "run '%s'" % MAKE.bin()
     print("Hb is now configured for %s. Just %s." % (conf, act))
 
     if not options.coverage:
-        if platform.name() == "symbian" or local:
-            print("You must run '%s install' to copy the .prf file in place." % platform.make())
+        if QMAKE.platform() == "symbian" or BUILDENV.local():
+            print("You must run '%s install' to copy Hb files in place." % MAKE.bin())
         else:
-            print("Once everything is built, you must run '%s install'." % platform.make())
-        if platform != "symbian":
-            if local:
-                print("Hb will be used from '%s'." % sourcedir)
+            print("Once everything is built, you must run '%s install'." % MAKE.bin())
+        if QMAKE.platform() != "symbian":
+            if BUILDENV.local():
+                print("Hb will be used from '%s'." % BUILDENV.prefix())
             else:
-                print("Hb will be installed to '%s'." % basedir)
-    if platform.name() == "win32":
-        path = os.path.join(basedir, "bin")
-        if local:
-            path = os.path.join(currentdir, "bin")
-        print("NOTE: Make sure that '%s' is in PATH." % path)
+                print("Hb will be installed to '%s'." % BUILDENV.prefix())
+    if QMAKE.platform() == "win32":
+        print("NOTE: Make sure that '%s' is in PATH." % BUILDENV.bindir())
         if options.coverage:
             print("Test code coverage measurement will FAIL if wrong Hb DLLs are found in PATH before '%s'." % path)
 
     print("")
-    print("To reconfigure, run '%s clean' and '%s'." % (platform.make(), sys.argv[0]))
+    print("To reconfigure, run '%s clean' and '%s'." % (MAKE.bin(), sys.argv[0]))
     print("")
 
 if __name__ == "__main__":