xpra icon
Bug tracker and wiki

Changes in trunk/src/setup.py [6000:18085] in xpra


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/setup.py

    r6000 r18085  
    22
    33# This file is part of Xpra.
    4 # Copyright (C) 2010-2014 Antoine Martin <antoine@devloop.org.uk>
     4# Copyright (C) 2010-2017 Antoine Martin <antoine@devloop.org.uk>
    55# Copyright (C) 2008, 2009, 2010 Nathaniel Smith <njs@pobox.com>
    66# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     
    1111# does the make_constants hack.)
    1212
    13 import commands
    1413import glob
    1514from distutils.core import setup
    1615from distutils.extension import Extension
    17 import subprocess, sys, traceback
     16import sys
    1817import os.path
    19 import stat
     18from distutils.command.build import build
     19from distutils.command.install_data import install_data
     20import shutil
     21
     22if sys.version<'2.7':
     23    raise Exception("xpra no longer supports Python 2 versions older than 2.7")
     24if sys.version[0]=='3' and sys.version<'3.4':
     25    raise Exception("xpra no longer supports Python 3 versions older than 3.4")
     26#we don't support versions of Python without the new ssl code:
     27import ssl
     28assert ssl.SSLContext, "xpra requires a Python version with ssl.SSLContext support"
    2029
    2130print(" ".join(sys.argv))
    2231
     32#*******************************************************************************
     33# build options, these may get modified further down..
     34#
    2335import xpra
    24 from xpra.platform.features import LOCAL_SERVERS_SUPPORTED, SHADOW_SUPPORTED
    25 
    26 WIN32 = sys.platform.startswith("win")
     36data_files = []
     37modules = []
     38packages = []       #used by py2app
     39excludes = []       #only used by cx_freeze on win32
     40ext_modules = []
     41cmdclass = {}
     42scripts = []
     43description = "multi-platform screen and application forwarding system"
     44long_description = "Xpra is a multi platform persistent remote display server and client for " + \
     45            "forwarding applications and desktop screens. Also known as 'screen for X11'."
     46url = "http://xpra.org/"
     47
     48
     49XPRA_VERSION = xpra.__version__         #@UndefinedVariable
     50setup_options = {
     51                 "name"             : "xpra",
     52                 "version"          : XPRA_VERSION,
     53                 "license"          : "GPLv2+",
     54                 "author"           : "Antoine Martin",
     55                 "author_email"     : "antoine@devloop.org.uk",
     56                 "url"              : url,
     57                 "download_url"     : "http://xpra.org/src/",
     58                 "description"      : description,
     59                 "long_description" : long_description,
     60                 "data_files"       : data_files,
     61                 "py_modules"       : modules,
     62                 }
     63
     64WIN32 = sys.platform.startswith("win") or sys.platform.startswith("msys")
    2765OSX = sys.platform.startswith("darwin")
    28 
    29 
     66LINUX = sys.platform.startswith("linux")
     67NETBSD = sys.platform.startswith("netbsd")
     68FREEBSD = sys.platform.startswith("freebsd")
     69PYTHON3 = sys.version_info[0] == 3
     70POSIX = os.name=="posix"
     71import struct
     72BITS = struct.calcsize("P")*8
     73
     74
     75if "pkg-info" in sys.argv:
     76    with open("PKG-INFO", "wb") as f:
     77        pkg_info_values = setup_options.copy()
     78        pkg_info_values.update({
     79                                "metadata_version"  : "1.1",
     80                                "summary"           :  description,
     81                                "home_page"         : url,
     82                                })
     83        for k in ("Metadata-Version", "Name", "Version", "Summary", "Home-page",
     84                  "Author", "Author-email", "License", "Download-URL", "Description"):
     85            v = pkg_info_values[k.lower().replace("-", "_")]
     86            f.write(b"%s: %s\n" % (k, v))
     87    sys.exit(0)
     88
     89
     90print("Xpra version %s" % XPRA_VERSION)
    3091#*******************************************************************************
    3192# Most of the options below can be modified on the command line
     
    3394# only the default values are specified here:
    3495#*******************************************************************************
     96from xpra.os_util import get_status_output, is_Ubuntu, is_Debian, is_Raspbian, getUbuntuVersion,\
     97    PYTHON3
     98
     99PKG_CONFIG = os.environ.get("PKG_CONFIG", "pkg-config")
     100has_pkg_config = False
     101#we don't support building with "pkg-config" on win32 with python2:
     102if PKG_CONFIG:
     103    v = get_status_output([PKG_CONFIG, "--version"])
     104    has_pkg_config = v[0]==0 and v[1]
     105    if has_pkg_config:
     106        print("found pkg-config version: %s" % v[1].strip("\n\r"))
     107
     108from Cython.Compiler.Version import version as cython_version
     109
     110for arg in list(sys.argv):
     111    if arg.startswith("--pkg-config-path="):
     112        pcp = arg[len("--pkg-config-path="):]
     113        pcps = [pcp] + os.environ.get("PKG_CONFIG_PATH", "").split(os.path.pathsep)
     114        os.environ["PKG_CONFIG_PATH"] = os.path.pathsep.join([x for x in pcps if x])
     115        print("using PKG_CONFIG_PATH=%s" % (os.environ["PKG_CONFIG_PATH"], ))
     116        sys.argv.remove(arg)
     117
     118def no_pkgconfig(*_pkgs_options, **_ekw):
     119    return {}
     120
    35121def pkg_config_ok(*args):
    36     return commands.getstatusoutput("pkg-config %s" % (" ".join(args)))[0]==0
    37 
    38 shadow_ENABLED = SHADOW_SUPPORTED
    39 server_ENABLED = LOCAL_SERVERS_SUPPORTED or shadow_ENABLED
    40 client_ENABLED = True
    41 
    42 x11_ENABLED = not WIN32 and not OSX
    43 argb_ENABLED = True
    44 gtk2_ENABLED = client_ENABLED
    45 gtk3_ENABLED = False
    46 qt4_ENABLED = False
    47 opengl_ENABLED = client_ENABLED
    48 html5_ENABLED = not WIN32 and not OSX
    49 
    50 bencode_ENABLED         = True
    51 cython_bencode_ENABLED  = True
    52 rencode_ENABLED         = True
    53 cymaths_ENABLED         = True
    54 cyxor_ENABLED           = True
    55 clipboard_ENABLED       = True
    56 Xdummy_ENABLED          = None          #none means auto-detect
    57 sound_ENABLED           = True
    58 
    59 enc_proxy_ENABLED       = True
    60 enc_x264_ENABLED        = True          #too important to detect
    61 enc_x265_ENABLED        = pkg_config_ok("--exists", "x265")
    62 webp_ENABLED            = WIN32 or pkg_config_ok("--atleast-version=0.3", "libwebp")
    63 x264_static_ENABLED     = False
    64 x265_static_ENABLED     = False
    65 vpx_ENABLED             = WIN32 or pkg_config_ok("--atleast-version=1.0", "vpx") or pkg_config_ok("--atleast-version=1.0", "libvpx")
    66 vpx_static_ENABLED      = False
    67 #ffmpeg 1.x and libav:
    68 dec_avcodec_ENABLED     = not WIN32 and pkg_config_ok("--max-version=55", "libavcodec")
    69 #ffmpeg 2 onwards:
    70 dec_avcodec2_ENABLED    = WIN32 or pkg_config_ok("--atleast-version=55", "libavcodec")
    71 # some version strings I found:
    72 # Fedora 19: 54.92.100
    73 # Fedora 20: 55.39.101
    74 # Debian sid and jessie: 54.35.0
    75 # Debian wheezy: 53.35
    76 avcodec_static_ENABLED  = False
    77 avcodec2_static_ENABLED = False
    78 csc_swscale_ENABLED     = WIN32 or pkg_config_ok("--exists", "libswscale")
    79 swscale_static_ENABLED  = False
    80 csc_cython_ENABLED      = True
    81 webm_ENABLED            = True
    82 nvenc_ENABLED           = pkg_config_ok("--exists", "nvenc3")
    83 csc_nvcuda_ENABLED      = pkg_config_ok("--exists", "cuda")
    84 csc_opencl_ENABLED      = pkg_config_ok("--exists", "OpenCL")
    85 
     122    cmd = [PKG_CONFIG]  + [str(x) for x in args]
     123    return get_status_output(cmd)[0]==0
     124
     125def pkg_config_version(req_version, pkgname):
     126    cmd = [PKG_CONFIG, "--modversion", pkgname]
     127    r, out, _ = get_status_output(cmd)
     128    if r!=0 or not out:
     129        return False
     130    from distutils.version import LooseVersion
     131    return LooseVersion(out)>=LooseVersion(req_version)
     132
     133def is_RH():
     134    try:
     135        with open("/etc/redhat-release", mode='rb') as f:
     136            data = f.read()
     137        return data.startswith("CentOS") or data.startswith("RedHat")
     138    except:
     139        pass
     140    return False
     141
     142DEFAULT = True
     143if "--minimal" in sys.argv:
     144    sys.argv.remove("--minimal")
     145    DEFAULT = False
     146
     147from xpra.platform.features import LOCAL_SERVERS_SUPPORTED, SHADOW_SUPPORTED
     148shadow_ENABLED = SHADOW_SUPPORTED and DEFAULT
     149server_ENABLED = (LOCAL_SERVERS_SUPPORTED or shadow_ENABLED) and DEFAULT
     150rfb_ENABLED = server_ENABLED
     151service_ENABLED = LINUX and server_ENABLED
     152sd_listen_ENABLED = POSIX and pkg_config_ok("--exists", "libsystemd") and (not is_Ubuntu() or getUbuntuVersion()>[16, 4])
     153proxy_ENABLED  = DEFAULT
     154client_ENABLED = DEFAULT
     155
     156x11_ENABLED = DEFAULT and not WIN32 and not OSX
     157xinput_ENABLED = x11_ENABLED
     158uinput_ENABLED = x11_ENABLED
     159dbus_ENABLED = DEFAULT and x11_ENABLED and not (OSX or WIN32)
     160gtk_x11_ENABLED = DEFAULT and not WIN32 and not OSX
     161gtk2_ENABLED = DEFAULT and client_ENABLED and not PYTHON3
     162gtk3_ENABLED = DEFAULT and client_ENABLED and PYTHON3
     163opengl_ENABLED = DEFAULT and client_ENABLED
     164html5_ENABLED = DEFAULT
     165html5_gzip_ENABLED = DEFAULT
     166html5_brotli_ENABLED = DEFAULT
     167minify_ENABLED = html5_ENABLED
     168pam_ENABLED = DEFAULT and (server_ENABLED or proxy_ENABLED) and POSIX and not OSX and (os.path.exists("/usr/include/pam/pam_misc.h") or os.path.exists("/usr/include/security/pam_misc.h"))
     169
     170xdg_open_ENABLED        = LINUX and DEFAULT
     171netdev_ENABLED          = LINUX and DEFAULT
     172vsock_ENABLED           = LINUX and os.path.exists("/usr/include/linux/vm_sockets.h")
     173bencode_ENABLED         = DEFAULT
     174cython_bencode_ENABLED  = DEFAULT
     175clipboard_ENABLED       = DEFAULT
     176Xdummy_ENABLED          = None          #None means auto-detect
     177Xdummy_wrapper_ENABLED  = None          #None means auto-detect
     178if WIN32 or OSX:
     179    Xdummy_ENABLED = False
     180sound_ENABLED           = DEFAULT
     181printing_ENABLED        = DEFAULT
     182crypto_ENABLED          = DEFAULT
     183mdns_ENABLED            = DEFAULT
     184
     185enc_proxy_ENABLED       = DEFAULT
     186enc_x264_ENABLED        = DEFAULT and pkg_config_ok("--exists", "x264")
     187enc_x265_ENABLED        = DEFAULT and pkg_config_ok("--exists", "x265")
     188pillow_ENABLED          = DEFAULT
     189webp_ENABLED            = DEFAULT and pkg_config_version("0.5", "libwebp")
     190jpeg_ENABLED            = DEFAULT and pkg_config_version("1.4", "libturbojpeg")
     191vpx_ENABLED             = DEFAULT and pkg_config_version("1.4", "vpx")
     192enc_ffmpeg_ENABLED      = False
     193#opencv currently broken on 32-bit windows (crashes on load):
     194webcam_ENABLED          = DEFAULT and not OSX
     195v4l2_ENABLED            = DEFAULT and (not WIN32 and not OSX and not FREEBSD)
     196#ffmpeg 3.1 or later is required
     197dec_avcodec2_ENABLED    = DEFAULT and pkg_config_version("57", "libavcodec")
     198csc_swscale_ENABLED     = DEFAULT and pkg_config_ok("--exists", "libswscale")
     199nvenc_ENABLED = DEFAULT and BITS==64 and pkg_config_version("7", "nvenc")
     200nvfbc_ENABLED = DEFAULT and BITS==64 and pkg_config_ok("--exists", "nvfbc")
     201cuda_kernels_ENABLED    = DEFAULT
     202cuda_rebuild_ENABLED    = DEFAULT
     203csc_libyuv_ENABLED      = DEFAULT and pkg_config_ok("--exists", "libyuv")
     204example_ENABLED         = DEFAULT
     205
     206#Cython / gcc / packaging build options:
     207annotate_ENABLED        = True
    86208warn_ENABLED            = True
    87209strict_ENABLED          = True
    88 PIC_ENABLED             = True
     210PIC_ENABLED             = not WIN32     #ming32 moans that it is always enabled already
    89211debug_ENABLED           = False
    90212verbose_ENABLED         = False
    91213bundle_tests_ENABLED    = False
     214tests_ENABLED           = False
     215rebuild_ENABLED         = True
    92216
    93217#allow some of these flags to be modified on the command line:
    94 SWITCHES = ("enc_x264", "x264_static",
    95             "enc_x265", "x265_static",
    96             "nvenc",
    97             "dec_avcodec", "avcodec_static",
    98             "dec_avcodec2", "avcodec2_static",
    99             "csc_swscale", "swscale_static",
    100             "csc_nvcuda", "csc_opencl", "csc_cython",
    101             "vpx", "vpx_static",
    102             "webp", "webm",
    103             "rencode", "bencode", "cython_bencode",
     218SWITCHES = ["enc_x264", "enc_x265", "enc_ffmpeg",
     219            "nvenc", "cuda_kernels", "cuda_rebuild", "nvfbc",
     220            "vpx", "webp", "pillow", "jpeg",
     221            "v4l2",
     222            "dec_avcodec2", "csc_swscale",
     223            "csc_libyuv",
     224            "bencode", "cython_bencode", "vsock", "netdev", "mdns",
    104225            "clipboard",
    105             "server", "client", "x11",
    106             "gtk2", "gtk3", "qt4", "html5",
    107             "sound", "cyxor", "cymaths", "opengl", "argb",
    108             "warn", "strict", "shadow", "debug", "PIC", "Xdummy", "verbose", "bundle_tests")
     226            "server", "client", "dbus", "x11", "xinput", "uinput", "sd_listen",
     227            "gtk_x11", "service",
     228            "gtk2", "gtk3", "example",
     229            "html5", "minify", "html5_gzip", "html5_brotli",
     230            "pam", "xdg_open",
     231            "sound", "opengl", "printing", "webcam",
     232            "rebuild",
     233            "annotate", "warn", "strict",
     234            "shadow", "proxy", "rfb",
     235            "debug", "PIC",
     236            "Xdummy", "Xdummy_wrapper", "verbose", "tests", "bundle_tests"]
     237if WIN32:
     238    SWITCHES.append("zip")
     239    zip_ENABLED = True
    109240HELP = "-h" in sys.argv or "--help" in sys.argv
    110241if HELP:
     
    120251            default_str = "auto-detect"
    121252        print("%s or %s (default: %s)" % (with_str.ljust(25), without_str.ljust(30), default_str))
     253    print("  --pkg-config-path=PATH")
     254    print("  --rpath=PATH")
    122255    sys.exit(0)
    123256
     257install = "dist"
     258rpath = None
     259ssl_cert = None
     260ssl_key = None
     261minifier = None
    124262filtered_args = []
    125263for arg in sys.argv:
    126     #deprecated flag:
    127     if arg == "--enable-Xdummy":
    128         Xdummy_ENABLED = True
     264    matched = False
     265    for x in ("rpath", "ssl-cert", "ssl-key", "install"):
     266        varg = "--%s=" % x
     267        if arg.startswith(varg):
     268            value = arg[len(varg):]
     269            globals()[x.replace("-", "_")] = value
     270            #remove these arguments from sys.argv,
     271            #except for --install=PATH
     272            matched = x!="install"
     273            break
     274    if matched:
    129275        continue
    130     matched = False
    131276    for x in SWITCHES:
    132         if arg=="--with-%s" % x:
     277        with_str = "--with-%s" % x
     278        without_str = "--without-%s" % x
     279        if arg.startswith(with_str+"="):
     280            vars()["%s_ENABLED" % x] = arg[len(with_str)+1:]
     281            matched = True
     282            break
     283        elif arg==with_str:
    133284            vars()["%s_ENABLED" % x] = True
    134285            matched = True
    135286            break
    136         elif arg=="--without-%s" % x:
     287        elif arg==without_str:
    137288            vars()["%s_ENABLED" % x] = False
    138289            matched = True
     
    145296    for x in SWITCHES:
    146297        switches_info[x] = vars()["%s_ENABLED" % x]
    147     print("build switches: %s" % switches_info)
    148     if LOCAL_SERVERS_SUPPORTED:
    149         print("Xdummy build flag: %s" % Xdummy_ENABLED)
     298    print("build switches:")
     299    for k in sorted(SWITCHES):
     300        v = switches_info[k]
     301        print("* %s : %s" % (str(k).ljust(20), {None : "Auto", True : "Y", False : "N"}.get(v, v)))
    150302
    151303    #sanity check the flags:
     
    153305        print("Warning: clipboard can only be used with the server or one of the gtk clients!")
    154306        clipboard_ENABLED = False
    155     if opengl_ENABLED and not gtk2_ENABLED:
    156         print("Warning: opengl can only be used with the gtk2 clients")
    157         opengl_ENABLED = False
    158     if shadow_ENABLED and not server_ENABLED:
    159         print("Warning: shadow requires server to be enabled!")
    160         shadow_ENABLED = False
    161     if cymaths_ENABLED and not server_ENABLED:
    162         print("Warning: cymaths requires server to be enabled!")
    163         cymaths_ENABLED = False
    164307    if x11_ENABLED and WIN32:
    165308        print("Warning: enabling x11 on MS Windows is unlikely to work!")
    166     if client_ENABLED and not gtk2_ENABLED and not gtk3_ENABLED and not qt4_ENABLED:
     309    if gtk_x11_ENABLED and not x11_ENABLED:
     310        print("Error: you must enable x11 to support gtk_x11!")
     311        exit(1)
     312    if client_ENABLED and not gtk2_ENABLED and not gtk3_ENABLED:
    167313        print("Warning: client is enabled but none of the client toolkits are!?")
    168     if not argb_ENABLED and (x11_ENABLED or OSX):
    169         print("Error: argb is required for x11 and osx builds!")
    170         exit(1)
    171     if not client_ENABLED and not server_ENABLED:
    172         print("Error: you must build at least the client or server!")
    173         exit(1)
     314    if DEFAULT and (not client_ENABLED and not server_ENABLED):
     315        print("Warning: you probably want to build at least the client or server!")
     316    if DEFAULT and not pillow_ENABLED:
     317        print("Warning: including Python Pillow is VERY STRONGLY recommended")
     318    if minify_ENABLED:
     319        r = get_status_output(["uglifyjs", "--version"])[0]
     320        if r==0:
     321            minifier = "uglifyjs"
     322        else:
     323            print("Warning: uglifyjs failed and return %i" % r)
     324            try:
     325                import yuicompressor
     326                assert yuicompressor
     327                minifier = "yuicompressor"
     328            except ImportError as e:
     329                print("Warning: yuicompressor module not found, cannot minify")
     330                minify_ENABLED = False
     331    if not enc_x264_ENABLED and not vpx_ENABLED:
     332        print("Warning: no x264 and no vpx support!")
     333        print(" you should enable at least one of these two video encodings")
    174334
    175335
    176336#*******************************************************************************
    177 # build options, these may get modified further down..
    178 #
    179 setup_options = {}
    180 setup_options["name"] = "xpra"
    181 setup_options["author"] = "Antoine Martin"
    182 setup_options["author_email"] = "antoine@devloop.org.uk"
    183 setup_options["version"] = xpra.__version__
    184 setup_options["url"] = "http://xpra.org/"
    185 setup_options["download_url"] = "http://xpra.org/src/"
    186 setup_options["description"] = "Xpra: 'screen for X' utility"
    187 
    188 xpra_desc = "'screen for X' -- a tool to detach/reattach running X programs"
    189 setup_options["long_description"] = xpra_desc
    190 data_files = []
    191 setup_options["data_files"] = data_files
    192 modules = []
    193 setup_options["py_modules"] = modules
    194 packages = []       #used by py2app and py2exe
    195 excludes = []       #only used by py2exe on win32
    196 ext_modules = []
    197 cmdclass = {}
    198 scripts = []
    199 
    200 external_includes = ["cairo", "pango", "pangocairo", "atk", "glib", "gobject", "gio", "gtk.keysyms",
    201                      "Crypto", "Crypto.Cipher",
    202                      "hashlib",
    203                      "PIL", "PIL.Image",
     337# default sets:
     338
     339external_includes = ["hashlib",
    204340                     "ctypes", "platform"]
     341
     342
     343if gtk3_ENABLED or (sound_ENABLED and PYTHON3):
     344    external_includes += ["gi"]
     345elif gtk2_ENABLED or x11_ENABLED:
     346    external_includes += "cairo", "pango", "pangocairo", "atk", "glib", "gobject", "gio", "gtk.keysyms"
    205347
    206348external_excludes = [
     
    212354                    "GimpGradientFile", "GimpPaletteFile", "BmpImagePlugin", "TiffImagePlugin",
    213355                    #not used:
    214                     "curses", "email", "mimetypes", "mimetools", "pdb",
    215                     "urllib", "urllib2", "tty",
    216                     "ssl", "_ssl",
    217                     "cookielib", "BaseHTTPServer", "ftplib", "httplib", "fileinput",
    218                     "distutils", "setuptools", "doctest"
     356                    "curses", "pdb",
     357                    "tty",
     358                    "setuptools", "doctest"
    219359                    ]
    220 
     360if not html5_ENABLED and not crypto_ENABLED:
     361    external_excludes += ["ssl", "_ssl"]
     362if not html5_ENABLED:
     363    external_excludes += ["BaseHTTPServer", "mimetypes", "mimetools"]
     364
     365if not client_ENABLED and not server_ENABLED:
     366    excludes += ["PIL"]
     367if not dbus_ENABLED:
     368    excludes += ["dbus"]
    221369
    222370
    223371#because of differences in how we specify packages and modules
    224 #for distutils / py2app and py2exe
     372#for distutils / py2app and cx_freeze
    225373#use the following functions, which should get the right
    226374#data in the global variables "packages", "modules" and "excludes"
     
    253401
    254402def add_modules(*mods):
     403    def add(v):
     404        global modules
     405        if v not in modules:
     406            modules.append(v)
     407    do_add_modules(add, *mods)
     408
     409def do_add_modules(op, *mods):
    255410    """ adds the packages and any .py module found in the packages to the "modules" list
    256411    """
    257412    global modules
    258413    for x in mods:
    259         if x not in modules:
    260             modules.append(x)
     414        #ugly path stripping:
     415        if x.startswith("./"):
     416            x = x[2:]
     417        if x.endswith(".py"):
     418            x = x[:-3]
     419            x = x.replace("/", ".") #.replace("\\", ".")
    261420        pathname = os.path.sep.join(x.split("."))
     421        #is this a file module?
     422        f = "%s.py" % pathname
     423        if os.path.exists(f) and os.path.isfile(f):
     424            op(x)
    262425        if os.path.exists(pathname) and os.path.isdir(pathname):
    263426            #add all file modules found in this directory
    264427            for f in os.listdir(pathname):
    265                 if f.endswith(".py") and f.find("Copy ")<0:
     428                #make sure we only include python files,
     429                #and ignore eclipse copies
     430                if f.endswith(".py") and not f.startswith("Copy ")<0:
    266431                    fname = os.path.join(pathname, f)
    267432                    if os.path.isfile(fname):
    268433                        modname = "%s.%s" % (x, f.replace(".py", ""))
    269                         modules.append(modname)
     434                        op(modname)
    270435
    271436def toggle_packages(enabled, *module_names):
     
    275440        remove_packages(*module_names)
    276441
     442def toggle_modules(enabled, *module_names):
     443    if enabled:
     444        def op(v):
     445            global modules
     446            if v not in modules:
     447                modules.append(v)
     448        do_add_modules(op, *module_names)
     449    else:
     450        remove_packages(*module_names)
     451
     452
    277453#always included:
    278 add_modules("xpra",
    279             "xpra.platform",
    280             "xpra.codecs",
    281             "xpra.codecs.xor")
    282 add_packages("xpra.scripts", "xpra.keyboard", "xpra.net")
    283 
     454add_modules("xpra", "xpra.platform", "xpra.net")
     455add_modules("xpra.scripts.main")
     456
     457
     458def add_data_files(target_dir, files):
     459    #this is overriden below because cx_freeze uses the opposite structure (files first...). sigh.
     460    assert type(target_dir)==str
     461    assert type(files) in (list, tuple)
     462    data_files.append((target_dir, files))
     463
     464
     465#for pretty printing of options:
     466def print_option(prefix, k, v):
     467    if type(v)==dict:
     468        print("%s* %s:" % (prefix, k))
     469        for kk,vv in v.items():
     470            print_option(" "+prefix, kk, vv)
     471    else:
     472        print("%s* %s=%s" % (prefix, k, v))
    284473
    285474#*******************************************************************************
    286475# Utility methods for building with Cython
    287476def cython_version_check(min_version):
    288     try:
    289         from Cython.Compiler.Version import version as cython_version
    290     except ImportError, e:
    291         sys.exit("ERROR: Cannot find Cython: %s" % e)
    292477    from distutils.version import LooseVersion
    293478    if LooseVersion(cython_version) < LooseVersion(".".join([str(x) for x in min_version])):
     
    297482                 % (cython_version, ".".join([str(part) for part in min_version])))
    298483
    299 def cython_add(extension, min_version=(0, 14, 0)):
     484def cython_add(extension, min_version=(0, 19)):
    300485    #gentoo does weird things, calls --no-compile with build *and* install
    301486    #then expects to find the cython modules!? ie:
     
    303488    if "--no-compile" in sys.argv and not ("build" in sys.argv and "install" in sys.argv):
    304489        return
    305     global ext_modules, cmdclass
    306490    cython_version_check(min_version)
    307491    from Cython.Distutils import build_ext
    308492    ext_modules.append(extension)
    309     cmdclass = {'build_ext': build_ext}
     493    global cmdclass
     494    cmdclass['build_ext'] = build_ext
     495
     496def insert_into_keywords(kw, key, *args):
     497    values = kw.setdefault(key, [])
     498    for arg in args:
     499        values.insert(0, arg)
    310500
    311501def add_to_keywords(kw, key, *args):
     
    319509
    320510
     511def checkdirs(*dirs):
     512    for d in dirs:
     513        if not os.path.exists(d) or not os.path.isdir(d):
     514            raise Exception("cannot find a directory which is required for building: '%s'" % d)
     515
    321516PYGTK_PACKAGES = ["pygobject-2.0", "pygtk-2.0"]
     517#override the pkgconfig file,
     518#we don't need to link against any of these:
     519gtk2_ignored_tokens=[("-l%s" % x) for x in
     520                     ["fontconfig", "freetype", "cairo",
     521                      "atk-1.0", "pangoft2-1.0", "pango-1.0", "pangocairo-1.0",
     522                      "gio-2.0", "gdk_pixbuf-2.0"]]
    322523
    323524GCC_VERSION = []
     
    326527    if len(GCC_VERSION)==0:
    327528        cmd = [os.environ.get("CC", "gcc"), "-v"]
    328         proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    329         output, _ = proc.communicate()
    330         status = proc.wait()
    331         if status==0:
     529        r, _, err = get_status_output(cmd)
     530        if r==0:
    332531            V_LINE = "gcc version "
    333             for line in output.decode("utf8").splitlines():
     532            for line in err.splitlines():
    334533                if line.startswith(V_LINE):
    335534                    v_str = line[len(V_LINE):].split(" ")[0]
     
    343542    return GCC_VERSION
    344543
    345 def make_constants_pxi(constants_path, pxi_path):
     544def make_constants_pxi(constants_path, pxi_path, **kwargs):
    346545    constants = []
    347     for line in open(constants_path):
    348         data = line.split("#", 1)[0].strip()
    349         # data can be empty ''...
    350         if not data:
    351             continue
    352         # or a pair like 'cFoo "Foo"'...
    353         elif len(data.split()) == 2:
    354             (pyname, cname) = data.split()
    355             constants.append((pyname, cname))
    356         # or just a simple token 'Foo'
    357         else:
    358             constants.append(data)
    359     out = open(pxi_path, "w")
    360     out.write("cdef extern from *:\n")
    361     ### Apparently you can't use | on enum's?!
    362     # out.write("    enum MagicNumbers:\n")
    363     # for const in constants:
    364     #     if isinstance(const, tuple):
    365     #         out.write('        %s %s\n' % const)
    366     #     else:
    367     #         out.write('        %s\n' % (const,))
    368     for const in constants:
    369         if isinstance(const, tuple):
    370             out.write('    unsigned int %s %s\n' % const)
    371         else:
    372             out.write('    unsigned int %s\n' % (const,))
    373 
    374     out.write("constants = {\n")
    375     for const in constants:
    376         if isinstance(const, tuple):
    377             pyname = const[0]
    378         else:
    379             pyname = const
    380         out.write('    "%s": %s,\n' % (pyname, pyname))
    381     out.write("}\n")
    382 
    383 def make_constants(*paths):
     546    with open(constants_path) as f:
     547        for line in f:
     548            data = line.split("#", 1)[0].strip()
     549            # data can be empty ''...
     550            if not data:
     551                continue
     552            # or a pair like 'cFoo "Foo"'...
     553            elif len(data.split()) == 2:
     554                (pyname, cname) = data.split()
     555                constants.append((pyname, cname))
     556            # or just a simple token 'Foo'
     557            else:
     558                constants.append(data)
     559
     560    with open(pxi_path, "w") as out:
     561        if constants:
     562            out.write("cdef extern from *:\n")
     563            ### Apparently you can't use | on enum's?!
     564            # out.write("    enum MagicNumbers:\n")
     565            # for const in constants:
     566            #     if isinstance(const, tuple):
     567            #         out.write('        %s %s\n' % const)
     568            #     else:
     569            #         out.write('        %s\n' % (const,))
     570            for const in constants:
     571                if isinstance(const, tuple):
     572                    out.write('    unsigned int %s %s\n' % const)
     573                else:
     574                    out.write('    unsigned int %s\n' % (const,))
     575
     576            out.write("constants = {\n")
     577            for const in constants:
     578                if isinstance(const, tuple):
     579                    pyname = const[0]
     580                else:
     581                    pyname = const
     582                out.write('    "%s": %s,\n' % (pyname, pyname))
     583            out.write("}\n")
     584            if kwargs:
     585                out.write("\n\n")
     586
     587        if kwargs:
     588            for k, v in kwargs.items():
     589                out.write('DEF %s = %s\n' % (k, v))
     590
     591
     592def should_rebuild(src_file, bin_file):
     593    if not os.path.exists(bin_file):
     594        return "no file"
     595    elif rebuild_ENABLED:
     596        if os.path.getctime(bin_file)<os.path.getctime(src_file):
     597            return "binary file out of date"
     598        elif os.path.getctime(bin_file)<os.path.getctime(__file__):
     599            return "newer build file"
     600    return None
     601
     602def make_constants(*paths, **kwargs):
    384603    base = os.path.join(os.getcwd(), *paths)
    385604    constants_file = "%s.txt" % base
    386605    pxi_file = "%s.pxi" % base
    387     reason = None
    388     if not os.path.exists(pxi_file):
    389         reason = "no pxi file"
    390     elif os.path.getctime(pxi_file)<os.path.getctime(constants_file):
    391         reason = "pxi file out of date"
    392     elif os.path.getctime(pxi_file)<os.path.getctime(__file__):
    393         reason = "newer build file"
     606    reason = should_rebuild(constants_file, pxi_file)
    394607    if reason:
    395608        if verbose_ENABLED:
    396609            print("(re)generating %s (%s):" % (pxi_file, reason))
    397         make_constants_pxi(constants_file, pxi_file)
    398 
    399 
    400 def static_link_args(*libnames):
    401     return ["-Wl,-Bstatic"] + ["-l%s" % x for x in libnames] + ["-Wl,-Bsymbolic", "-Wl,-Bdynamic"]
    402 
    403 def get_static_pkgconfig(*libnames):
    404     defs = pkgconfig()
    405     remove_from_keywords(defs, 'extra_compile_args', '-fsanitize=address')
    406     if os.name=="posix":
    407         if debug_ENABLED:
    408             add_to_keywords(defs, 'extra_link_args', "-Wl,--verbose")
    409         defs.update({'include_dirs': ["/usr/local/include"],
    410                      'library_dirs': ["/usr/local/lib", "/usr/local/lib64"]})
    411     if len(libnames)>0:
    412         add_to_keywords(defs,  'extra_link_args', *static_link_args(*libnames))
    413     return defs
     610        make_constants_pxi(constants_file, pxi_file, **kwargs)
     611
    414612
    415613# Tweaked from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502261
    416 def pkgconfig(*pkgs_options, **ekw):
    417     static = ekw.get("static", None)
    418     if static is not None:
    419         del ekw["static"]
    420         if static:
    421             return get_static_pkgconfig(*pkgs_options)
    422 
     614def exec_pkgconfig(*pkgs_options, **ekw):
    423615    kw = dict(ekw)
     616    if "optimize" in kw:
     617        optimize = kw["optimize"]
     618        del kw["optimize"]
     619        if type(optimize)==bool:
     620            optimize = int(optimize)*3
     621        if not debug_ENABLED:
     622            add_to_keywords(kw, 'extra_compile_args', "-O%i" % optimize)
     623    ignored_flags = kw.pop("ignored_flags", [])
     624    ignored_tokens = kw.pop("ignored_tokens", [])
     625
    424626    if len(pkgs_options)>0:
    425627        package_names = []
     
    438640            for option in options:
    439641                cmd = ["pkg-config", "--exists", option]
    440                 proc = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    441                 status = proc.wait()
    442                 if status==0:
     642                r, _, _ = get_status_output(cmd)
     643                if r==0:
    443644                    valid_option = option
    444645                    break
    445646            if not valid_option:
    446                 sys.exit("ERROR: cannot find a valid pkg-config package for %s" % (options,))
     647                raise Exception("ERROR: cannot find a valid pkg-config entry for %s using PKG_CONFIG_PATH=%s" % (" or ".join(options), os.environ.get("PKG_CONFIG_PATH", "(empty)")))
    447648            package_names.append(valid_option)
    448649        if verbose_ENABLED and list(pkgs_options)!=list(package_names):
    449             print("pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
     650            print("exec_pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
    450651        flag_map = {'-I': 'include_dirs',
    451652                    '-L': 'library_dirs',
    452653                    '-l': 'libraries'}
    453         cmd = ["pkg-config", "--libs", "--cflags", "%s" % (" ".join(package_names),)]
    454         proc = subprocess.Popen(cmd, env=os.environ, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    455         (output, _) = proc.communicate()
    456         status = proc.wait()
    457         if status!=0:
    458             sys.exit("ERROR: call to pkg-config ('%s') failed" % " ".join(cmd))
    459         if sys.version>='3':
    460             output = output.decode('utf-8')
    461         for token in output.split():
    462             if token[:2] in flag_map:
    463                 add_to_keywords(kw, flag_map.get(token[:2]), token[2:])
    464             else: # throw others to extra_link_args
    465                 add_to_keywords(kw, 'extra_link_args', token)
    466             for k, v in kw.items(): # remove duplicates
    467                 kw[k] = list(set(v))
     654        pkg_config_cmd = ["pkg-config", "--libs", "--cflags", "%s" % (" ".join(package_names),)]
     655        r, pkg_config_out, err = get_status_output(pkg_config_cmd)
     656        if r!=0:
     657            sys.exit("ERROR: call to '%s' failed (err=%s)" % (" ".join(cmd), err))
     658        env_cflags = os.environ.get("CFLAGS")       #["dpkg-buildflags", "--get", "CFLAGS"]
     659        env_ldflags = os.environ.get("LDFLAGS")     #["dpkg-buildflags", "--get", "LDFLAGS"]
     660        for s in (pkg_config_out, env_cflags, env_ldflags):
     661            if not s:
     662                continue
     663            for token in s.split():
     664                if token in ignored_tokens:
     665                    pass
     666                elif token[:2] in ignored_flags:
     667                    pass
     668                elif token[:2] in flag_map:
     669                    add_to_keywords(kw, flag_map.get(token[:2]), token[2:])
     670                elif token.startswith("-W"):
     671                    add_to_keywords(kw, 'extra_compile_args', token)
     672                else:# throw others to extra_link_args
     673                    add_to_keywords(kw, 'extra_link_args', token)
    468674    if warn_ENABLED:
    469675        add_to_keywords(kw, 'extra_compile_args', "-Wall")
    470676        add_to_keywords(kw, 'extra_link_args', "-Wall")
    471677    if strict_ENABLED:
    472         #these are almost certainly real errors since our code is "clean":
    473         if get_gcc_version()>=[4, 4]:
    474             eifd = "-Werror=implicit-function-declaration"
     678        if os.environ.get("CC", "").find("clang")>=0:
     679            #clang emits too many warnings with cython code,
     680            #so we can't enable Werror without turning off some warnings:
     681            #this list of flags should allow clang to build the whole source tree,
     682            #as of Cython 0.26 + clang 4.0. Other version combinations may require
     683            #(un)commenting other switches.
     684            eifd = ["-Werror",
     685                    #"-Wno-unneeded-internal-declaration",
     686                    #"-Wno-unknown-attributes",
     687                    #"-Wno-unused-function",
     688                    #"-Wno-self-assign",
     689                    #"-Wno-sometimes-uninitialized",
     690                    #cython adds rpath to the compilation command??
     691                    #and the "-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1" is also ignored by clang:
     692                    "-Wno-unused-command-line-argument",
     693                    ]
     694        elif get_gcc_version()>=[4, 4]:
     695            eifd = ["-Werror"]
     696            if is_Debian() or is_Ubuntu() or is_Raspbian():
     697                #needed on Debian and Ubuntu to avoid this error:
     698                #/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47:1: error: function declaration isn't a prototype [-Werror=strict-prototypes]
     699                eifd.append("-Wno-error=strict-prototypes")
     700            if NETBSD:
     701                #see: http://trac.cython.org/ticket/395
     702                eifd += ["-fno-strict-aliasing"]
     703            elif FREEBSD:
     704                eifd += ["-Wno-error=unused-function"]
    475705        else:
    476             eifd = "-Werror-implicit-function-declaration"
    477         add_to_keywords(kw, 'extra_compile_args', eifd)
     706            #older versions of OSX ship an old gcc,
     707            #not much we can do with this:
     708            eifd = []
     709        for eif in eifd:
     710            add_to_keywords(kw, 'extra_compile_args', eif)
    478711    if PIC_ENABLED:
    479712        add_to_keywords(kw, 'extra_compile_args', "-fPIC")
     
    481714        add_to_keywords(kw, 'extra_compile_args', '-g')
    482715        add_to_keywords(kw, 'extra_compile_args', '-ggdb')
    483         kw['cython_gdb'] = True
    484         if get_gcc_version()>=4.8:
     716        if get_gcc_version()>=[4, 8]:
    485717            add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address')
    486718            add_to_keywords(kw, 'extra_link_args', '-fsanitize=address')
     719    if rpath and kw.get("libraries"):
     720        insert_into_keywords(kw, "library_dirs", rpath)
     721        insert_into_keywords(kw, "extra_link_args", "-Wl,-rpath=%s" % rpath)
    487722    #add_to_keywords(kw, 'include_dirs', '.')
    488723    if verbose_ENABLED:
    489         print("pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
     724        print("exec_pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
    490725    return kw
     726pkgconfig = exec_pkgconfig
    491727
    492728
    493729#*******************************************************************************
    494 def get_xorg_conf_and_script():
    495     if not server_ENABLED:
    496         return "etc/xpra/client-only/xpra.conf", False
    497 
    498     def Xvfb():
    499         return "etc/xpra/Xvfb/xpra.conf", False
    500 
    501     if sys.platform.find("bsd")>=0:
    502         print("Warning: sorry, no support for Xdummy on %s" % sys.platform)
    503         return Xvfb()
    504 
    505     XORG_BIN = None
    506     PATHS = os.environ.get("PATH").split(os.pathsep)
    507     for x in PATHS:
    508         xorg = os.path.join(x, "Xorg")
    509         if os.path.isfile(xorg):
    510             XORG_BIN = xorg
    511             break
    512     if not XORG_BIN:
    513         print("Xorg not found, cannot detect version or Xdummy support")
    514         return Xvfb()
    515 
    516     def Xorg_suid_check():
    517         xorg_stat = os.stat(XORG_BIN)
    518         if (xorg_stat.st_mode & stat.S_ISUID)!=0:
    519             if (xorg_stat.st_mode & stat.S_IROTH)==0:
    520                 print("Xorg is suid and not readable, Xdummy support unavailable")
    521                 return Xvfb()
    522             print("%s is suid and readable, using the xpra_Xdummy wrapper" % XORG_BIN)
    523             return "etc/xpra/xpra_Xdummy/xpra.conf", True
    524         else:
    525             print("using Xdummy config file")
    526             return "etc/xpra/Xdummy/xpra.conf", False
    527 
    528     if Xdummy_ENABLED is False:
    529         return Xvfb()
    530     elif Xdummy_ENABLED is True:
    531         print("Xdummy support specified as 'enabled', will detect suid mode")
    532         return Xorg_suid_check()
     730
     731
     732def get_base_conf_dir(install_dir, stripbuildroot=True):
     733    #in some cases we want to strip the buildroot (to generate paths in the config file)
     734    #but in other cases we want the buildroot path (when writing out the config files)
     735    #and in some cases, we don't have the install_dir specified (called from detect_xorg_setup, and that's fine too)
     736    #this is a bit hackish, but I can't think of a better way of detecting it
     737    #(ie: "$HOME/rpmbuild/BUILDROOT/xpra-0.15.0-0.fc21.x86_64/usr")
     738    dirs = (install_dir or sys.prefix).split(os.path.sep)
     739    if install_dir and stripbuildroot:
     740        pkgdir = os.environ.get("pkgdir")
     741        if "debian" in dirs and "tmp" in dirs:
     742            #ugly fix for stripping the debian tmp dir:
     743            #ie: "???/tmp/???/tags/v0.15.x/src/debian/tmp/" -> ""
     744            while "tmp" in dirs:
     745                dirs = dirs[dirs.index("tmp")+1:]
     746        elif "debian" in dirs:
     747            #same for recent debian versions:
     748            #ie: "xpra-2.0.2/debian/xpra/usr" -> "usr"
     749            i = dirs.index("debian")
     750            if dirs[i+1] == "xpra":
     751                dirs = dirs[i+2:]
     752        elif "BUILDROOT" in dirs:
     753            #strip rpm style build root:
     754            #[$HOME, "rpmbuild", "BUILDROOT", "xpra-$VERSION"] -> []
     755            dirs = dirs[dirs.index("BUILDROOT")+2:]
     756        elif pkgdir and install_dir.startswith(pkgdir):
     757            #arch build dir:
     758            dirs = install_dir.lstrip(pkgdir).split(os.path.sep)
     759        elif "usr" in dirs:
     760            #ie: ["some", "path", "to", "usr"] -> ["usr"]
     761            #assume "/usr" or "/usr/local" is the build root
     762            while "usr" in dirs[1:]:
     763                dirs = dirs[dirs[1:].index("usr")+1:]
     764        elif "image" in dirs:
     765            # Gentoo's "${PORTAGE_TMPDIR}/portage/${CATEGORY}/${PF}/image/_python2.7" -> ""
     766            while "image" in dirs:
     767                dirs = dirs[dirs.index("image")+2:]
     768    #now deal with the fact that "/etc" is used for the "/usr" prefix
     769    #but "/usr/local/etc" is used for the "/usr/local" prefix..
     770    if dirs and dirs[-1]=="usr":
     771        dirs = dirs[:-1]
     772    #is this an absolute path?
     773    if len(dirs)==0 or dirs[0]=="usr" or (install_dir or sys.prefix).startswith(os.path.sep):
     774        #ie: ["/", "usr"] or ["/", "usr", "local"]
     775        dirs.insert(0, os.path.sep)
     776    return dirs
     777
     778def get_conf_dir(install_dir, stripbuildroot=True):
     779    dirs = get_base_conf_dir(install_dir, stripbuildroot)
     780    dirs.append("etc")
     781    dirs.append("xpra")
     782    return os.path.join(*dirs)
     783
     784def detect_xorg_setup(install_dir=None):
     785    from xpra.scripts import config
     786    config.debug = config.warn
     787    conf_dir = get_conf_dir(install_dir)
     788    return config.detect_xvfb_command(conf_dir, None, Xdummy_ENABLED, Xdummy_wrapper_ENABLED)
     789
     790def build_xpra_conf(install_dir):
     791    #generates an actual config file from the template
     792    xvfb_command = detect_xorg_setup(install_dir)
     793    from xpra.platform.features import DEFAULT_ENV
     794    def bstr(b):
     795        if b is None:
     796            return "auto"
     797        return ["no", "yes"][int(b)]
     798    start_env = "\n".join("start-env = %s" % x for x in DEFAULT_ENV)
     799    conf_dir = get_conf_dir(install_dir)
     800    from xpra.platform.features import DEFAULT_SSH_COMMAND, DEFAULT_PULSEAUDIO_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS
     801    from xpra.platform.paths import get_socket_dirs
     802    from xpra.scripts.config import get_default_key_shortcuts, get_default_systemd_run, DEFAULT_POSTSCRIPT_PRINTER, DEFAULT_PULSEAUDIO
     803    #remove build paths and user specific paths with UID ("/run/user/UID/Xpra"):
     804    socket_dirs = get_socket_dirs()
     805    if WIN32:
     806        bind = "Main"
    533807    else:
    534         print("Xdummy support unspecified, will try to detect")
    535 
    536     cmd = ["lsb_release", "-cs"]
    537     try:
    538         proc = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    539         out, _ = proc.communicate()
    540         release = out.replace("\n", "")
    541         print("Found OS release: %s" % release)
    542         if release in ("raring", "saucy"):
    543             #yet another instance of Ubuntu breaking something
    544             print("Warning: Ubuntu '%s' breaks Xorg/Xdummy usage - using Xvfb fallback" % release)
    545             return  Xvfb()
    546     except Exception, e:
    547         print("failed to detect OS release using %s: %s" % (" ".join(cmd), e))
    548 
    549     #do live detection
    550     cmd = ["Xorg", "-version"]
    551     if verbose_ENABLED:
    552         print("detecting Xorg version using: %s" % str(cmd))
    553     try:
    554         proc = subprocess.Popen(cmd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    555         out, _ = proc.communicate()
    556         V_LINE = "X.Org X Server "
    557         xorg_version = None
    558         for line in out.decode("utf8").splitlines():
    559             if line.startswith(V_LINE):
    560                 v_str = line[len(V_LINE):]
    561                 xorg_version = [int(x) for x in v_str.split(".")[:2]]
    562                 break
    563         if not xorg_version:
    564             print("Xorg version could not be detected, Xdummy support unavailable")
    565             return Xvfb()
    566         if xorg_version<[1, 12]:
    567             print("Xorg version %s is too old (1.12 or later required), Xdummy support not available" % v_str)
    568             return Xvfb()
    569         print("found valid recent version of Xorg server: %s" % v_str)
    570         return Xorg_suid_check()
    571     except Exception, e:
    572         print("failed to detect Xorg version: %s" % e)
    573         print("not installing Xdummy support")
    574         traceback.print_exc()
    575         return  Xvfb()
     808        if os.getuid()>0:
     809            #remove any paths containing the uid,
     810            #osx uses /var/tmp/$UID-Xpra,
     811            #but this should not be included in the default config for all users!
     812            #(the buildbot's uid!)
     813            socket_dirs = [x for x in socket_dirs if x.find(str(os.getuid()))<0]
     814        bind = "auto"
     815    #FIXME: we should probably get these values from the default config instead
     816    pdf, postscript = "", ""
     817    if POSIX and printing_ENABLED:
     818        try:
     819            if "/usr/sbin" not in sys.path:
     820                sys.path.append("/usr/sbin")
     821            from xpra.platform.pycups_printing import get_printer_definition
     822            print("probing cups printer definitions")
     823            pdf = get_printer_definition("pdf")
     824            postscript = get_printer_definition("postscript") or DEFAULT_POSTSCRIPT_PRINTER
     825            print("pdf=%s, postscript=%s" % (pdf, postscript))
     826        except Exception as e:
     827            print("could not probe for pdf/postscript printers: %s" % e)
     828    def pretty_cmd(cmd):
     829        return " ".join(cmd)
     830    #OSX doesn't have webcam support yet (no opencv builds on 10.5.x)
     831    #Ubuntu 16.10 has opencv builds that conflict with our private ffmpeg
     832    webcam = webcam_ENABLED and not (OSX or getUbuntuVersion()==[16, 10])
     833    #no python-avahi on RH / CentOS, need dbus module on *nix:
     834    mdns = mdns_ENABLED and (OSX or WIN32 or (not is_RH() and dbus_ENABLED))
     835    SUBS = {
     836            'xvfb_command'          : pretty_cmd(xvfb_command),
     837            'ssh_command'           : DEFAULT_SSH_COMMAND,
     838            'key_shortcuts'         : "".join(("key-shortcut = %s\n" % x) for x in get_default_key_shortcuts()),
     839            'remote_logging'        : "both",
     840            'start_env'             : start_env,
     841            'pulseaudio'            : bstr(DEFAULT_PULSEAUDIO),
     842            'pulseaudio_command'    : pretty_cmd(DEFAULT_PULSEAUDIO_COMMAND),
     843            'pulseaudio_configure_commands' : "\n".join(("pulseaudio-configure-commands = %s" % pretty_cmd(x)) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS),
     844            'conf_dir'              : conf_dir,
     845            'bind'                  : bind,
     846            'ssl_cert'              : ssl_cert or "",
     847            'ssl_key'               : ssl_key or "",
     848            'systemd_run'           : get_default_systemd_run(),
     849            'socket_dirs'           : "".join(("socket-dirs = %s\n" % x) for x in socket_dirs),
     850            'log_dir'               : "auto",
     851            'mdns'                  : bstr(mdns),
     852            'notifications'         : bstr(OSX or WIN32 or dbus_ENABLED),
     853            'dbus_proxy'            : bstr(not OSX and not WIN32 and dbus_ENABLED),
     854            'pdf_printer'           : pdf,
     855            'postscript_printer'    : postscript,
     856            'webcam'                : ["no", "auto"][webcam],
     857            'mousewheel'            : "on",
     858            'printing'              : printing_ENABLED,
     859            'dbus_control'          : bstr(dbus_ENABLED),
     860            'mmap'                  : bstr(True),
     861            }
     862    def convert_templates(subdirs=[]):
     863        dirname = os.path.join(*(["etc", "xpra"] + subdirs))
     864        #get conf dir for install, without stripping the build root
     865        target_dir = os.path.join(get_conf_dir(install_dir, stripbuildroot=False), *subdirs)
     866        print("convert_templates(%s) dirname=%s, target_dir=%s" % (subdirs, dirname, target_dir))
     867        if not os.path.exists(target_dir):
     868            try:
     869                os.makedirs(target_dir)
     870            except Exception as e:
     871                print("cannot create target dir '%s': %s" % (target_dir, e))
     872        for f in sorted(os.listdir(dirname)):
     873            if f.endswith("osx.conf.in") and not OSX:
     874                continue
     875            filename = os.path.join(dirname, f)
     876            if os.path.isdir(filename):
     877                convert_templates(subdirs+[f])
     878                continue
     879            if not f.endswith(".in"):
     880                continue
     881            with open(filename, "r") as f_in:
     882                template  = f_in.read()
     883            target_file = os.path.join(target_dir, f[:-len(".in")])
     884            print("generating %s from %s" % (target_file, f))
     885            with open(target_file, "w") as f_out:
     886                config_data = template % SUBS
     887                f_out.write(config_data)
     888    convert_templates()
    576889
    577890
     
    580893    #clean and sdist don't actually use cython,
    581894    #so skip this (and avoid errors)
    582     def pkgconfig(*pkgs_options, **ekw):
    583         return {}
     895    pkgconfig = no_pkgconfig
    584896    #always include everything in this case:
    585897    add_packages("xpra")
    586898    #ensure we remove the files we generate:
    587899    CLEAN_FILES = [
    588                    "xpra/gtk_common/gdk_atoms.c",
    589                    "xpra/x11/gtk_x11/constants.pxi",
    590                    "xpra/x11/gtk_x11/gdk_bindings.c",
    591                    "xpra/x11/gtk_x11/gdk_display_source.c",
     900                   "xpra/build_info.py",
     901                   "xpra/monotonic_time.c",
     902                   "xpra/gtk_common/gtk2/gdk_atoms.c",
     903                   "xpra/gtk_common/gtk2/gdk_bindings.c",
     904                   "xpra/gtk_common/gtk3/gdk_atoms.c",
     905                   "xpra/x11/gtk2/constants.pxi",
     906                   "xpra/x11/gtk2/gdk_bindings.c",
     907                   "xpra/x11/gtk2/gdk_display_source.c",
     908                   "xpra/x11/gtk3/gdk_display_source.c",
    592909                   "xpra/x11/bindings/constants.pxi",
    593910                   "xpra/x11/bindings/wait_for_x_server.c",
     
    597914                   "xpra/x11/bindings/randr_bindings.c",
    598915                   "xpra/x11/bindings/core_bindings.c",
     916                   "xpra/x11/bindings/posix_display_source.c",
    599917                   "xpra/x11/bindings/ximage.c",
    600                    "xpra/net/rencode/rencode.c",
     918                   "xpra/x11/bindings/xi2_bindings.c",
     919                   "xpra/platform/win32/propsys.cpp",
     920                   "xpra/platform/darwin/gdk_bindings.c",
     921                   "xpra/platform/xposix/sd_listen.c",
     922                   "xpra/platform/xposix/netdev_query.c",
     923                   "xpra/net/bencode/cython_bencode.c",
     924                   "xpra/net/vsock.c",
     925                   "xpra/buffers/membuf.c",
    601926                   "xpra/codecs/vpx/encoder.c",
    602927                   "xpra/codecs/vpx/decoder.c",
    603928                   "xpra/codecs/nvenc/encoder.c",
    604                    "xpra/codecs/nvenc/constants.pxi",
     929                   "xpra/codecs/nvfbc/fbc_capture_linux.cpp",
     930                   "xpra/codecs/nvfbc/fbc_capture_win.cpp",
     931                   "xpra/codecs/cuda_common/ARGB_to_NV12.fatbin",
     932                   "xpra/codecs/cuda_common/ARGB_to_YUV444.fatbin",
     933                   "xpra/codecs/cuda_common/BGRA_to_NV12.fatbin",
     934                   "xpra/codecs/cuda_common/BGRA_to_YUV444.fatbin",
    605935                   "xpra/codecs/enc_x264/encoder.c",
    606936                   "xpra/codecs/enc_x265/encoder.c",
     937                   "xpra/codecs/jpeg/encoder.c",
     938                   "xpra/codecs/jpeg/decoder.c",
     939                   "xpra/codecs/enc_ffmpeg/encoder.c",
     940                   "xpra/codecs/v4l2/constants.pxi",
     941                   "xpra/codecs/v4l2/pusher.c",
     942                   "xpra/codecs/libav_common/av_log.c",
    607943                   "xpra/codecs/webp/encode.c",
    608                    "xpra/codecs/dec_avcodec/decoder.c",
    609                    "xpra/codecs/dec_avcodec/constants.pxi",
     944                   "xpra/codecs/webp/decode.c",
    610945                   "xpra/codecs/dec_avcodec2/decoder.c",
     946                   "xpra/codecs/csc_libyuv/colorspace_converter.cpp",
    611947                   "xpra/codecs/csc_swscale/colorspace_converter.c",
    612                    "xpra/codecs/csc_swscale/constants.pxi",
    613                    "xpra/codecs/csc_cython/colorspace_converter.c",
    614948                   "xpra/codecs/xor/cyxor.c",
    615949                   "xpra/codecs/argb/argb.c",
    616                    "xpra/server/stats/cymaths.c",
    617                    "etc/xpra/xpra.conf"]
    618     if sys.platform.startswith("win"):
    619         #on win32, the build creates ".pyd" files, clean those too:
    620         for x in list(CLEAN_FILES):
    621             if x.endswith(".c"):
    622                 CLEAN_FILES.append(x[:-2]+".pyd")
     950                   "xpra/codecs/nvapi_version.c",
     951                   "xpra/gtk_common/gdk_atoms.c",
     952                   "xpra/client/gtk3/cairo_workaround.c",
     953                   "xpra/server/cystats.c",
     954                   "xpra/server/window/region.c",
     955                   "xpra/server/window/motion.c",
     956                   "xpra/server/pam.c",
     957                   "etc/xpra/xpra.conf",
     958                   #special case for the generated xpra conf files in build (see #891):
     959                   "build/etc/xpra/xpra.conf"] + glob.glob("build/etc/xpra/conf.d/*.conf")
     960    for x in CLEAN_FILES:
     961        p, ext = os.path.splitext(x)
     962        if ext in (".c", ".cpp", ".pxi"):
     963            #clean the Cython annotated html files:
     964            CLEAN_FILES.append(p+".html")
     965            if WIN32 and ext!=".pxi":
     966                #on win32, the build creates ".pyd" files, clean those too:
     967                CLEAN_FILES.append(p+".pyd")
     968                #when building with python3, we need to clean files named like:
     969                #"xpra/codecs/csc_libyuv/colorspace_converter-cpython-36m.dll"
     970                filename = os.path.join(os.getcwd(), p.replace("/", os.path.sep)+"*.dll")
     971                CLEAN_FILES += glob.glob(filename)
    623972    if 'clean' in sys.argv:
    624973        CLEAN_FILES.append("xpra/build_info.py")
     
    630979            os.unlink(filename)
    631980
    632 from add_build_info import record_build_info, record_src_info, has_src_info
     981from add_build_info import record_build_info, BUILD_INFO_FILE, record_src_info, SRC_INFO_FILE, has_src_info
    633982
    634983if "clean" not in sys.argv:
    635984    # Add build info to build_info.py file:
    636985    record_build_info()
     986    # ensure it is included in the module list if it didn't exist before
     987    add_modules(BUILD_INFO_FILE)
    637988
    638989if "sdist" in sys.argv:
    639990    record_src_info()
    640991
    641 if "install" in sys.argv:
     992if "install" in sys.argv or "build" in sys.argv:
    642993    #if installing from source tree rather than
    643994    #from a source snapshot, we may not have a "src_info" file
     
    645996    if not has_src_info():
    646997        record_src_info()
     998        # ensure it is now included in the module list
     999        add_modules(SRC_INFO_FILE)
    6471000
    6481001
     
    6631016    return m
    6641017
     1018
     1019def install_html5(install_dir="www"):
     1020    from setup_html5 import install_html5 as do_install_html5
     1021    do_install_html5(install_dir, minifier, html5_gzip_ENABLED, html5_brotli_ENABLED, verbose_ENABLED)
     1022
     1023
    6651024#*******************************************************************************
    6661025if WIN32:
    667     # The Microsoft C library DLLs:
    668     # Unfortunately, these files cannot be re-distributed legally :(
    669     # So here is the md5sum so you can find the right version:
    670     # (you can find them in various packages, including Visual Studio 2008,
    671     # pywin32, etc...)
    672     import md5
    673     md5sums = {"Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest" : "37f44d535dcc8bf7a826dfa4f5fa319b",
    674                "Microsoft.VC90.CRT/msvcm90.dll"                 : "4a8bc195abdc93f0db5dab7f5093c52f",
    675                "Microsoft.VC90.CRT/msvcp90.dll"                 : "6de5c66e434a9c1729575763d891c6c2",
    676                "Microsoft.VC90.CRT/msvcr90.dll"                 : "e7d91d008fe76423962b91c43c88e4eb",
    677                "Microsoft.VC90.CRT/vcomp90.dll"                 : "f6a85f3b0e30c96c993c69da6da6079e",
    678                "Microsoft.VC90.MFC/Microsoft.VC90.MFC.manifest" : "17683bda76942b55361049b226324be9",
    679                "Microsoft.VC90.MFC/mfc90.dll"                   : "462ddcc5eb88f34aed991416f8e354b2",
    680                "Microsoft.VC90.MFC/mfc90u.dll"                  : "b9030d821e099c79de1c9125b790e2da",
    681                "Microsoft.VC90.MFC/mfcm90.dll"                  : "d4e7c1546cf3131b7d84b39f8da9e321",
    682                "Microsoft.VC90.MFC/mfcm90u.dll"                 : "371226b8346f29011137c7aa9e93f2f6",
    683                }
    684     # This is where I keep them, you will obviously need to change this value:
    685     C_DLLs = "C:\\"
    686     for dll_file, md5sum in md5sums.items():
    687         filename = os.path.join(C_DLLs, *dll_file.split("/"))
    688         if not os.path.exists(filename) or not os.path.isfile(filename):
    689             sys.exit("ERROR: DLL file %s is missing or not a file!" % filename)
    690         sys.stdout.write("* verifying md5sum for %s: " % filename)
    691         f = open(filename, mode='rb')
    692         data = f.read()
    693         f.close()
    694         m = md5.new()
    695         m.update(data)
    696         digest = m.hexdigest()
    697         assert digest==md5sum, "md5 digest for file %s does not match, expected %s but found %s" % (dll_file, md5sum, digest)
    698         sys.stdout.write("OK\n")
    699         sys.stdout.flush()
    700     #this should all be done with pkgconfig...
    701     #but until someone figures this out, the ugly path code below works
    702     #as long as you install in the same place or tweak the paths.
    703 
    704     #first some header crap so codecs can find the inttypes.h
    705     #and stdint.h:
    706     win32_include_dir = os.path.join(os.getcwd(), "win32")
    707 
    708     #cuda:
    709     cuda_path = "C:\\NVIDIA\CUDA\CUDAToolkit"
    710     cuda_include_dir   = os.path.join(cuda_path, "include")
    711     cuda_bin_dir       = os.path.join(cuda_path, "bin")
    712 
    713     #ffmpeg is needed for both swscale and x264:
    714     libffmpeg_path = None
    715     if dec_avcodec_ENABLED:
    716         assert not dec_avcodec2_ENABLED, "cannot enable both dec_avcodec and dec_avcodec2"
    717         libffmpeg_path = "C:\\ffmpeg-win32-bin"
    718     elif dec_avcodec2_ENABLED:
    719         assert not dec_avcodec_ENABLED, "cannot enable both dec_avcodec and dec_avcodec2"
    720         libffmpeg_path = "C:\\ffmpeg2-win32-bin"
    721     else:
    722         if csc_swscale_ENABLED:
    723             for p in ("C:\\ffmpeg2-win32-bin", "C:\\ffmpeg-win32-bin"):
    724                 if os.path.exists(p):
    725                     libffmpeg_path = p
    726             assert libffmpeg_path is not None, "no ffmpeg found, cannot use csc_swscale"
    727     libffmpeg_include_dir   = os.path.join(libffmpeg_path, "include")
    728     libffmpeg_lib_dir       = os.path.join(libffmpeg_path, "lib")
    729     libffmpeg_bin_dir       = os.path.join(libffmpeg_path, "bin")
    730     #x265
    731     x265_path ="C:\\x265"
    732     x265_include_dir    = x265_path
    733     x265_lib_dir        = x265_path
    734     x265_bin_dir        = x265_path
    735     #x264 (direct from build dir.. yuk - sorry!):
    736     x264_path ="C:\\x264"
    737     x264_include_dir    = x264_path
    738     x264_lib_dir        = x264_path
    739     x264_bin_dir        = x264_path
    740     # Same for vpx:
    741     # http://code.google.com/p/webm/downloads/list
    742     #the path after installing may look like this:
    743     #vpx_PATH="C:\\vpx-vp8-debug-src-x86-win32mt-vs9-v1.1.0"
    744     #but we use something more generic, without the version numbers:
    745     vpx_path = ""
    746     for p in ("C:\\vpx-1.3", "C:\\vpx-1.2", "C:\\vpx-1.1", "C:\\vpx-vp8"):
    747         if os.path.exists(p) and os.path.isdir(p):
    748             vpx_path = p
    749             break
    750     vpx_include_dir     = os.path.join(vpx_path, "include")
    751     vpx_lib_dir         = os.path.join(vpx_path, "lib", "Win32")
    752     if os.path.exists(os.path.join(vpx_lib_dir, "vpx.lib")):
    753         vpx_lib_names = ["vpx"]               #for libvpx 1.3.0
    754     elif os.path.exists(os.path.join(vpx_lib_dir, "vpxmd.lib")):
    755         vpx_lib_names = ["vpxmd"]             #for libvpx 1.2.0
    756     else:
    757         vpx_lib_names = ["vpxmt", "vpxmtd"]   #for libvpx 1.1.0
    758     #webp:
    759     webp_path = "C:\\libwebp-windows-x86"
    760     webp_include_dir    = webp_path+"\\include"
    761     webp_lib_dir        = webp_path+"\\lib"
    762     webp_bin_dir        = webp_path+"\\bin"
    763     webp_lib_names      = ["libwebp"]
    764 
    765     # Same for PyGTK:
    766     # http://www.pygtk.org/downloads.html
    767     gtk2_path = "C:\\Python27\\Lib\\site-packages\\gtk-2.0"
    768     python_include_path = "C:\\Python27\\include"
    769     gtk2runtime_path        = os.path.join(gtk2_path, "runtime")
    770     gtk2_lib_dir            = os.path.join(gtk2runtime_path, "bin")
    771     gtk2_base_include_dir   = os.path.join(gtk2runtime_path, "include")
    772 
    773     pygtk_include_dir       = os.path.join(python_include_path, "pygtk-2.0")
    774     atk_include_dir         = os.path.join(gtk2_base_include_dir, "atk-1.0")
    775     gtk2_include_dir        = os.path.join(gtk2_base_include_dir, "gtk-2.0")
    776     gdkpixbuf_include_dir   = os.path.join(gtk2_base_include_dir, "gdk-pixbuf-2.0")
    777     glib_include_dir        = os.path.join(gtk2_base_include_dir, "glib-2.0")
    778     cairo_include_dir       = os.path.join(gtk2_base_include_dir, "cairo")
    779     pango_include_dir       = os.path.join(gtk2_base_include_dir, "pango-1.0")
    780     gdkconfig_include_dir   = os.path.join(gtk2runtime_path, "lib", "gtk-2.0", "include")
    781     glibconfig_include_dir  = os.path.join(gtk2runtime_path, "lib", "glib-2.0", "include")
    782 
    783     def checkdirs(*dirs):
    784         for d in dirs:
    785             if not os.path.exists(d) or not os.path.isdir(d):
    786                 raise Exception("cannot find a directory which is required for building: %s" % d)
    787 
    788     def pkgconfig(*pkgs_options, **ekw):
    789         kw = dict(ekw)
    790         #remove static flag on win32..
    791         static = kw.get("static", None)
    792         if static is not None:
    793             del kw["static"]
    794         #always add the win32 include dirs, everyone needs that:
    795         add_to_keywords(kw, 'include_dirs', win32_include_dir)
    796         if len(pkgs_options)==0:
    797             return kw
    798 
    799         def add_to_PATH(bindir):
    800             if os.environ['PATH'].find(bindir)<0:
    801                 os.environ['PATH'] = bindir + ';' + os.environ['PATH']
    802             if bindir not in sys.path:
    803                 sys.path.append(bindir)
    804         if "avcodec" in pkgs_options[0]:
    805             add_to_PATH(libffmpeg_bin_dir)
    806             add_to_keywords(kw, 'include_dirs', libffmpeg_include_dir)
    807             add_to_keywords(kw, 'libraries', "avcodec", "avutil")
    808             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_lib_dir)
    809             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_bin_dir)
    810             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    811             checkdirs(libffmpeg_include_dir, libffmpeg_lib_dir, libffmpeg_bin_dir)
    812         elif "swscale" in pkgs_options[0]:
    813             add_to_PATH(libffmpeg_bin_dir)
    814             add_to_keywords(kw, 'include_dirs', libffmpeg_include_dir)
    815             add_to_keywords(kw, 'libraries', "swscale", "avutil")
    816             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_lib_dir)
    817             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % libffmpeg_bin_dir)
    818             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    819             checkdirs(libffmpeg_include_dir, libffmpeg_lib_dir, libffmpeg_bin_dir)
    820         elif "x264" in pkgs_options[0]:
    821             add_to_PATH(libffmpeg_bin_dir)
    822             add_to_PATH(x264_bin_dir)
    823             add_to_keywords(kw, 'include_dirs', x264_include_dir)
    824             add_to_keywords(kw, 'libraries', "libx264")
    825             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % x264_lib_dir)
    826             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    827             checkdirs(x264_include_dir, x264_lib_dir)
    828         elif "x265" in pkgs_options[0]:
    829             add_to_PATH(libffmpeg_bin_dir)
    830             add_to_PATH(x265_bin_dir)
    831             add_to_keywords(kw, 'include_dirs', x265_include_dir)
    832             add_to_keywords(kw, 'libraries', "libx265")
    833             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % x265_lib_dir)
    834             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    835             checkdirs(x265_include_dir, x265_lib_dir)
    836         elif "vpx" in pkgs_options[0]:
    837             add_to_PATH(libffmpeg_bin_dir)
    838             add_to_keywords(kw, 'include_dirs', vpx_include_dir)
    839             add_to_keywords(kw, 'libraries', *vpx_lib_names)
    840             add_to_keywords(kw, 'extra_link_args', "/NODEFAULTLIB:LIBCMT")
    841             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % vpx_lib_dir)
    842             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    843             checkdirs(vpx_include_dir, vpx_lib_dir)
    844         elif "webp" in pkgs_options[0]:
    845             add_to_PATH(webp_bin_dir)
    846             add_to_keywords(kw, 'include_dirs', webp_include_dir)
    847             add_to_keywords(kw, 'libraries', *webp_lib_names)
    848             add_to_keywords(kw, 'extra_link_args', "/LIBPATH:%s" % webp_lib_dir)
    849             add_to_keywords(kw, 'extra_link_args', "/OPT:NOREF")
    850             checkdirs(webp_include_dir, webp_lib_dir, webp_bin_dir)
    851         elif "pygobject-2.0" in pkgs_options[0]:
    852             dirs = (python_include_path,
    853                     pygtk_include_dir, atk_include_dir, gtk2_include_dir,
    854                     gtk2_base_include_dir, gdkconfig_include_dir, gdkpixbuf_include_dir,
    855                     glib_include_dir, glibconfig_include_dir,
    856                     cairo_include_dir, pango_include_dir)
    857             add_to_keywords(kw, 'include_dirs', *dirs)
    858             checkdirs(*dirs)
    859         elif "cuda" in pkgs_options[0]:
    860             add_to_keywords(kw, 'include_dirs', cuda_include_dir)
    861             checkdirs(cuda_include_dir)
    862             data_files.append(('.', glob.glob("%s/*32*.dll" % cuda_bin_dir)))
    863         else:
    864             sys.exit("ERROR: unknown package config: %s" % str(pkgs_options))
    865         if debug_ENABLED:
    866             #Od will override whatever may be specified elsewhere
    867             #and allows us to use the debug switches,
    868             #at the cost of a warning...
    869             for flag in ('/Od', '/Zi', '/DEBUG', '/RTC1', '/GS'):
    870                 add_to_keywords(kw, 'extra_compile_args', flag)
    871             add_to_keywords(kw, 'extra_link_args', "/DEBUG")
    872             kw['cython_gdb'] = True
    873         print("pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
    874         return kw
    875 
    876     import py2exe    #@UnresolvedImport
    877     assert py2exe is not None
    878 
    879     #with py2exe, we don't use py_modules, we use "packages"... sigh
    880     #(and it is a little bit different too - see below)
    881     del setup_options["py_modules"]
     1026    MINGW_PREFIX = os.environ.get("MINGW_PREFIX")
     1027    assert MINGW_PREFIX, "you must run this build from a MINGW environment"
    8821028    add_packages("xpra.platform.win32")
    8831029    remove_packages("xpra.platform.darwin", "xpra.platform.xposix")
    884     #UI applications (detached from shell: no text output if ran from cmd.exe)
    885     setup_options["windows"] = [
    886                     {'script': 'scripts/xpra',                          'icon_resources': [(1, "win32/xpra_txt.ico")],  "dest_base": "Xpra",},
    887                     {'script': 'scripts/xpra_launcher',                 'icon_resources': [(1, "win32/xpra.ico")],      "dest_base": "Xpra-Launcher",},
    888                     {'script': 'xpra/gtk_common/gtk_view_keyboard.py',  'icon_resources': [(1, "win32/keyboard.ico")],  "dest_base": "GTK_Keyboard_Test",},
    889                     {'script': 'xpra/gtk_common/gtk_view_clipboard.py', 'icon_resources': [(1, "win32/clipboard.ico")], "dest_base": "GTK_Clipboard_Test",},
    890               ]
    891     #Console: provide an Xpra_cmd.exe we can run from the cmd.exe shell
    892     console = [
    893                     {'script': 'scripts/xpra',                          'icon_resources': [(1, "win32/xpra_txt.ico")],  "dest_base": "Xpra_cmd",},
    894                     {'script': 'win32/python_execfile.py',              'icon_resources': [(1, "win32/python.ico")],    "dest_base": "Python_execfile",},
    895                     {'script': 'xpra/platform/win32/gui.py',            'icon_resources': [(1, "win32/loop.ico")],      "dest_base": "Events_Test",},
    896                     {'script': 'xpra/codecs/loader.py',                 'icon_resources': [(1, "win32/encoding.ico")],  "dest_base": "Encoding_info",},
    897                     {'script': 'xpra/sound/gstreamer_util.py',          'icon_resources': [(1, "win32/gstreamer.ico")], "dest_base": "GStreamer_info",},
    898                     {'script': 'xpra/sound/src.py',                     'icon_resources': [(1, "win32/microphone.ico")],"dest_base": "Sound_Record",},
    899                     {'script': 'xpra/sound/sink.py',                    'icon_resources': [(1, "win32/speaker.ico")],   "dest_base": "Sound_Play",},
    900               ]
    901     if opengl_ENABLED:
    902         console.append({'script': 'xpra/client/gl/gl_check.py',            'icon_resources': [(1, "win32/opengl.ico")],    "dest_base": "OpenGL_check",})
    903     setup_options["console"] = console
    904 
    905     py2exe_includes = external_includes + ["win32con", "win32gui", "win32process", "win32api"]
    906     dll_excludes = ["w9xpopen.exe","tcl85.dll", "tk85.dll"]
     1030
     1031    #this is where the win32 gi installer will put things:
     1032    gnome_include_path = os.environ.get("MINGW_PREFIX")
     1033
     1034    #only add the cx_freeze specific options
     1035    #if we aren't just building the Cython bits with "build_ext":
     1036    if "build_ext" not in sys.argv:
     1037        #with cx_freeze, we don't use py_modules
     1038        del setup_options["py_modules"]
     1039        import cx_Freeze                            #@UnresolvedImport
     1040        from cx_Freeze import setup, Executable     #@UnresolvedImport @Reimport
     1041        CX5 = cx_Freeze.version>="5"
     1042        if CX5 and not hasattr(sys, "base_prefix"):
     1043            #workaround for broken sqlite hook with python 2.7, see:
     1044            #https://github.com/anthony-tuininga/cx_Freeze/pull/272
     1045            sys.base_prefix = sys.prefix
     1046
     1047        #cx_freeze doesn't use "data_files"...
     1048        del setup_options["data_files"]
     1049        #it wants source files first, then where they are placed...
     1050        #one item at a time (no lists)
     1051        #all in its own structure called "include_files" instead of "data_files"...
     1052        def add_data_files(target_dir, files):
     1053            if verbose_ENABLED:
     1054                print("add_data_files(%s, %s)" % (target_dir, files))
     1055            assert type(target_dir)==str
     1056            assert type(files) in (list, tuple)
     1057            for f in files:
     1058                target_file = os.path.join(target_dir, os.path.basename(f))
     1059                data_files.append((f, target_file))
     1060
     1061        #pass a potentially nested dictionary representing the tree
     1062        #of files and directories we do want to include
     1063        #relative to gnome_include_path
     1064        def add_dir(base, defs):
     1065            if verbose_ENABLED:
     1066                print("add_dir(%s, %s)" % (base, defs))
     1067            if type(defs) in (list, tuple):
     1068                for sub in defs:
     1069                    if type(sub)==dict:
     1070                        add_dir(base, sub)
     1071                    else:
     1072                        assert type(sub)==str
     1073                        filename = os.path.join(gnome_include_path, base, sub)
     1074                        if os.path.exists(filename):
     1075                            add_data_files(base, [filename])
     1076                        else:
     1077                            print("Warning: missing '%s'" % filename)
     1078            else:
     1079                assert type(defs)==dict
     1080                for d, sub in defs.items():
     1081                    assert type(sub) in (dict, list, tuple)
     1082                    #recurse down:
     1083                    add_dir(os.path.join(base, d), sub)
     1084
     1085        #convenience method for adding GI libs and "typelib" and "gir":
     1086        def add_gi(*libs):
     1087            if verbose_ENABLED:
     1088                print("add_gi(%s)" % str(libs))
     1089            add_dir('lib',      {"girepository-1.0":    ["%s.typelib" % x for x in libs]})
     1090            add_dir('share',    {"gir-1.0" :            ["%s.gir" % x for x in libs]})
     1091
     1092        def add_DLLs(*dll_names):
     1093            try:
     1094                do_add_DLLs(*dll_names)
     1095            except Exception as e:
     1096                print("Error: failed to add DLLs: %s" % (dll_names, ))
     1097                print(" %s" % e)
     1098                sys.exit(1)
     1099
     1100        def do_add_DLLs(*dll_names):
     1101            dll_names = list(dll_names)
     1102            dll_files = []
     1103            import re
     1104            version_re = re.compile("\-[0-9\.\-]+$")
     1105            dirs = os.environ.get("PATH").split(os.path.pathsep)
     1106            if os.path.exists(gnome_include_path):
     1107                dirs.insert(0, gnome_include_path)
     1108            if verbose_ENABLED:
     1109                print("add_DLLs: looking for %s in %s" % (dll_names, dirs))
     1110            for d in dirs:
     1111                if not os.path.exists(d):
     1112                    continue
     1113                for x in os.listdir(d):
     1114                    dll_path = os.path.join(d, x)
     1115                    x = x.lower()
     1116                    if os.path.isdir(dll_path) or not x.startswith("lib") or not x.endswith(".dll"):
     1117                        continue
     1118                    nameversion = x[3:-4]                       #strip "lib" and ".dll": "libatk-1.0-0.dll" -> "atk-1.0-0"
     1119                    if verbose_ENABLED:
     1120                        print("checking %s: %s" % (x, nameversion))
     1121                    m = version_re.search(nameversion)          #look for version part of filename
     1122                    if m:
     1123                        dll_version = m.group(0)                #found it, ie: "-1.0-0"
     1124                        dll_name = nameversion[:-len(dll_version)]  #ie: "atk"
     1125                        dll_version = dll_version.lstrip("-")   #ie: "1.0-0"
     1126                    else:
     1127                        dll_version = ""                        #no version
     1128                        dll_name = nameversion                  #ie: "libzzz.dll" -> "zzz"
     1129                    if dll_name in dll_names:
     1130                        #this DLL is on our list
     1131                        print("%s %s %s" % (dll_name.ljust(22), dll_version.ljust(10), x))
     1132                        dll_files.append(dll_path)
     1133                        dll_names.remove(dll_name)
     1134            if len(dll_names)>0:
     1135                print("some DLLs could not be found:")
     1136                for x in dll_names:
     1137                    print(" - lib%s*.dll" % x)
     1138            add_data_files("", dll_files)
     1139
     1140        #list of DLLs we want to include, without the "lib" prefix, or the version and extension
     1141        #(ie: "libatk-1.0-0.dll" -> "atk")
     1142        if sound_ENABLED or gtk3_ENABLED:
     1143            add_DLLs('gio', 'girepository', 'glib',
     1144                     'gnutls', 'gobject', 'gthread',
     1145                     'orc', 'stdc++',
     1146                     'winpthread',
     1147                     )
     1148        if gtk3_ENABLED:
     1149            add_DLLs('atk',
     1150                     'dbus', 'dbus-glib',
     1151                     'gdk', 'gdk_pixbuf', 'gtk',
     1152                     'cairo-gobject', 'pango', 'pangocairo', 'pangoft2', 'pangowin32',
     1153                     'harfbuzz', 'harfbuzz-gobject',
     1154                     'jasper', 'epoxy',
     1155                     'intl',
     1156                     'p11-kit',
     1157                     'jpeg', 'png16', 'rsvg', 'webp', 'tiff')
     1158            #these are missing in newer aio installers (sigh):
     1159            do_add_DLLs('javascriptcoregtk')
     1160            if opengl_ENABLED:
     1161                do_add_DLLs('gdkglext', 'gtkglext')
     1162
     1163        if gtk3_ENABLED:
     1164            add_dir('etc', ["fonts", "gtk-3.0", "pango", "pkcs11"])     #add "dbus-1"?
     1165            add_dir('lib', ["gdk-pixbuf-2.0", "gtk-3.0",
     1166                            "libvisual-0.4", "p11-kit", "pkcs11"])
     1167            add_dir('share', ["fontconfig", "fonts", "glib-2.0",        #add "dbus-1"?
     1168                              "p11-kit", "xml",
     1169                              {"icons"  : ["hicolor"]},
     1170                              {"locale" : ["en"]},
     1171                              {"themes" : ["Default"]}
     1172                             ])
     1173        if gtk3_ENABLED or sound_ENABLED:
     1174            add_dir('lib', ["gio"])
     1175            packages.append("gi")
     1176            add_gi("Gio-2.0", "GIRepository-2.0", "Glib-2.0", "GModule-2.0",
     1177                   "GObject-2.0")
     1178        if gtk3_ENABLED:
     1179            add_gi("Atk-1.0",
     1180                   "fontconfig-2.0", "freetype2-2.0",
     1181                   "GDesktopEnums-3.0", "Soup-2.4",
     1182                   "GdkPixbuf-2.0", "Gdk-3.0", "Gtk-3.0",
     1183                   "HarfBuzz-0.0",
     1184                   "Libproxy-1.0", "libxml2-2.0",
     1185                   "cairo-1.0", "Pango-1.0", "PangoCairo-1.0", "PangoFT2-1.0",
     1186                   "Rsvg-2.0",
     1187                   "win32-1.0")
     1188            if opengl_ENABLED:
     1189                add_gi("GdkGLExt-3.0", "GtkGLExt-3.0", "GL-1.0")
     1190            add_DLLs('visual', 'curl', 'soup', 'openjpeg')
     1191        if server_ENABLED and not PYTHON3:
     1192            add_DLLs('sqlite3')
     1193
     1194        if gtk2_ENABLED:
     1195            add_dir('lib',      {
     1196                "gdk-pixbuf-2.0":    {
     1197                    "2.10.0"    :   {
     1198                        "loaders"   :
     1199                            ["libpixbufloader-%s.dll" % x for x in ("ico", "jpeg", "svg", "bmp")]
     1200                        },
     1201                    },
     1202                })
     1203
     1204        if sound_ENABLED:
     1205            add_dir("share", ["gst-plugins-bad", "gst-plugins-base", "gstreamer-1.0"])
     1206            add_gi("Gst-1.0", "GstAllocators-1.0", "GstAudio-1.0", "GstBase-1.0",
     1207                   "GstTag-1.0")
     1208            add_DLLs('gstreamer', 'orc-test')
     1209            for p in ("app", "audio", "base", "codecparsers", "fft", "net", "video",
     1210                      "pbutils", "riff", "sdp", "rtp", "rtsp", "tag", "uridownloader",
     1211                      #I think 'coreelements' needs those (otherwise we would exclude them):
     1212                      "basecamerabinsrc", "mpegts", "photography",
     1213                      ):
     1214                add_DLLs('gst%s' % p)
     1215            #DLLs needed by the plugins:
     1216            add_DLLs("faac", "faad", "flac", "mad", "mpg123")
     1217            #add the gstreamer plugins we need:
     1218            GST_PLUGINS = ("app",
     1219                           "cutter",
     1220                           #muxers:
     1221                           "gdp", "matroska", "ogg", "isomp4",
     1222                           "audioparsers", "audiorate", "audioconvert", "audioresample", "audiotestsrc",
     1223                           "coreelements", "directsoundsink", "directsoundsrc", "wasapi",
     1224                           #codecs:
     1225                           "opus", "opusparse", "flac", "lame", "mad", "mpg123", "speex", "faac", "faad",
     1226                           "volume", "vorbis", "wavenc", "wavpack", "wavparse",
     1227                           #untested: a52dec, voaacenc
     1228                           )
     1229            add_dir(os.path.join("lib", "gstreamer-1.0"), [("libgst%s.dll" % x) for x in GST_PLUGINS])
     1230            #END OF SOUND
     1231
     1232        if server_ENABLED:
     1233            #used by proxy server:
     1234            external_includes += ["multiprocessing", "setproctitle"]
     1235
     1236        external_includes += ["encodings"]
     1237        if client_ENABLED:
     1238            #for parsing "open-command":
     1239            external_includes += ["shlex"]
     1240            #for version check:
     1241            external_includes += [
     1242                                  "ftplib", "fileinput",
     1243                                  ]
     1244            if PYTHON3:
     1245                external_includes += ["urllib", "http.cookiejar", "http.client"]
     1246            else:
     1247                external_includes += ["urllib2", "cookielib", "httplib"]
     1248
     1249        if PYTHON3:
     1250            #hopefully, cx_Freeze will fix this horror:
     1251            #(we shouldn't have to deal with DLL dependencies)
     1252            import site
     1253            lib_python = os.path.dirname(site.getsitepackages()[0])
     1254            lib_dynload_dir = os.path.join(lib_python, "lib-dynload")
     1255            add_data_files('', glob.glob("%s/zlib*dll" % lib_dynload_dir))
     1256            for x in ("io", "codecs", "abc", "_weakrefset", "encodings"):
     1257                add_data_files("", glob.glob("%s/%s*" % (lib_python, x)))
     1258        #ensure that cx_freeze won't automatically grab other versions that may lay on our path:
     1259        os.environ["PATH"] = gnome_include_path+";"+os.environ.get("PATH", "")
     1260        bin_excludes = ["MSVCR90.DLL", "MFC100U.DLL"]
     1261        cx_freeze_options = {
     1262                            "includes"          : external_includes,
     1263                            "packages"          : packages,
     1264                            "include_files"     : data_files,
     1265                            "excludes"          : excludes,
     1266                            "include_msvcr"     : True,
     1267                            "bin_excludes"      : bin_excludes,
     1268                            }
     1269        if not CX5:
     1270            cx_freeze_options.update({
     1271                            "compressed"        : True,
     1272                            "create_shared_zip" : zip_ENABLED,
     1273                            })
     1274        else:
     1275            #cx_Freeze v5 workarounds:
     1276            if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
     1277                add_packages("numpy.core._methods", "numpy.lib.format")
     1278
     1279        setup_options["options"] = {"build_exe" : cx_freeze_options}
     1280        executables = []
     1281        setup_options["executables"] = executables
     1282
     1283        def add_exe(script, icon, base_name, base="Console"):
     1284            kwargs = {}
     1285            if not CX5:
     1286                kwargs = {
     1287                    "compress"              : True,
     1288                    "copyDependentFiles"    : True,
     1289                    "appendScriptToExe"     : False,
     1290                    "appendScriptToLibrary" : True,
     1291                    }
     1292            executables.append(Executable(
     1293                        script                  = script,
     1294                        initScript              = None,
     1295                        #targetDir               = "dist",
     1296                        icon                    = "win32/%s" % icon,
     1297                        targetName              = "%s.exe" % base_name,
     1298                        base                    = base,
     1299                        **kwargs))
     1300
     1301        def add_console_exe(script, icon, base_name):
     1302            add_exe(script, icon, base_name)
     1303        def add_gui_exe(script, icon, base_name):
     1304            add_exe(script, icon, base_name, base="Win32GUI")
     1305        def add_service_exe(script, icon, base_name):
     1306            add_exe(script, icon, base_name, base="Win32Service")
     1307
     1308        #UI applications (detached from shell: no text output if ran from cmd.exe)
     1309        if client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED):
     1310            add_gui_exe("scripts/xpra",                         "xpra_txt.ico",     "Xpra")
     1311            add_gui_exe("scripts/xpra_launcher",                "xpra.ico",         "Xpra-Launcher")
     1312            add_gui_exe("xpra/gtk_common/gtk_view_keyboard.py", "keyboard.ico",     "GTK_Keyboard_Test")
     1313            add_gui_exe("xpra/scripts/bug_report.py",           "bugs.ico",         "Bug_Report")
     1314            add_gui_exe("xpra/platform/win32/gdi_screen_capture.py", "screenshot.ico", "Screenshot")
     1315        if server_ENABLED:
     1316            add_gui_exe("scripts/auth_dialog",                  "authentication.ico", "Auth_Dialog")
     1317        if gtk2_ENABLED:
     1318            #these need porting..
     1319            add_gui_exe("xpra/gtk_common/gtk_view_clipboard.py","clipboard.ico",    "GTK_Clipboard_Test")
     1320        if mdns_ENABLED and (gtk2_ENABLED or gtk3_ENABLED):
     1321            add_gui_exe("xpra/client/gtk_base/mdns_gui.py",     "mdns.ico",         "Xpra_Browser")
     1322        #Console: provide an Xpra_cmd.exe we can run from the cmd.exe shell
     1323        add_console_exe("scripts/xpra",                     "xpra_txt.ico",     "Xpra_cmd")
     1324        add_console_exe("xpra/scripts/version.py",          "information.ico",  "Version_info")
     1325        add_console_exe("xpra/net/net_util.py",             "network.ico",      "Network_info")
     1326        if gtk2_ENABLED or gtk3_ENABLED:
     1327            add_console_exe("xpra/scripts/gtk_info.py",         "gtk.ico",          "GTK_info")
     1328            add_console_exe("xpra/gtk_common/keymap.py",        "keymap.ico",       "Keymap_info")
     1329            add_console_exe("xpra/platform/keyboard.py",        "keymap.ico",       "Keyboard_info")
     1330        if client_ENABLED or server_ENABLED:
     1331            add_console_exe("win32/python_execfile.py",         "python.ico",       "Python_execfile")
     1332            add_console_exe("xpra/scripts/config.py",           "gears.ico",        "Config_info")
     1333        if server_ENABLED:
     1334            add_console_exe("xpra/server/auth/sqlite_auth.py",  "sqlite.ico",        "SQLite_auth_tool")
     1335            add_console_exe("xpra/server/auth/win32_auth.py",   "authentication.ico", "System-Auth-Test")
     1336            add_console_exe("win32/service/proxy.py",           "xpra_txt.ico",      "Xpra-Proxy")
     1337            add_console_exe("xpra/platform/win32/lsa_logon_lib.py", "xpra_txt.ico",     "System-Logon-Test")
     1338        if client_ENABLED:
     1339            add_console_exe("xpra/codecs/loader.py",            "encoding.ico",     "Encoding_info")
     1340            add_console_exe("xpra/platform/paths.py",           "directory.ico",    "Path_info")
     1341            add_console_exe("xpra/platform/features.py",        "features.ico",     "Feature_info")
     1342        if client_ENABLED:
     1343            add_console_exe("xpra/platform/gui.py",             "browse.ico",       "NativeGUI_info")
     1344            add_console_exe("xpra/platform/win32/gui.py",       "loop.ico",         "Events_Test")
     1345        if sound_ENABLED:
     1346            add_console_exe("xpra/sound/gstreamer_util.py",     "gstreamer.ico",    "GStreamer_info")
     1347            add_console_exe("scripts/xpra",                     "speaker.ico",      "Xpra_Audio")
     1348            add_console_exe("xpra/platform/win32/directsound.py", "speaker.ico",      "Audio_Devices")
     1349            #add_console_exe("xpra/sound/src.py",                "microphone.ico",   "Sound_Record")
     1350            #add_console_exe("xpra/sound/sink.py",               "speaker.ico",      "Sound_Play")
     1351        if opengl_ENABLED:
     1352            if PYTHON3:
     1353                add_console_exe("xpra/client/gl/gl_check.py",   "opengl.ico",       "OpenGL_check")
     1354            else:
     1355                add_console_exe("xpra/client/gl/gtk_base/gtkgl_check.py", "opengl.ico", "OpenGL_check")
     1356        if webcam_ENABLED:
     1357            add_console_exe("xpra/platform/webcam.py",          "webcam.ico",    "Webcam_info")
     1358            add_console_exe("xpra/scripts/show_webcam.py",          "webcam.ico",    "Webcam_Test")
     1359        if printing_ENABLED:
     1360            add_console_exe("xpra/platform/printing.py",        "printer.ico",     "Print")
     1361            add_console_exe("xpra/platform/win32/pdfium.py",    "printer.ico",     "PDFIUM_Print")
     1362            add_DLLs("pdfium")  #libpdfium.dll
     1363        if nvenc_ENABLED:
     1364            add_console_exe("xpra/codecs/nv_util.py",                   "nvidia.ico",   "NVidia_info")
     1365        if nvfbc_ENABLED:
     1366            add_console_exe("xpra/codecs/nvfbc/capture.py",             "nvidia.ico",   "NvFBC_capture")
     1367        if nvfbc_ENABLED or nvenc_ENABLED:
     1368            add_console_exe("xpra/codecs/cuda_common/cuda_context.py",  "cuda.ico",     "CUDA_info")
     1369
     1370        if example_ENABLED:
     1371            add_gui_exe("xpra/client/gtk_base/example/colors.py",               "encoding.ico",     "Colors")
     1372            add_gui_exe("xpra/client/gtk_base/example/colors_gradient.py",      "encoding.ico",     "Colors-Gradient")
     1373            if not PYTHON3:
     1374                add_gui_exe("xpra/client/gtk_base/example/gl_colors_gradient.py",   "encoding.ico",     "OpenGL-Colors-Gradient")
     1375            add_gui_exe("xpra/client/gtk_base/example/colors_plain.py",         "encoding.ico",     "Colors-Plain")
     1376            add_gui_exe("xpra/client/gtk_base/example/bell.py",                 "bell.ico",         "Bell")
     1377            add_gui_exe("xpra/client/gtk_base/example/transparent_colors.py",   "transparent.ico",  "Transparent-Colors")
     1378            add_gui_exe("xpra/client/gtk_base/example/transparent_window.py",   "transparent.ico",  "Transparent-Window")
     1379            add_gui_exe("xpra/client/gtk_base/example/fontrendering.py",        "font.ico",         "Font-Rendering")
     1380
     1381        #FIXME: how do we figure out what target directory to use?
     1382        print("calling build_xpra_conf in-place")
     1383        #building etc files in-place:
     1384        build_xpra_conf(".")
     1385        add_data_files('etc/xpra', glob.glob("etc/xpra/*conf"))
     1386        add_data_files('etc/xpra', glob.glob("etc/xpra/nvenc*.keys"))
     1387        add_data_files('etc/xpra', glob.glob("etc/xpra/nvfbc*.keys"))
     1388        add_data_files('etc/xpra/conf.d', glob.glob("etc/xpra/conf.d/*conf"))
     1389        #build minified html5 client in temporary build dir:
     1390        if "clean" not in sys.argv and html5_ENABLED:
     1391            install_html5(os.path.join(install, "www"), )
     1392            for k,v in glob_recurse("build/www").items():
     1393                if (k!=""):
     1394                    k = os.sep+k
     1395                add_data_files('www'+k, v)
     1396
     1397    if client_ENABLED or server_ENABLED:
     1398        add_data_files('',      ['COPYING', 'README', 'win32/website.url'])
     1399        add_data_files('icons', glob.glob('win32\\*.ico') + glob.glob('icons\\*.*'))
     1400
     1401    if webcam_ENABLED:
     1402        add_data_files('',      ['win32\\DirectShow.tlb'])
     1403        add_modules("comtypes.gen.stdole", "comtypes.gen.DirectShowLib")
     1404
    9071405    remove_packages(*external_excludes)
     1406    external_includes.append("mmap")
    9081407    remove_packages(#not used on win32:
    909                     "mmap",
    9101408                    #we handle GL separately below:
    9111409                    "OpenGL", "OpenGL_accelerate",
     
    9131411                    "ctypes.macholib")
    9141412
    915     if not cyxor_ENABLED or opengl_ENABLED:
     1413    if webcam_ENABLED:
     1414        external_includes.append("cv2")
     1415
     1416    if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
    9161417        #we need numpy for opengl or as a fallback for the Cython xor module
    917         py2exe_includes.append("numpy")
     1418        external_includes.append("numpy")
    9181419    else:
    919         remove_packages("numpy",
    920                         "unittest", "difflib",  #avoid numpy warning (not an error)
     1420        remove_packages("unittest", "difflib",  #avoid numpy warning (not an error)
    9211421                        "pydoc")
    9221422
    923     if sound_ENABLED:
    924         py2exe_includes += ["pygst", "gst", "gst.extend"]
    925     else:
    926         remove_packages("pygst", "gst", "gst.extend")
    927 
    928     if opengl_ENABLED:
     1423    #make sure we don't include the gstreamer 0.10 "pygst" bindings:
     1424    remove_packages("pygst", "gst", "gst.extend")
     1425
     1426    #add subset of PyOpenGL modules (only when installing):
     1427    if opengl_ENABLED and ("install_exe" in sys.argv or "install" in sys.argv):
    9291428        #for this hack to work, you must add "." to the sys.path
    9301429        #so python can load OpenGL from the install directory
    9311430        #(further complicated by the fact that "." is the "frozen" path...)
     1431        #but we re-add those two directories to the library.zip as part of the build script
    9321432        import OpenGL, OpenGL_accelerate        #@UnresolvedImport
    933         import shutil
    934         print("*** copy PyOpenGL modules ***")
     1433        print("*** copying PyOpenGL modules to %s ***" % install)
    9351434        for module_name, module in {"OpenGL" : OpenGL, "OpenGL_accelerate" : OpenGL_accelerate}.items():
    9361435            module_dir = os.path.dirname(module.__file__ )
    9371436            try:
    9381437                shutil.copytree(
    939                     module_dir, os.path.join("dist", module_name),
    940                     ignore = shutil.ignore_patterns("Tk")
     1438                    module_dir, os.path.join(install, module_name),
     1439                    ignore = shutil.ignore_patterns("Tk", "AGL", "EGL", "GLX", "GLX.*", "_GLX.*", "GLE", "GLES1", "GLES2", "GLES3")
    9411440                )
    942             except WindowsError, error:     #@UndefinedVariable
    943                 if not "already exists" in str( error ):
     1441            except Exception as e:
     1442                if not isinstance(e, WindowsError) or (not "already exists" in str(e)): #@UndefinedVariable
    9441443                    raise
    945     py2exe_options = {
    946                       "skip_archive"   : False,
    947                       "optimize"       : 0,    #WARNING: do not change - causes crashes
    948                       "unbuffered"     : True,
    949                       "compressed"     : True,
    950                       "skip_archive"   : False,
    951                       "packages"       : packages,
    952                       "includes"       : py2exe_includes,
    953                       "excludes"       : excludes,
    954                       "dll_excludes"   : dll_excludes,
    955                      }
    956     setup_options["options"] = {"py2exe" : py2exe_options}
    957     data_files += [
    958                    ('', ['COPYING', 'README',
    959                          'win32/website.url',
    960                          'etc/xpra/client-only/xpra.conf'] +
    961                          glob.glob('%s\\bin\\*.dll' % libffmpeg_path)),
    962                    ('icons', glob.glob('win32\\*.ico') + glob.glob('icons\\*.*')),
    963                    ('Microsoft.VC90.CRT', glob.glob('%s\\Microsoft.VC90.CRT\\*.*' % C_DLLs)),
    964                    ('Microsoft.VC90.MFC', glob.glob('%s\\Microsoft.VC90.MFC\\*.*' % C_DLLs)),
    965                    ]
    966     if enc_x264_ENABLED:
    967         data_files.append(('', ['%s\\libx264.dll' % x264_bin_dir]))
    968     html5_dir = ''
    969 
    970     if webm_ENABLED or webp_ENABLED:
    971         #Note: confusingly, the python bindings are called webm...
    972         #add the webp DLL to the output:
    973         #And since 0.2.1, you have to compile the DLL yourself..
    974         #the path after installing may look like this:
    975         #webp_DLL = "C:\\libwebp-0.3.1-windows-x86\\bin\\libwebp.dll"
    976         #but we use something more generic, without the version numbers:
    977         webp_DLL = webp_bin_dir+"\\libwebp.dll"
    978         data_files.append(('', [webp_DLL]))
    979         #and its license:
    980         data_files.append(('webm', ["xpra/codecs/webm/LICENSE"]))
    981 
    982 
     1444
     1445    add_data_files('', glob.glob("win32\\bundle-extra\\*"))
     1446    add_data_files('', ["bell.wav"])
     1447    add_data_files('http-headers', glob.glob("http-headers\\*"))
     1448
     1449    #END OF win32
    9831450#*******************************************************************************
    9841451else:
    9851452    #OSX and *nix:
    986     scripts += ["scripts/xpra", "scripts/xpra_launcher"]
    987     data_files += [
    988                     ("share/man/man1",      ["man/xpra.1", "man/xpra_launcher.1"]),
    989                     ("share/xpra",          ["README", "COPYING"]),
    990                     ("share/xpra/icons",    glob.glob("icons/*")),
    991                     ("share/applications",  ["xdg/xpra_launcher.desktop", "xdg/xpra.desktop"]),
    992                     ("share/icons",         ["xdg/xpra.png"])
    993                   ]
    994     html5_dir = "share/xpra/www"
    995     if webm_ENABLED:
    996         data_files.append(('share/xpra/webm', ["xpra/codecs/webm/LICENSE"]))
     1453    scripts += ["scripts/xpra", "scripts/xpra_launcher", "scripts/xpra_browser", "scripts/udev_product_version", "scripts/xpra_signal_listener"]
     1454    if POSIX and not OSX:
     1455        libexec_scripts = []
     1456        from xpra.os_util import is_Fedora, is_CentOS
     1457        if is_Fedora() or is_CentOS():
     1458            libexec = "libexec"
     1459        else:
     1460            libexec = "lib"
     1461        if xdg_open_ENABLED:
     1462            libexec_scripts += ["scripts/xdg-open", "scripts/gnome-open", "scripts/gvfs-open"]
     1463        if server_ENABLED:
     1464            libexec_scripts.append("scripts/auth_dialog")
     1465        if libexec_scripts:
     1466            add_data_files("%s/xpra/" % libexec, libexec_scripts)
     1467    add_data_files("share/man/man1",      ["man/xpra.1", "man/xpra_launcher.1", "man/xpra_browser.1"])
     1468    add_data_files("share/xpra",          ["README", "COPYING"])
     1469    add_data_files("share/xpra/icons",    glob.glob("icons/*"))
     1470    add_data_files("share/applications",  ["xdg/xpra-launcher.desktop", "xdg/xpra-browser.desktop", "xdg/xpra.desktop"])
     1471    add_data_files("share/mime/packages", ["xdg/application-x-xpraconfig.xml"])
     1472    add_data_files("share/icons",         ["xdg/xpra.png", "xdg/xpra-mdns.png"])
     1473    add_data_files("share/appdata",       ["xdg/xpra.appdata.xml"])
     1474    add_data_files('share/xpra/',         ["bell.wav"])
     1475    add_data_files('share/xpra/http-headers', glob.glob("http-headers/*"))
     1476
     1477    #here, we override build and install so we can
     1478    #generate our /etc/xpra/xpra.conf
     1479    class build_override(build):
     1480        def run(self):
     1481            build.run(self)
     1482            self.run_command("build_conf")
     1483
     1484    class build_conf(build):
     1485        def run(self):
     1486            try:
     1487                build_base = self.distribution.command_obj['build'].build_base
     1488            except:
     1489                build_base = self.build_base
     1490            build_xpra_conf(build_base)
     1491
     1492    class install_data_override(install_data):
     1493        def run(self):
     1494            print("install_data_override: install_dir=%s" % self.install_dir)
     1495            if html5_ENABLED:
     1496                install_html5(os.path.join(self.install_dir, "share/xpra/www"))
     1497            install_data.run(self)
     1498
     1499            root_prefix = self.install_dir.rstrip("/")
     1500            if root_prefix.endswith("/usr"):
     1501                root_prefix = root_prefix[:-4]    #ie: "/" or "/usr/src/rpmbuild/BUILDROOT/xpra-0.18.0-0.20160513r12573.fc23.x86_64/"
     1502            build_xpra_conf(root_prefix)
     1503
     1504            def copytodir(src, dst_dir, dst_name=None, chmod=0o644):
     1505                #convert absolute paths:
     1506                if dst_dir.startswith("/"):
     1507                    dst_dir = root_prefix+dst_dir
     1508                else:
     1509                    dst_dir = self.install_dir.rstrip("/")+"/"+dst_dir
     1510                #make sure the target directory exists:
     1511                self.mkpath(dst_dir)
     1512                #generate the target filename:
     1513                filename = os.path.basename(src)
     1514                dst_file = os.path.join(dst_dir, dst_name or filename)
     1515                #copy it
     1516                print("copying %s -> %s (%s)" % (src, dst_dir, oct(chmod)))
     1517                shutil.copyfile(src, dst_file)
     1518                if chmod:
     1519                    os.chmod(dst_file, chmod)
     1520
     1521            if printing_ENABLED and POSIX:
     1522                #install "/usr/lib/cups/backend" with 0700 permissions:
     1523                copytodir("cups/xpraforwarder", "lib/cups/backend", chmod=0o700)
     1524
     1525            if x11_ENABLED:
     1526                #install xpra_Xdummy if we need it:
     1527                xvfb_command = detect_xorg_setup()
     1528                if any(x.find("xpra_Xdummy")>=0 for x in (xvfb_command or [])) or Xdummy_wrapper_ENABLED is True:
     1529                    copytodir("scripts/xpra_Xdummy", "bin", chmod=0o755)
     1530                #install xorg*.conf, cuda.conf and nvenc.keys:
     1531                etc_xpra_files = ["xorg.conf"]
     1532                if uinput_ENABLED:
     1533                    etc_xpra_files.append("xorg-uinput.conf")
     1534                if nvenc_ENABLED or nvfbc_ENABLED:
     1535                    etc_xpra_files.append("cuda.conf")
     1536                if nvenc_ENABLED:
     1537                    etc_xpra_files.append("nvenc.keys")
     1538                if nvfbc_ENABLED:
     1539                    etc_xpra_files.append("nvfbc.keys")
     1540                for x in etc_xpra_files:
     1541                    copytodir("etc/xpra/%s" % x, "/etc/xpra")
     1542                copytodir("etc/X11/xorg.conf.d/90-xpra-virtual.conf", "/etc/X11/xorg.conf.d/")
     1543
     1544            if pam_ENABLED:
     1545                copytodir("etc/pam.d/xpra", "/etc/pam.d")
     1546
     1547            systemd_dir = "/lib/systemd/system"
     1548            if service_ENABLED:
     1549                #Linux init service:
     1550                if os.path.exists("/bin/systemctl"):
     1551                    if sd_listen_ENABLED:
     1552                        copytodir("service/xpra.service", systemd_dir)
     1553                    else:
     1554                        copytodir("service/xpra-nosocketactivation.service", systemd_dir, dst_name="xpra.service")
     1555                else:
     1556                    copytodir("service/xpra", "/etc/init.d")
     1557                if os.path.exists("/etc/sysconfig"):
     1558                    copytodir("etc/sysconfig/xpra", "/etc/sysconfig")
     1559                elif os.path.exists("/etc/default"):
     1560                    copytodir("etc/sysconfig/xpra", "/etc/default")
     1561            if sd_listen_ENABLED:
     1562                copytodir("service/xpra.socket", systemd_dir)
     1563            if dbus_ENABLED and proxy_ENABLED:
     1564                copytodir("dbus/xpra.conf", "/etc/dbus-1/system.d")
     1565
     1566
     1567    # add build_conf to build step
     1568    cmdclass.update({
     1569             'build'        : build_override,
     1570             'build_conf'   : build_conf,
     1571             'install_data' : install_data_override,
     1572             })
    9971573
    9981574    if OSX:
     1575        #pyobjc needs email.parser
     1576        external_includes += ["email", "uu", "urllib", "objc", "cups", "six"]
     1577        if not PYTHON3:
     1578            external_includes += ["urllib2"]
    9991579        #OSX package names (ie: gdk-x11-2.0 -> gdk-2.0, etc)
    10001580        PYGTK_PACKAGES += ["gdk-2.0", "gtk+-2.0"]
    10011581        add_packages("xpra.platform.darwin")
     1582        remove_packages("xpra.platform.win32", "xpra.platform.xposix")
     1583        #to support GStreamer 1.x we need this:
     1584        modules.append("importlib")
     1585        modules.append("xpra.scripts.gtk_info")
     1586        modules.append("xpra.scripts.show_webcam")
    10021587    else:
    10031588        PYGTK_PACKAGES += ["gdk-x11-2.0", "gtk+-x11-2.0"]
    10041589        add_packages("xpra.platform.xposix")
    1005         #always include the wrapper in case we need it later:
    1006         #(we remove it during the 'install' step below if it isn't actually needed)
    1007         scripts.append("scripts/xpra_Xdummy")
     1590        remove_packages("xpra.platform.win32", "xpra.platform.darwin")
     1591        #not supported by all distros, but doesn't hurt to install them anyway:
     1592        for x in ("tmpfiles.d", "sysusers.d"):
     1593            add_data_files("lib/%s" % x, ["%s/xpra.conf" % x])
     1594        if uinput_ENABLED:
     1595            add_data_files("lib/udev/rules.d/", ["udev/rules.d/71-xpra-virtual-pointer.rules"])
    10081596
    10091597    #gentoo does weird things, calls --no-compile with build *and* install
     
    10121600    #otherwise we use the flags to skip pkgconfig
    10131601    if ("--no-compile" in sys.argv or "--skip-build" in sys.argv) and not ("build" in sys.argv and "install" in sys.argv):
    1014         def pkgconfig(*pkgs_options, **ekw):
    1015             return {}
    1016     if "install" in sys.argv:
    1017         #prepare default [/usr/local]/etc configuration files:
    1018         if sys.prefix == '/usr':
    1019             etc_prefix = '/etc/xpra'
    1020         else:
    1021             etc_prefix = sys.prefix + '/etc/xpra'
    1022 
    1023         etc_files = []
    1024         if server_ENABLED and x11_ENABLED:
    1025             etc_files = ["etc/xpra/xorg.conf"]
    1026             #figure out the version of the Xorg server:
    1027             xorg_conf, use_Xdummy_wrapper = get_xorg_conf_and_script()
    1028             if not use_Xdummy_wrapper and "scripts/xpra_Xdummy" in scripts:
    1029                 #if we're not using the wrapper, don't install it
    1030                 scripts.remove("scripts/xpra_Xdummy")
    1031             etc_files.append(xorg_conf)
    1032         data_files.append((etc_prefix, etc_files))
     1602        pkgconfig = no_pkgconfig
    10331603
    10341604    if OSX and "py2app" in sys.argv:
     
    10451615        remove_packages(*external_excludes)
    10461616
    1047         Plist = {"CFBundleDocumentTypes" : {
    1048                         "CFBundleTypeExtensions"    : ["Xpra"],
    1049                         "CFBundleTypeName"          : "Xpra Session Config File",
    1050                         "CFBundleName"              : "Xpra",
    1051                         "CFBundleTypeRole"          : "Viewer",
    1052                         }}
     1617        try:
     1618            from xpra.src_info import REVISION
     1619        except:
     1620            REVISION = "unknown"
     1621        Plist = {
     1622            "CFBundleDocumentTypes" : {
     1623                "CFBundleTypeExtensions"    : ["Xpra"],
     1624                "CFBundleTypeName"          : "Xpra Session Config File",
     1625                "CFBundleName"              : "Xpra",
     1626                "CFBundleTypeRole"          : "Viewer",
     1627                },
     1628            "CFBundleGetInfoString" : "%s-r%s (c) 2012-2017 http://xpra.org/" % (XPRA_VERSION, REVISION),
     1629            "CFBundleIdentifier"            : "org.xpra.xpra",
     1630            }
    10531631        #Note: despite our best efforts, py2app will not copy all the modules we need
    10541632        #so the make-app.sh script still has to hack around this problem.
    10551633        add_modules(*external_includes)
     1634        #needed by python-lz4:
     1635        add_modules("distutils")
    10561636        py2app_options = {
    10571637            'iconfile'          : '../osx/xpra.icns',
     
    10651645            }
    10661646        setup_options["options"] = {"py2app": py2app_options}
    1067         setup_options["app"]     = ["xpra/client/gtk2/client_launcher.py"]
     1647        setup_options["app"]     = ["xpra/client/gtk_base/client_launcher.py"]
     1648
     1649    if OSX:
     1650        #simply adding the X11 path to PKG_CONFIG_PATH breaks things in mysterious ways,
     1651        #so instead we have to query each package seperately and merge the results:
     1652        def osx_pkgconfig(*pkgs_options, **ekw):
     1653            kw = dict(ekw)
     1654            for pkg in pkgs_options:
     1655                saved_pcp = os.environ.get("PKG_CONFIG_PATH")
     1656                if pkg.lower().startswith("x"):
     1657                    os.environ["PKG_CONFIG_PATH"] = "/usr/X11/lib/pkgconfig"
     1658                #print("exec_pkgconfig(%s, %s)", pkg, kw)
     1659                kw = exec_pkgconfig(pkg, **kw)
     1660                os.environ["PKG_CONFIG_PATH"] = saved_pcp
     1661            return kw
     1662
     1663        pkgconfig = osx_pkgconfig
    10681664
    10691665
    10701666if html5_ENABLED:
    1071     for k,v in glob_recurse("html5").items():
    1072         if (k!=""):
    1073             k = os.sep+k
    1074         data_files.append((html5_dir+k, v))
    1075 
     1667    if WIN32 or OSX:
     1668        external_includes.append("websockify")
     1669        external_includes.append("numpy")
     1670        external_includes.append("ssl")
     1671        external_includes.append("_ssl")
     1672        if not PYTHON3:
     1673            external_includes.append("mimetypes")
     1674            external_includes.append("mimetools")
     1675            external_includes.append("BaseHTTPServer")
     1676
     1677
     1678if annotate_ENABLED:
     1679    from Cython.Compiler import Options
     1680    Options.annotate = True
    10761681
    10771682
    10781683#*******************************************************************************
    1079 toggle_packages(server_ENABLED, "xpra.server", "xpra.server.stats", "xpra.server.auth")
    1080 toggle_packages(server_ENABLED or gtk2_ENABLED or gtk3_ENABLED, "xpra.gtk_common", "xpra.clipboard")
    1081 
    1082 
    1083 toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.gtk_x11", "xpra.x11.bindings")
     1684buffers_c = "xpra/buffers/buffers.c"
     1685memalign_c = "xpra/buffers/memalign.c"
     1686xxhash_c = "xpra/buffers/xxhash.c"
     1687membuffers_c = [memalign_c, buffers_c, xxhash_c]
     1688
     1689add_packages("xpra.buffers")
     1690buffers_pkgconfig = pkgconfig(optimize=3)
     1691cython_add(Extension("xpra.buffers.membuf",
     1692            ["xpra/buffers/membuf.pyx"]+membuffers_c, **buffers_pkgconfig))
     1693
     1694
     1695toggle_packages(dbus_ENABLED, "xpra.dbus")
     1696toggle_packages(mdns_ENABLED, "xpra.net.mdns")
     1697toggle_packages(server_ENABLED or proxy_ENABLED, "xpra.server", "xpra.server.auth")
     1698toggle_packages(rfb_ENABLED, "xpra.server.rfb")
     1699toggle_packages(proxy_ENABLED, "xpra.server.proxy")
     1700toggle_packages(server_ENABLED, "xpra.server.window")
     1701toggle_packages(shadow_ENABLED, "xpra.server.shadow")
     1702toggle_packages(server_ENABLED or client_ENABLED, "xpra.clipboard")
     1703toggle_packages(x11_ENABLED and dbus_ENABLED and server_ENABLED, "xpra.x11.dbus")
     1704
     1705#cannot use toggle here as cx_Freeze will complain if we try to exclude this module:
     1706if dbus_ENABLED and server_ENABLED:
     1707    add_packages("xpra.server.dbus")
     1708
     1709if OSX and not PYTHON3:
     1710    quartz_pkgconfig = pkgconfig(*PYGTK_PACKAGES)
     1711    add_to_keywords(quartz_pkgconfig, 'extra_compile_args',
     1712                    "-I/System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/Cocoa.h",
     1713                    '-ObjC',
     1714                    '-mmacosx-version-min=10.10')
     1715    add_to_keywords(quartz_pkgconfig, 'extra_link_args',
     1716                    '-framework', 'Foundation',
     1717                    '-framework', 'AppKit',
     1718                    )
     1719    cython_add(Extension("xpra.platform.darwin.gdk_bindings",
     1720                ["xpra/platform/darwin/gdk_bindings.pyx", "xpra/platform/darwin/nsevent_glue.m"],
     1721                language="objc",
     1722                **quartz_pkgconfig
     1723                ))
     1724
     1725monotonic_time_pkgconfig = pkgconfig()
     1726if not OSX and not WIN32:
     1727    add_to_keywords(monotonic_time_pkgconfig, 'extra_link_args', "-lrt")
     1728cython_add(Extension("xpra.monotonic_time",
     1729            ["xpra/monotonic_time.pyx", "xpra/monotonic_ctime.c"],
     1730            **monotonic_time_pkgconfig
     1731            ))
     1732
     1733
     1734toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.bindings")
    10841735if x11_ENABLED:
    10851736    make_constants("xpra", "x11", "bindings", "constants")
    1086     make_constants("xpra", "x11", "gtk_x11", "constants")
     1737    make_constants("xpra", "x11", "gtk2", "constants")
    10871738
    10881739    cython_add(Extension("xpra.x11.bindings.wait_for_x_server",
     
    10981749                **pkgconfig("x11")
    10991750                ))
     1751    cython_add(Extension("xpra.x11.bindings.posix_display_source",
     1752                ["xpra/x11/bindings/posix_display_source.pyx"],
     1753                **pkgconfig("x11")
     1754                ))
     1755
    11001756    cython_add(Extension("xpra.x11.bindings.randr_bindings",
    11011757                ["xpra/x11/bindings/randr_bindings.pyx"],
     
    11041760    cython_add(Extension("xpra.x11.bindings.keyboard_bindings",
    11051761                ["xpra/x11/bindings/keyboard_bindings.pyx"],
    1106                 **pkgconfig("x11", "xtst", "xfixes")
     1762                **pkgconfig("x11", "xtst", "xfixes", "xkbfile")
    11071763                ))
    11081764
    11091765    cython_add(Extension("xpra.x11.bindings.window_bindings",
    11101766                ["xpra/x11/bindings/window_bindings.pyx"],
    1111                 **pkgconfig("xtst", "xfixes", "xcomposite", "xdamage")
     1767                **pkgconfig("x11", "xtst", "xfixes", "xcomposite", "xdamage", "xext")
    11121768                ))
    11131769    cython_add(Extension("xpra.x11.bindings.ximage",
    11141770                ["xpra/x11/bindings/ximage.pyx"],
    1115                 **pkgconfig("xcomposite", "xdamage", "xext")
     1771                **pkgconfig("x11", "xext", "xcomposite")
    11161772                ))
    1117 
    1118     #below uses gtk/gdk:
    1119     cython_add(Extension("xpra.x11.gtk_x11.gdk_display_source",
    1120                 ["xpra/x11/gtk_x11/gdk_display_source.pyx"],
    1121                 **pkgconfig(*PYGTK_PACKAGES)
     1773if xinput_ENABLED:
     1774    cython_add(Extension("xpra.x11.bindings.xi2_bindings",
     1775                ["xpra/x11/bindings/xi2_bindings.pyx"],
     1776                **pkgconfig("x11", "xi")
    11221777                ))
    1123     GDK_BINDINGS_PACKAGES = PYGTK_PACKAGES + ["xfixes", "xdamage"]
    1124     cython_add(Extension("xpra.x11.gtk_x11.gdk_bindings",
    1125                 ["xpra/x11/gtk_x11/gdk_bindings.pyx"],
    1126                 **pkgconfig(*GDK_BINDINGS_PACKAGES)
     1778
     1779toggle_packages(gtk_x11_ENABLED, "xpra.x11.gtk_x11")
     1780if gtk_x11_ENABLED:
     1781    toggle_packages(PYTHON3, "xpra.x11.gtk3")
     1782    toggle_packages(not PYTHON3, "xpra.x11.gtk2", "xpra.x11.gtk2.models")
     1783    if PYTHON3:
     1784        #GTK3 display source:
     1785        cython_add(Extension("xpra.x11.gtk3.gdk_display_source",
     1786                    ["xpra/x11/gtk3/gdk_display_source.pyx"],
     1787                    **pkgconfig("gdk-3.0")
     1788                    ))
     1789    else:
     1790        #GTK2:
     1791        cython_add(Extension("xpra.x11.gtk2.gdk_display_source",
     1792                    ["xpra/x11/gtk2/gdk_display_source.pyx"],
     1793                    **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1794                    ))
     1795        GDK_BINDINGS_PACKAGES = PYGTK_PACKAGES + ["x11", "xext", "xfixes", "xdamage"]
     1796        cython_add(Extension("xpra.x11.gtk2.gdk_bindings",
     1797                    ["xpra/x11/gtk2/gdk_bindings.pyx"],
     1798                    **pkgconfig(*GDK_BINDINGS_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1799                    ))
     1800
     1801toggle_packages(not PYTHON3 and (gtk2_ENABLED or gtk_x11_ENABLED), "xpra.gtk_common.gtk2")
     1802if not PYTHON3 and (gtk2_ENABLED or gtk_x11_ENABLED):
     1803    cython_add(Extension("xpra.gtk_common.gtk2.gdk_bindings",
     1804                ["xpra/gtk_common/gtk2/gdk_bindings.pyx"],
     1805                **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
    11271806                ))
    11281807
    1129 
    1130 toggle_packages(argb_ENABLED, "xpra.codecs.argb")
    1131 if argb_ENABLED:
     1808if client_ENABLED and gtk3_ENABLED:
     1809    #cairo workaround:
     1810    if OSX:
     1811        pycairo = "py3cairo"
     1812    else:
     1813        pycairo = "pycairo"
     1814    cython_add(Extension("xpra.client.gtk3.cairo_workaround",
     1815                ["xpra/client/gtk3/cairo_workaround.pyx"],
     1816                **pkgconfig(pycairo)
     1817                ))
     1818
     1819if client_ENABLED or server_ENABLED:
     1820    add_packages("xpra.codecs.argb")
     1821    argb_pkgconfig = pkgconfig(optimize=3)
    11321822    cython_add(Extension("xpra.codecs.argb.argb",
    1133                 ["xpra/codecs/argb/argb.pyx"]))
     1823                ["xpra/codecs/argb/argb.pyx"], **argb_pkgconfig))
     1824
     1825
     1826#build tests, but don't install them:
     1827toggle_packages(tests_ENABLED, "unit")
    11341828
    11351829
    11361830if bundle_tests_ENABLED:
    11371831    #bundle the tests directly (not in library.zip):
    1138     for k,v in glob_recurse("tests").items():
     1832    for k,v in glob_recurse("unit").items():
    11391833        if (k!=""):
    11401834            k = os.sep+k
    1141         data_files.append(("tests"+k, v))
    1142 
    1143 #special case for client: cannot use toggle_packages which would include gtk3, qt, etc:
     1835        add_data_files("unit"+k, v)
     1836
     1837#python-cryptography needs workarounds for bundling:
     1838if crypto_ENABLED and (OSX or WIN32):
     1839    external_includes.append("_ssl")
     1840    external_includes.append("cffi")
     1841    external_includes.append("_cffi_backend")
     1842    external_includes.append("cryptography")
     1843    external_includes.append("pkg_resources._vendor.packaging")
     1844    external_includes.append("pkg_resources._vendor.packaging.requirements")
     1845    external_includes.append("pkg_resources._vendor.pyparsing")
     1846    add_modules("cryptography.hazmat.bindings._openssl")
     1847    add_modules("cryptography.hazmat.bindings._constant_time")
     1848    add_modules("cryptography.hazmat.bindings._padding")
     1849    add_modules("cryptography.hazmat.backends.openssl")
     1850    add_modules("cryptography.fernet")
     1851    if WIN32:
     1852        external_includes.append("appdirs")
     1853
     1854#special case for client: cannot use toggle_packages which would include gtk3, etc:
    11441855if client_ENABLED:
    11451856    add_modules("xpra.client", "xpra.client.notifications")
    1146 toggle_packages((client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED)) or server_ENABLED, "xpra.gtk_common")
     1857toggle_packages((client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED)) or (PYTHON3 and sound_ENABLED) or server_ENABLED, "xpra.gtk_common")
    11471858toggle_packages(client_ENABLED and gtk2_ENABLED, "xpra.client.gtk2")
    1148 toggle_packages(client_ENABLED and gtk3_ENABLED, "xpra.client.gtk3", "gi")
    1149 toggle_packages(client_ENABLED and qt4_ENABLED, "xpra.client.qt4", "PyQt4")
     1859toggle_packages(client_ENABLED and gtk3_ENABLED, "xpra.client.gtk3")
     1860toggle_packages((client_ENABLED and gtk3_ENABLED) or (sound_ENABLED and WIN32 and (MINGW_PREFIX or PYTHON3)), "gi")
    11501861toggle_packages(client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED), "xpra.client.gtk_base")
    1151 toggle_packages(sound_ENABLED, "xpra.sound")
    1152 toggle_packages(webm_ENABLED, "xpra.codecs.webm")
    1153 toggle_packages(client_ENABLED and gtk2_ENABLED and opengl_ENABLED, "xpra.client.gl")
     1862toggle_packages(client_ENABLED and opengl_ENABLED and gtk2_ENABLED, "xpra.client.gl.gtk2")
     1863toggle_packages(client_ENABLED and opengl_ENABLED and gtk3_ENABLED, "xpra.client.gl.gtk3")
     1864toggle_packages(client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED) and example_ENABLED, "xpra.client.gtk_base.example")
     1865if client_ENABLED and WIN32 and MINGW_PREFIX:
     1866    propsys_pkgconfig = pkgconfig()
     1867    if debug_ENABLED:
     1868        add_to_keywords(propsys_pkgconfig, 'extra_compile_args', "-DDEBUG")
     1869    add_to_keywords(propsys_pkgconfig, 'extra_link_args', "-luuid", "-lshlwapi", "-lole32", "-static-libgcc")
     1870    cython_add(Extension("xpra.platform.win32.propsys",
     1871                ["xpra/platform/win32/propsys.pyx", "xpra/platform/win32/setappid.cpp"],
     1872                language="c++",
     1873                **propsys_pkgconfig))
     1874
     1875if client_ENABLED or server_ENABLED:
     1876    add_modules("xpra.codecs")
     1877toggle_packages(client_ENABLED or server_ENABLED, "xpra.keyboard")
     1878if client_ENABLED or server_ENABLED:
     1879    add_modules("xpra.scripts.config", "xpra.scripts.exec_util", "xpra.scripts.fdproxy", "xpra.scripts.version")
     1880if server_ENABLED or proxy_ENABLED:
     1881    add_modules("xpra.scripts.server")
     1882if WIN32 and client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED):
     1883    add_modules("xpra.scripts.gtk_info")
     1884
     1885toggle_packages(not WIN32, "xpra.platform.pycups_printing")
     1886#we can't just include "xpra.client.gl" because cx_freeze then do the wrong thing
     1887#and tries to include both gtk3 and gtk2, and fails hard..
     1888for x in ("gl_check", "gl_colorspace_conversions", "gl_window_backing_base", "gl_drivers"):
     1889    toggle_packages(client_ENABLED and opengl_ENABLED, "xpra.client.gl.%s" % x)
     1890toggle_packages(client_ENABLED and opengl_ENABLED and (gtk2_ENABLED or gtk3_ENABLED), "xpra.client.gl.gtk_base")
     1891
     1892
     1893toggle_modules(sound_ENABLED, "xpra.sound")
     1894toggle_modules(sound_ENABLED and not (OSX or WIN32), "xpra.sound.pulseaudio")
    11541895
    11551896toggle_packages(clipboard_ENABLED, "xpra.clipboard")
    11561897if clipboard_ENABLED:
    1157     cython_add(Extension("xpra.gtk_common.gdk_atoms",
    1158                 ["xpra/gtk_common/gdk_atoms.pyx"],
    1159                 **pkgconfig(*PYGTK_PACKAGES)
    1160                 ))
    1161 
    1162 if cyxor_ENABLED:
     1898    if PYTHON3:
     1899        cython_add(Extension("xpra.gtk_common.gtk3.gdk_atoms",
     1900                             ["xpra/gtk_common/gtk3/gdk_atoms.pyx"],
     1901                             **pkgconfig("gtk+-3.0")
     1902                             ))
     1903    else:
     1904        cython_add(Extension("xpra.gtk_common.gtk2.gdk_atoms",
     1905                             ["xpra/gtk_common/gtk2/gdk_atoms.pyx"],
     1906                             **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1907                             ))
     1908
     1909toggle_packages(client_ENABLED or server_ENABLED, "xpra.codecs.xor")
     1910if client_ENABLED or server_ENABLED:
    11631911    cython_add(Extension("xpra.codecs.xor.cyxor",
    11641912                ["xpra/codecs/xor/cyxor.pyx"],
    1165                 **pkgconfig()))
    1166 
    1167 if cymaths_ENABLED:
    1168     cython_add(Extension("xpra.server.stats.cymaths",
    1169                 ["xpra/server/stats/cymaths.pyx"],
    1170                 **pkgconfig()))
    1171 
    1172 
    1173 #needed for both nvenc and csc_cuda:
    1174 toggle_packages(csc_nvcuda_ENABLED or nvenc_ENABLED, "xpra.codecs.cuda_common")
    1175 
    1176 toggle_packages(csc_opencl_ENABLED, "xpra.codecs.csc_opencl")
    1177 toggle_packages(csc_nvcuda_ENABLED, "xpra.codecs.csc_nvcuda")
     1913                **pkgconfig(optimize=3)))
     1914
     1915if server_ENABLED or shadow_ENABLED:
     1916    O3_pkgconfig = pkgconfig(optimize=3)
     1917    cython_add(Extension("xpra.server.cystats",
     1918                ["xpra/server/cystats.pyx"],
     1919                **O3_pkgconfig))
     1920    cython_add(Extension("xpra.server.window.region",
     1921                ["xpra/server/window/region.pyx"],
     1922                **O3_pkgconfig))
     1923    cython_add(Extension("xpra.server.window.motion",
     1924                ["xpra/server/window/motion.pyx"],
     1925                **O3_pkgconfig))
     1926
     1927if sd_listen_ENABLED:
     1928    sdp = pkgconfig("libsystemd")
     1929    cython_add(Extension("xpra.platform.xposix.sd_listen",
     1930                ["xpra/platform/xposix/sd_listen.pyx"],
     1931                **sdp))
     1932
     1933
    11781934toggle_packages(enc_proxy_ENABLED, "xpra.codecs.enc_proxy")
    11791935
     1936toggle_packages(nvfbc_ENABLED, "xpra.codecs.nvfbc")
     1937if nvfbc_ENABLED:
     1938    nvfbc_pkgconfig = pkgconfig("nvfbc")
     1939    #add_to_keywords(nvfbc_pkgconfig, 'extra_compile_args', "-Wno-endif-labels")
     1940    platform = sys.platform.rstrip("0123456789")
     1941    cython_add(Extension("xpra.codecs.nvfbc.fbc_capture_%s" % platform,
     1942                         ["xpra/codecs/nvfbc/fbc_capture_%s.pyx" % platform],
     1943                         language="c++",
     1944                         **nvfbc_pkgconfig))
     1945
    11801946toggle_packages(nvenc_ENABLED, "xpra.codecs.nvenc")
     1947toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.cuda_common")
     1948toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.nv_util")
     1949
     1950if nvenc_ENABLED and cuda_kernels_ENABLED:
     1951    #find nvcc:
     1952    path_options = os.environ.get("PATH", "").split(os.path.pathsep)
     1953    if WIN32:
     1954        nvcc_exe = "nvcc.exe"
     1955        path_options = [
     1956                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin",
     1957                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\bin",
     1958                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.5\\bin",
     1959                         ] + path_options
     1960        #pycuda may link against curand, find it and ship it:
     1961        for p in path_options:
     1962            if os.path.exists(p):
     1963                add_data_files("", glob.glob("%s\\curand64*.dll" % p))
     1964                break
     1965    else:
     1966        nvcc_exe = "nvcc"
     1967        for v in ("", "-9.0", "-8.0", "-7.5"):
     1968            path_options += ["/usr/local/cuda%s/bin" % v, "/opt/cuda%s/bin" % v]
     1969    options = [os.path.join(x, nvcc_exe) for x in path_options]
     1970    def which(cmd):
     1971        try:
     1972            code, out, _ = get_status_output(["which", cmd])
     1973            if code==0:
     1974                return out
     1975        except:
     1976            pass
     1977    #prefer the one we find on the $PATH, if any:
     1978    try:
     1979        v = which(nvcc_exe)
     1980        if v and (v not in options):
     1981            options.insert(0, v)
     1982    except:
     1983        pass
     1984    nvcc_versions = {}
     1985    for filename in options:
     1986        if not os.path.exists(filename):
     1987            continue
     1988        code, out, err = get_status_output([filename, "--version"])
     1989        if code==0:
     1990            vpos = out.rfind(", V")
     1991            if vpos>0:
     1992                version = out[vpos+3:].strip("\n")
     1993                version_str = " version %s" % version
     1994            else:
     1995                version = "0"
     1996                version_str = " unknown version!"
     1997            print("found CUDA compiler: %s%s" % (filename, version_str))
     1998            nvcc_versions[version] = filename
     1999    assert nvcc_versions, "cannot find nvcc compiler!"
     2000    #choose the most recent one:
     2001    version, nvcc = list(reversed(sorted(nvcc_versions.items())))[0]
     2002    if len(nvcc_versions)>1:
     2003        print(" using version %s from %s" % (version, nvcc))
     2004    if WIN32:
     2005        cuda_path = os.path.dirname(nvcc)           #strip nvcc.exe
     2006        cuda_path = os.path.dirname(cuda_path)      #strip /bin/
     2007    #first compile the cuda kernels
     2008    #(using the same cuda SDK for both nvenc modules for now..)
     2009    #TODO:
     2010    # * compile directly to output directory instead of using data files?
     2011    # * detect which arches we want to build for? (does it really matter much?)
     2012    kernels = ("ARGB_to_NV12", "ARGB_to_YUV444", "BGRA_to_NV12", "BGRA_to_YUV444")
     2013    for kernel in kernels:
     2014        cuda_src = "xpra/codecs/cuda_common/%s.cu" % kernel
     2015        cuda_bin = "xpra/codecs/cuda_common/%s.fatbin" % kernel
     2016        if os.path.exists(cuda_bin) and (cuda_rebuild_ENABLED is False):
     2017            continue
     2018        reason = should_rebuild(cuda_src, cuda_bin)
     2019        if not reason:
     2020            continue
     2021        cmd = [nvcc,
     2022               '-fatbin',
     2023               #"-cubin",
     2024               #"-arch=compute_30", "-code=compute_30,sm_30,sm_35",
     2025               #"-gencode=arch=compute_50,code=sm_50",
     2026               #"-gencode=arch=compute_52,code=sm_52",
     2027               #"-gencode=arch=compute_52,code=compute_52",
     2028               "-c", cuda_src,
     2029               "-o", cuda_bin]
     2030        #GCC 6 uses C++11 by default:
     2031        if get_gcc_version()>=[6, 0]:
     2032            cmd.append("-std=c++11")
     2033        CL_VERSION = os.environ.get("CL_VERSION")
     2034        if CL_VERSION:
     2035            cmd += ["--use-local-env", "--cl-version", CL_VERSION]
     2036            #-ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cl.exe"
     2037            cmd += ["--machine", "32"]
     2038        if WIN32:
     2039            #cmd += ["--compiler-bindir", "C:\\msys64\\mingw64\\bin\\g++.exe"]
     2040            #cmd += ["--input-drive-prefix", "/"]
     2041            #cmd += ["--dependency-drive-prefix", "/"]
     2042            cmd += ["-I%s" % os.path.abspath("win32")]
     2043        comp_code_options = [(30, 30), (35, 35)]
     2044        #see: http://docs.nvidia.com/cuda/maxwell-compatibility-guide/#building-maxwell-compatible-apps-using-cuda-6-0
     2045        if version!="0" and version<"7.5":
     2046            print("CUDA version %s is very unlikely to work")
     2047            print("try upgrading to version 7.5 or later")
     2048        if version>="7.5":
     2049            comp_code_options.append((50, 50))
     2050            comp_code_options.append((52, 52))
     2051            comp_code_options.append((53, 53))
     2052        if version>="8.0":
     2053            comp_code_options.append((60, 60))
     2054            comp_code_options.append((61, 61))
     2055            comp_code_options.append((62, 62))
     2056        if version>="9.0":
     2057            comp_code_options.append((70, 70))
     2058        for arch, code in comp_code_options:
     2059            cmd.append("-gencode=arch=compute_%s,code=sm_%s" % (arch, code))
     2060        print("CUDA compiling %s (%s)" % (kernel.ljust(16), reason))
     2061        print(" %s" % " ".join("'%s'" % x for x in cmd))
     2062        c, stdout, stderr = get_status_output(cmd)
     2063        if c!=0:
     2064            print("Error: failed to compile CUDA kernel %s" % kernel)
     2065            print(stdout or "")
     2066            print(stderr or "")
     2067            sys.exit(1)
     2068    CUDA_BIN = "share/xpra/cuda"
     2069    if WIN32:
     2070        CUDA_BIN = "CUDA"
     2071    add_data_files(CUDA_BIN, ["xpra/codecs/cuda_common/%s.fatbin" % x for x in kernels])
     2072
    11812073if nvenc_ENABLED:
    1182     make_constants("xpra", "codecs", "nvenc", "constants")
    1183     nvenc_pkgconfig = pkgconfig("nvenc3", "cuda")
    1184     cython_add(Extension("xpra.codecs.nvenc.encoder",
    1185                          ["xpra/codecs/nvenc/encoder.pyx"],
    1186                          **nvenc_pkgconfig), min_version=(0, 16))
     2074    nvencmodule = "nvenc"
     2075    nvenc_pkgconfig = pkgconfig(nvencmodule, ignored_flags=["-l", "-L"])
     2076    #don't link against libnvidia-encode, we load it dynamically:
     2077    libraries = nvenc_pkgconfig.get("libraries", [])
     2078    if "nvidia-encode" in libraries:
     2079        libraries.remove("nvidia-encode")
     2080    if PYTHON3 and get_gcc_version()>=[6, 2]:
     2081        #with gcc 6.2 on Fedora:
     2082        #xpra/codecs/nvenc/encoder.c: In function '__Pyx_PyInt_LshiftObjC':
     2083        #xpra/codecs/nvenc/encoder.c:45878:34: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
     2084        #    if (unlikely(!(b < sizeof(long)*8 && a == x >> b)) && a) {
     2085        add_to_keywords(nvenc_pkgconfig, 'extra_compile_args', "-Wno-sign-compare")
     2086    cython_add(Extension("xpra.codecs.%s.encoder" % nvencmodule,
     2087                         ["xpra/codecs/%s/encoder.pyx" % nvencmodule],
     2088                         **nvenc_pkgconfig))
    11872089
    11882090toggle_packages(enc_x264_ENABLED, "xpra.codecs.enc_x264")
    11892091if enc_x264_ENABLED:
    1190     x264_pkgconfig = pkgconfig("x264", static=x264_static_ENABLED)
     2092    x264_pkgconfig = pkgconfig("x264")
     2093    if get_gcc_version()>=[6, 0]:
     2094        add_to_keywords(x264_pkgconfig, 'extra_compile_args', "-Wno-unused-variable")
    11912095    cython_add(Extension("xpra.codecs.enc_x264.encoder",
    11922096                ["xpra/codecs/enc_x264/encoder.pyx"],
    1193                 **x264_pkgconfig), min_version=(0, 16))
     2097                **x264_pkgconfig))
    11942098
    11952099toggle_packages(enc_x265_ENABLED, "xpra.codecs.enc_x265")
    11962100if enc_x265_ENABLED:
    1197     x265_pkgconfig = pkgconfig("x265", static=x265_static_ENABLED)
     2101    x265_pkgconfig = pkgconfig("x265")
    11982102    cython_add(Extension("xpra.codecs.enc_x265.encoder",
    11992103                ["xpra/codecs/enc_x265/encoder.pyx"],
    1200                 **x265_pkgconfig), min_version=(0, 16))
     2104                **x265_pkgconfig))
     2105
     2106toggle_packages(pillow_ENABLED, "xpra.codecs.pillow")
     2107if pillow_ENABLED:
     2108    external_includes += ["PIL", "PIL.Image", "PIL.WebPImagePlugin"]
    12012109
    12022110toggle_packages(webp_ENABLED, "xpra.codecs.webp")
     
    12042112    webp_pkgconfig = pkgconfig("webp")
    12052113    cython_add(Extension("xpra.codecs.webp.encode",
    1206                 ["xpra/codecs/webp/encode.pyx"],
    1207                 **webp_pkgconfig), min_version=(0, 16))
    1208 
    1209 toggle_packages(dec_avcodec_ENABLED, "xpra.codecs.dec_avcodec")
    1210 if dec_avcodec_ENABLED:
    1211     make_constants("xpra", "codecs", "dec_avcodec", "constants")
    1212     avcodec_pkgconfig = pkgconfig("avcodec", "avutil", static=avcodec_static_ENABLED)
    1213     cython_add(Extension("xpra.codecs.dec_avcodec.decoder",
    1214                 ["xpra/codecs/dec_avcodec/decoder.pyx", "xpra/codecs/memalign/memalign.c", "xpra/codecs/inline.c"],
    1215                 **avcodec_pkgconfig), min_version=(0, 19))
     2114                    ["xpra/codecs/webp/encode.pyx"],
     2115                    **webp_pkgconfig))
     2116    cython_add(Extension("xpra.codecs.webp.decode",
     2117                ["xpra/codecs/webp/decode.pyx"],
     2118                **webp_pkgconfig))
     2119
     2120toggle_packages(jpeg_ENABLED, "xpra.codecs.jpeg")
     2121if jpeg_ENABLED:
     2122    jpeg_pkgconfig = pkgconfig("libturbojpeg")
     2123    cython_add(Extension("xpra.codecs.jpeg.encoder",
     2124                ["xpra/codecs/jpeg/encoder.pyx"],
     2125                **jpeg_pkgconfig))
     2126    cython_add(Extension("xpra.codecs.jpeg.decoder",
     2127                ["xpra/codecs/jpeg/decoder.pyx"],
     2128                **jpeg_pkgconfig))
     2129
     2130#swscale and avcodec2 use libav_common/av_log:
     2131libav_common = dec_avcodec2_ENABLED or csc_swscale_ENABLED
     2132toggle_packages(libav_common, "xpra.codecs.libav_common")
     2133if libav_common:
     2134    avutil_pkgconfig = pkgconfig("avutil")
     2135    cython_add(Extension("xpra.codecs.libav_common.av_log",
     2136                ["xpra/codecs/libav_common/av_log.pyx"],
     2137                **avutil_pkgconfig))
     2138
    12162139
    12172140toggle_packages(dec_avcodec2_ENABLED, "xpra.codecs.dec_avcodec2")
    12182141if dec_avcodec2_ENABLED:
    1219     avcodec2_pkgconfig = pkgconfig("avcodec", "avutil", static=avcodec2_static_ENABLED)
     2142    avcodec2_pkgconfig = pkgconfig("avcodec", "avutil")
    12202143    cython_add(Extension("xpra.codecs.dec_avcodec2.decoder",
    1221                 ["xpra/codecs/dec_avcodec2/decoder.pyx", "xpra/codecs/memalign/memalign.c", "xpra/codecs/inline.c"],
    1222                 **avcodec2_pkgconfig), min_version=(0, 19))
    1223 
     2144                ["xpra/codecs/dec_avcodec2/decoder.pyx"],
     2145                **avcodec2_pkgconfig))
     2146
     2147
     2148toggle_packages(csc_libyuv_ENABLED, "xpra.codecs.csc_libyuv")
     2149if csc_libyuv_ENABLED:
     2150    libyuv_pkgconfig = pkgconfig("libyuv")
     2151    cython_add(Extension("xpra.codecs.csc_libyuv.colorspace_converter",
     2152                ["xpra/codecs/csc_libyuv/colorspace_converter.pyx"],
     2153                language="c++",
     2154                **libyuv_pkgconfig))
    12242155
    12252156toggle_packages(csc_swscale_ENABLED, "xpra.codecs.csc_swscale")
    12262157if csc_swscale_ENABLED:
    1227     make_constants("xpra", "codecs", "csc_swscale", "constants")
    1228     swscale_pkgconfig = pkgconfig("swscale", static=swscale_static_ENABLED)
     2158    swscale_pkgconfig = pkgconfig("swscale", "avutil")
    12292159    cython_add(Extension("xpra.codecs.csc_swscale.colorspace_converter",
    1230                 ["xpra/codecs/csc_swscale/colorspace_converter.pyx", "xpra/codecs/memalign/memalign.c", "xpra/codecs/inline.c"],
    1231                 **swscale_pkgconfig), min_version=(0, 19))
    1232 
    1233 toggle_packages(csc_cython_ENABLED, "xpra.codecs.csc_cython")
    1234 if csc_cython_ENABLED:
    1235     csc_cython_pkgconfig = pkgconfig()
    1236     cython_add(Extension("xpra.codecs.csc_cython.colorspace_converter",
    1237                 ["xpra/codecs/csc_cython/colorspace_converter.pyx", "xpra/codecs/memalign/memalign.c"],
    1238                 **csc_cython_pkgconfig), min_version=(0, 15))
     2160                ["xpra/codecs/csc_swscale/colorspace_converter.pyx"],
     2161                **swscale_pkgconfig))
     2162
    12392163
    12402164toggle_packages(vpx_ENABLED, "xpra.codecs.vpx")
    12412165if vpx_ENABLED:
    1242     vpx_pkgconfig = pkgconfig("vpx", static=vpx_static_ENABLED)
     2166    vpx_pkgconfig = pkgconfig("vpx")
    12432167    cython_add(Extension("xpra.codecs.vpx.encoder",
    1244                 ["xpra/codecs/vpx/encoder.pyx", "xpra/codecs/vpx/vpxlib.c", "xpra/codecs/memalign/memalign.c"],
    1245                 **vpx_pkgconfig), min_version=(0, 16))
     2168                ["xpra/codecs/vpx/encoder.pyx"],
     2169                **vpx_pkgconfig))
    12462170    cython_add(Extension("xpra.codecs.vpx.decoder",
    1247                 ["xpra/codecs/vpx/decoder.pyx", "xpra/codecs/memalign/memalign.c"],
    1248                 **vpx_pkgconfig), min_version=(0, 16))
    1249 
    1250 
    1251 toggle_packages(rencode_ENABLED, "xpra.net.rencode")
    1252 if rencode_ENABLED:
    1253     rencode_pkgconfig = pkgconfig()
    1254     if not debug_ENABLED:
    1255         if WIN32:
    1256             add_to_keywords(rencode_pkgconfig, 'extra_compile_args', "/Ox")
    1257         else:
    1258             add_to_keywords(rencode_pkgconfig, 'extra_compile_args', "-O3")
    1259     cython_add(Extension("xpra.net.rencode._rencode",
    1260                 ["xpra/net/rencode/rencode.pyx"],
    1261                 **rencode_pkgconfig))
     2171                ["xpra/codecs/vpx/decoder.pyx"],
     2172                **vpx_pkgconfig))
     2173
     2174toggle_packages(enc_ffmpeg_ENABLED, "xpra.codecs.enc_ffmpeg")
     2175if enc_ffmpeg_ENABLED:
     2176    ffmpeg_pkgconfig = pkgconfig("libavcodec", "libavformat", "libavutil")
     2177    cython_add(Extension("xpra.codecs.enc_ffmpeg.encoder",
     2178                ["xpra/codecs/enc_ffmpeg/encoder.pyx"],
     2179                **ffmpeg_pkgconfig))
     2180
     2181toggle_packages(v4l2_ENABLED, "xpra.codecs.v4l2")
     2182if v4l2_ENABLED:
     2183    v4l2_pkgconfig = pkgconfig()
     2184    #fuly warning: cython makes this difficult,
     2185    #we have to figure out if "device_caps" exists in the headers:
     2186    ENABLE_DEVICE_CAPS = False
     2187    if os.path.exists("/usr/include/linux/videodev2.h"):
     2188        hdata = open("/usr/include/linux/videodev2.h").read()
     2189        ENABLE_DEVICE_CAPS = hdata.find("device_caps")>=0
     2190    kwargs = {"ENABLE_DEVICE_CAPS" : ENABLE_DEVICE_CAPS}
     2191    make_constants("xpra", "codecs", "v4l2", "constants", **kwargs)
     2192    cython_add(Extension("xpra.codecs.v4l2.pusher",
     2193                ["xpra/codecs/v4l2/pusher.pyx"],
     2194                **v4l2_pkgconfig))
    12622195
    12632196
    12642197toggle_packages(bencode_ENABLED, "xpra.net.bencode")
     2198toggle_packages(bencode_ENABLED and cython_bencode_ENABLED, "xpra.net.bencode.cython_bencode")
    12652199if cython_bencode_ENABLED:
    1266     bencode_pkgconfig = pkgconfig()
    1267     if not debug_ENABLED:
    1268         if WIN32:
    1269             add_to_keywords(bencode_pkgconfig, 'extra_compile_args', "/Ox")
    1270         else:
    1271             add_to_keywords(bencode_pkgconfig, 'extra_compile_args', "-O3")
     2200    bencode_pkgconfig = pkgconfig(optimize=not debug_ENABLED)
    12722201    cython_add(Extension("xpra.net.bencode.cython_bencode",
    12732202                ["xpra/net/bencode/cython_bencode.pyx"],
    12742203                **bencode_pkgconfig))
    12752204
     2205if netdev_ENABLED:
     2206    netdev_pkgconfig = pkgconfig()
     2207    cython_add(Extension("xpra.platform.xposix.netdev_query",
     2208                ["xpra/platform/xposix/netdev_query.pyx"],
     2209                **netdev_pkgconfig))
     2210
     2211if vsock_ENABLED:
     2212    vsock_pkgconfig = pkgconfig()
     2213    cython_add(Extension("xpra.net.vsock",
     2214                ["xpra/net/vsock.pyx"],
     2215                **vsock_pkgconfig))
     2216
     2217if pam_ENABLED:
     2218    pam_pkgconfig = pkgconfig()
     2219    add_to_keywords(pam_pkgconfig, 'extra_compile_args', "-I/usr/include/pam", "-I/usr/include/security")
     2220    add_to_keywords(pam_pkgconfig, 'extra_link_args', "-lpam", "-lpam_misc")
     2221    cython_add(Extension("xpra.server.pam",
     2222                ["xpra/server/pam.pyx"],
     2223                **pam_pkgconfig))
     2224
    12762225
    12772226if ext_modules:
    1278     setup_options["ext_modules"] = ext_modules
     2227    from Cython.Build import cythonize
     2228    #this causes Cython to fall over itself:
     2229    #gdb_debug=debug_ENABLED
     2230    setup_options["ext_modules"] = cythonize(ext_modules, gdb_debug=False)
    12792231if cmdclass:
    12802232    setup_options["cmdclass"] = cmdclass
     
    12832235
    12842236
    1285 def print_option(prefix, k, v):
    1286     if type(v)==dict:
    1287         print("%s* %s:" % (prefix, k))
    1288         for kk,vv in v.items():
    1289             print_option(" "+prefix, kk, vv)
    1290     else:
    1291         print("%s* %s=%s" % (prefix, k, v))
    1292 
    12932237def main():
    12942238    if OSX or WIN32 or debug_ENABLED:
     2239        print()
    12952240        print("setup options:")
     2241        if verbose_ENABLED:
     2242            print("setup_options=%s" % (setup_options,))
     2243        try:
     2244            from xpra.util import repr_ellipsized as pv
     2245        except:
     2246            def pv(v):
     2247                return str(v)
    12962248        for k,v in setup_options.items():
    1297             print_option("", k, v)
     2249            print_option("", k, pv(v))
    12982250        print("")
    12992251
Note: See TracChangeset for help on using the changeset viewer.