Ignore:
Timestamp:
01/13/14 14:07:17 (3 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Better automatic configuration in orangeqt setup.py

File:
1 edited

Legend:

Unmodified
Added
Removed
  • source/orangeqt/setup.py

    • Property exe set to *
    r11672 r11831  
    1 #!usr/bin/env python 
    2  
    3 import os, sys 
    4  
    5 try: 
    6     from setuptools import setup 
    7     have_setuptools = True 
    8 except ImportError: 
    9     from distutils.core import setup 
    10     have_setuptools = False 
     1#!/usr/bin/env python 
     2 
     3import os 
     4import sys 
     5import shlex 
     6from collections import namedtuple 
     7from ConfigParser import SafeConfigParser 
     8 
     9from setuptools import setup 
    1110 
    1211from distutils.core import Extension 
    13 from distutils import log 
    14  
    15 import subprocess 
     12from distutils import dir_util, spawn, log 
     13 
    1614import glob 
    1715import numpy 
     16 
     17import sipdistutils 
     18 
     19try: 
     20    from PyQt4 import pyqtconfig 
     21except ImportError: 
     22    pyqtconfig = None 
     23 
     24try: 
     25    from PyQt4.QtCore import PYQT_CONFIGURATION 
     26except ImportError: 
     27    PYQT_CONFIGURATION = None 
     28 
     29pjoin = os.path.join 
    1830 
    1931NAME                = 'orangeqt-qt' 
     
    2638 
    2739 
    28  
    29 import PyQt4.QtCore 
    30  
    31 from PyQt4 import pyqtconfig  
    32  
    33 cfg = pyqtconfig.Configuration() 
    34 pyqt_sip_dir = cfg.pyqt_sip_dir 
    35  
    36 import sipdistutils 
     40pyqt_conf = namedtuple( 
     41    "pyqt_conf", 
     42    ["sip_flags", 
     43     "sip_dir"] 
     44) 
     45 
     46qt_conf = namedtuple( 
     47    "qt_conf", 
     48    ["prefix", 
     49     "include_dir", 
     50     "library_dir", 
     51     "framework", 
     52     "framework_dir"] 
     53) 
     54 
     55config = namedtuple( 
     56    "config", 
     57    ["sip", 
     58     "pyqt_conf", 
     59     "qt_conf"] 
     60) 
     61 
     62pyqt_sip_dir = None 
     63pyqt_sip_flags = None 
     64 
     65qt_dir = None 
     66qt_include_dir = None 
     67qt_lib_dir = None 
     68qt_framework = False 
     69 
     70# use PyQt4 build time config if provided 
     71if pyqtconfig is not None: 
     72    cfg = pyqtconfig.Configuration() 
     73    pyqt_sip_dir = cfg.pyqt_sip_dir 
     74    pyqt_sip_flags = cfg.pyqt_sip_flags 
     75 
     76    qt_dir = cfg.qt_dir 
     77    qt_include_dir = cfg.qt_inc_dir 
     78    qt_lib_dir = cfg.qt_lib_dir 
     79    qt_framework = bool(cfg.qt_framework) 
     80    qt_framework_dir = qt_lib_dir 
     81 
     82elif PYQT_CONFIGURATION is not None: 
     83    pyqt_sip_flags = PYQT_CONFIGURATION["sip_flags"] 
     84 
     85 
     86# if QTDIR env is defined use it 
     87if "QTDIR" in os.environ: 
     88    qt_dir = os.environ["QTDIR"] 
     89    if sys.platform == "darwin": 
     90        if glob(pjoin(qt_dir, "lib", "Qt*.framework")): 
     91            # This is the standard Qt4 framework layout 
     92            qt_framework = True 
     93            qt_framework_dir = pjoin(qt_dir, "lib") 
     94        elif glob(pjoin(qt_dir, "Frameworks", "Qt*.framework")): 
     95            # Also worth checking (standard for bundled apps) 
     96            qt_framework = True 
     97            qt_framework_dir = pjoin(qt_dir, "Frameworks") 
     98 
     99    if not qt_framework: 
     100        # Assume standard layout 
     101        qt_framework = False 
     102        qt_include_dir = pjoin(qt_dir, "include") 
     103        qt_lib_dir = pjoin(qt_dir, "lib") 
     104 
    37105 
    38106extra_compile_args = [] 
     
    40108include_dirs = [] 
    41109library_dirs = [] 
     110 
     111 
     112def site_config(): 
     113    parser = SafeConfigParser(dict(os.environ)) 
     114    parser.read(["site.cfg", 
     115                 os.path.expanduser("~/.orangeqt-site.cfg")]) 
     116 
     117    def get(section, option, default=None, type=None): 
     118        if parser.has_option(section, option): 
     119            if type is None: 
     120                return parser.get(section, option) 
     121            elif type is bool: 
     122                return parser.getboolean(section, option) 
     123            elif type is int: 
     124                return parser.getint(section, option) 
     125            else: 
     126                raise TypeError 
     127        else: 
     128            return default 
     129 
     130    sip_bin = get("sip", "sip_bin") 
     131 
     132    sip_flags = get("pyqt", "sip_flags", default=pyqt_sip_flags) 
     133    sip_dir = get("pyqt", "sip_dir", default=pyqt_sip_dir) 
     134 
     135    if sip_flags is not None: 
     136        sip_flags = shlex.split(sip_flags) 
     137    else: 
     138        sip_flags = [] 
     139 
     140    prefix = get("qt", "qt_dir", default=qt_dir) 
     141    include_dir = get("qt", "include_dir", default=qt_include_dir) 
     142    library_dir = get("qt", "library_dir", default=qt_lib_dir) 
     143    framework = get("qt", "framework", default=qt_framework, type=bool) 
     144    framework_dir = get("qt", "framework_dir", default=qt_framework_dir) 
     145 
     146    def path_list(path): 
     147        if path and path.strip(): 
     148            return path.split(os.pathsep) 
     149        else: 
     150            return [] 
     151 
     152    include_dir = path_list(include_dir) 
     153    library_dir = path_list(library_dir) 
     154 
     155    conf = config( 
     156        sip_bin, 
     157        pyqt_conf(sip_flags, sip_dir), 
     158        qt_conf(prefix, include_dir, library_dir, 
     159                framework, framework_dir) 
     160    ) 
     161    return conf 
     162 
     163site_cfg = site_config() 
    42164 
    43165if sys.platform == "darwin": 
     
    50172    sip_plaftorm_tag = "" 
    51173 
     174def which(name): 
     175    """ 
     176    Return the path of program named 'name' on the $PATH. 
     177    """ 
     178    if os.name == "nt" and not name.endswith(".exe"): 
     179        name = name + ".exe" 
     180 
     181    for path in os.environ["PATH"].split(os.pathsep): 
     182        path = os.path.join(path, name) 
     183        if os.path.isfile(path) and os.access(path, os.X_OK): 
     184            return path 
     185 
     186    return None 
     187 
     188 
    52189class PyQt4Extension(Extension): 
    53190    pass 
    54191 
     192 
    55193class build_pyqt_ext(sipdistutils.build_ext): 
     194    """ 
     195    A build_ext command for building PyQt4 sip based extensions 
     196    """ 
    56197    description = "Build a orangeqt PyQt4 extension." 
    57      
    58     user_options = sipdistutils.build_ext.user_options + \ 
    59         [("required", None,   
    60           "orangeqt is required (failure to build will raise an error)")] 
    61          
    62     boolean_options = sipdistutils.build_ext.boolean_options + \ 
    63         ["required"] 
    64      
    65     def initialize_options(self): 
    66         sipdistutils.build_ext.initialize_options(self) 
    67         self.required = False 
    68          
     198 
    69199    def finalize_options(self): 
    70200        sipdistutils.build_ext.finalize_options(self) 
    71         self.sip_opts = self.sip_opts + ["-k", "-j", "1", "-t",  
    72                         sip_plaftorm_tag, "-t", 
    73                         "Qt_" + PyQt4.QtCore.QT_VERSION_STR.replace('.', '_')] 
    74         if self.required is not None: 
    75             self.required = True 
     201        self.sip_opts = self.sip_opts + \ 
     202                        site_cfg.pyqt_conf.sip_flags + \ 
     203                        ["-j", "1"]  # without -j1 it does not build (??) 
    76204 
    77205    def build_extension(self, ext): 
    78206        if not isinstance(ext, PyQt4Extension): 
    79207            return 
    80         cppsources = [source for source in ext.sources if source.endswith(".cpp")] 
    81         if not os.path.exists(self.build_temp): 
    82             os.makedirs(self.build_temp) 
     208 
     209        cppsources = [source for source in ext.sources 
     210                      if source.endswith(".cpp")] 
     211 
     212        dir_util.mkpath(self.build_temp, dry_run=self.dry_run) 
     213 
     214        # Run moc on all header files. 
    83215        for source in cppsources: 
    84216            header = source.replace(".cpp", ".h") 
    85217            if os.path.exists(header): 
    86218                moc_file = os.path.basename(header).replace(".h", ".moc") 
    87                 call_arg = ["moc", "-o", os.path.join(self.build_temp, moc_file), header] 
    88                 log.info("Calling: " + " ".join(call_arg)) 
    89                 try: 
    90                     subprocess.call(call_arg) 
    91                 except OSError: 
    92                     raise OSError("Could not locate 'moc' executable.") 
    93         ext.extra_compile_args = ext.extra_compile_args + ["-I" + self.build_temp] 
     219                out_file = os.path.join(self.build_temp, moc_file) 
     220                call_arg = ["moc", "-o", out_file, header] 
     221                spawn.spawn(call_arg, dry_run=self.dry_run) 
     222 
     223        # Add the temp build directory to include path, for compiler to find 
     224        # the created .moc files 
     225        ext.include_dirs = ext.include_dirs + [self.build_temp] 
     226 
    94227        sipdistutils.build_ext.build_extension(self, ext) 
    95      
    96     def run(self): 
    97         try: 
    98             sipdistutils.build_ext.run(self) 
    99         except Exception as ex: 
    100             if self.required: 
    101                 raise 
    102             else: 
    103                 log.info("Could not build orangeqt extension (%r)\nSkipping." % ex) 
     228 
     229    def _find_sip(self): 
     230        if site_cfg.sip: 
     231            log.info("Using sip at %r (from .cfg file)" % site_cfg.sip) 
     232            return site_cfg.sip 
     233 
     234        # Try the base implementation 
     235        sip = sipdistutils.build_ext._find_sip(self) 
     236        if os.path.isfile(sip): 
     237            return sip 
     238 
     239        log.warn("Could not find sip executable at %r." % sip) 
     240 
     241        # Find sip on $PATH 
     242        sip = which("sip") 
     243 
     244        if sip: 
     245            log.info("Found sip on $PATH at: %s" % sip) 
     246            return sip 
     247 
     248        return sip 
    104249 
    105250    # For sipdistutils to find PyQt4's .sip files 
    106251    def _sip_sipfiles_dir(self): 
    107         return pyqt_sip_dir 
     252        if site_cfg.pyqt_conf.sip_dir: 
     253            return site_cfg.pyqt_conf.sip_dir 
     254 
     255        if os.path.isdir(pyqt_sip_dir): 
     256            return pyqt_sip_dir 
     257 
     258        log.warn("The default sip include directory %r does not exist" % 
     259                 pyqt_sip_dir) 
     260 
     261        path = os.path.join(sys.prefix, "share/sip/PyQt4") 
     262        if os.path.isdir(path): 
     263            log.info("Found sip include directory at %r" % path) 
     264            return path 
     265 
     266        return "." 
    108267 
    109268 
     
    114273 
    115274 
    116 # Used Qt4 libs 
    117 qt_libs = ["QtCore", "QtGui", "QtOpenGL"] 
    118  
    119  
    120 if cfg.qt_framework: 
    121     extra_compile_args = ["-F%s" % cfg.qt_lib_dir] 
    122     extra_link_args = ["-F%s" % cfg.qt_lib_dir] 
     275# Used Qt4 libraries 
     276qt_libs = ["QtCore", "QtGui"] 
     277 
     278if site_cfg.qt_conf.framework: 
     279    framework_dir = site_cfg.qt_conf.framework_dir 
     280    extra_compile_args = ["-F%s" % framework_dir] 
     281    extra_link_args = ["-F%s" % framework_dir] 
    123282    for lib in qt_libs: 
    124         include_dirs += [os.path.join(cfg.qt_lib_dir, 
     283        include_dirs += [os.path.join(framework_dir, 
    125284                                      lib + ".framework", "Headers")] 
    126285        extra_link_args += ["-framework", lib] 
    127 #    extra_link_args += ["-framework", "OpenGL"] 
    128286    qt_libs = [] 
    129287else: 
    130     include_dirs = [cfg.qt_inc_dir] + \ 
    131                    [os.path.join(cfg.qt_inc_dir, lib) for lib in qt_libs] 
    132     library_dirs += [cfg.qt_lib_dir] 
     288    include_dirs = [site_cfg.qt_conf.include_dir] + \ 
     289                   [pjoin(site_cfg.qt_conf.include_dir, lib) 
     290                    for lib in qt_libs] 
     291    library_dirs += [site_cfg.qt_conf.library_dir] 
    133292 
    134293if sys.platform == "win32": 
     
    138297include_dirs += [numpy.get_include(), "./"] 
    139298 
    140 orangeqt_ext = PyQt4Extension("orangeqt", 
    141                               ["orangeqt.sip"] + get_source_files("", "cpp", 
    142                                exclude=["canvas3d.cpp", "plot3d.cpp", "glextensions.cpp"] 
    143                                ), 
    144                               include_dirs=include_dirs, 
    145                               extra_compile_args=extra_compile_args + \ 
    146                                                    ["-DORANGEQT_EXPORTS"], 
    147                               extra_link_args=extra_link_args, 
    148                               libraries = qt_libs, 
    149                               library_dirs=library_dirs 
    150                              ) 
     299orangeqt_ext = PyQt4Extension( 
     300    "orangeqt", 
     301    ["orangeqt.sip"] + get_source_files( 
     302        "", "cpp", 
     303        exclude=["canvas3d.cpp", "plot3d.cpp", "glextensions.cpp"] 
     304     ), 
     305    include_dirs=include_dirs, 
     306    extra_compile_args=extra_compile_args + \ 
     307                         ["-DORANGEQT_EXPORTS"], 
     308    extra_link_args=extra_link_args, 
     309    libraries=qt_libs, 
     310    library_dirs=library_dirs 
     311) 
    151312 
    152313ENTRY_POINTS = { 
     
    156317} 
    157318 
     319 
    158320def setup_package(): 
    159     setup(name = NAME, 
    160           description = DESCRIPTION, 
    161           version = VERSION, 
    162           author = AUTHOR, 
    163           author_email = AUTHOR_EMAIL, 
    164           url = URL, 
    165           license = LICENSE, 
    166           ext_modules = [orangeqt_ext], 
     321    setup(name=NAME, 
     322          description=DESCRIPTION, 
     323          version=VERSION, 
     324          author=AUTHOR, 
     325          author_email=AUTHOR_EMAIL, 
     326          url=URL, 
     327          license=LICENSE, 
     328          ext_modules=[orangeqt_ext], 
    167329          cmdclass={"build_ext": build_pyqt_ext}, 
    168           entry_points = ENTRY_POINTS, 
     330          entry_points=ENTRY_POINTS, 
    169331          ) 
    170332 
Note: See TracChangeset for help on using the changeset viewer.