xpra icon
Bug tracker and wiki

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


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/setup.py

    r6000 r19058  
    22
    33# This file is part of Xpra.
    4 # Copyright (C) 2010-2014 Antoine Martin <antoine@devloop.org.uk>
     4# Copyright (C) 2010-2018 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")
     69OPENBSD = sys.platform.startswith("openbsd")
     70
     71PYTHON3 = sys.version_info[0] == 3
     72POSIX = os.name=="posix"
     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, BITS
     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      = pkg_config_version("58.18", "libavcodec")
     193#opencv currently broken on 32-bit windows (crashes on load):
     194webcam_ENABLED          = DEFAULT and not OSX and (not WIN32 or BITS==64)
     195v4l2_ENABLED            = DEFAULT and (not WIN32 and not OSX and not FREEBSD and not OPENBSD)
     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
    386     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"
     605    try:
     606        pxi_file = kwargs.pop("pxi_file")
     607    except KeyError:
     608        pxi_file = "%s.pxi" % base
     609    reason = should_rebuild(constants_file, pxi_file)
    394610    if reason:
    395611        if verbose_ENABLED:
    396612            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
     613        make_constants_pxi(constants_file, pxi_file, **kwargs)
     614
    414615
    415616# 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 
     617def exec_pkgconfig(*pkgs_options, **ekw):
    423618    kw = dict(ekw)
     619    optimize = kw.pop("optimize", None)
     620    if optimize and not debug_ENABLED:
     621        if type(optimize)==bool:
     622            optimize = int(optimize)*3
     623        add_to_keywords(kw, 'extra_compile_args', "-O%i" % optimize)
     624    ignored_flags = kw.pop("ignored_flags", [])
     625    ignored_tokens = kw.pop("ignored_tokens", [])
     626
    424627    if len(pkgs_options)>0:
    425628        package_names = []
     
    438641            for option in options:
    439642                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:
     643                r, _, _ = get_status_output(cmd)
     644                if r==0:
    443645                    valid_option = option
    444646                    break
    445647            if not valid_option:
    446                 sys.exit("ERROR: cannot find a valid pkg-config package for %s" % (options,))
     648                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)")))
    447649            package_names.append(valid_option)
    448650        if verbose_ENABLED and list(pkgs_options)!=list(package_names):
    449             print("pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
     651            print("exec_pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
    450652        flag_map = {'-I': 'include_dirs',
    451653                    '-L': 'library_dirs',
    452654                    '-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))
     655        pkg_config_cmd = ["pkg-config", "--libs", "--cflags", "%s" % (" ".join(package_names),)]
     656        r, pkg_config_out, err = get_status_output(pkg_config_cmd)
     657        if r!=0:
     658            sys.exit("ERROR: call to '%s' failed (err=%s)" % (" ".join(cmd), err))
     659        env_cflags = os.environ.get("CFLAGS")       #["dpkg-buildflags", "--get", "CFLAGS"]
     660        env_ldflags = os.environ.get("LDFLAGS")     #["dpkg-buildflags", "--get", "LDFLAGS"]
     661        for s in (pkg_config_out, env_cflags, env_ldflags):
     662            if not s:
     663                continue
     664            for token in s.split():
     665                if token in ignored_tokens:
     666                    pass
     667                elif token[:2] in ignored_flags:
     668                    pass
     669                elif token[:2] in flag_map:
     670                    add_to_keywords(kw, flag_map.get(token[:2]), token[2:])
     671                elif token.startswith("-W"):
     672                    add_to_keywords(kw, 'extra_compile_args', token)
     673                else:# throw others to extra_link_args
     674                    add_to_keywords(kw, 'extra_link_args', token)
    468675    if warn_ENABLED:
    469676        add_to_keywords(kw, 'extra_compile_args', "-Wall")
    470677        add_to_keywords(kw, 'extra_link_args', "-Wall")
    471678    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"
     679        if os.environ.get("CC", "").find("clang")>=0:
     680            #clang emits too many warnings with cython code,
     681            #so we can't enable Werror without turning off some warnings:
     682            #this list of flags should allow clang to build the whole source tree,
     683            #as of Cython 0.26 + clang 4.0. Other version combinations may require
     684            #(un)commenting other switches.
     685            eifd = ["-Werror",
     686                    #"-Wno-unneeded-internal-declaration",
     687                    #"-Wno-unknown-attributes",
     688                    #"-Wno-unused-function",
     689                    #"-Wno-self-assign",
     690                    #"-Wno-sometimes-uninitialized",
     691                    #cython adds rpath to the compilation command??
     692                    #and the "-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1" is also ignored by clang:
     693                    "-Wno-unused-command-line-argument",
     694                    ]
     695        elif get_gcc_version()>=[4, 4]:
     696            eifd = ["-Werror"]
     697            if is_Debian() or is_Ubuntu() or is_Raspbian():
     698                #needed on Debian and Ubuntu to avoid this error:
     699                #/usr/include/gtk-2.0/gtk/gtkitemfactory.h:47:1: error: function declaration isn't a prototype [-Werror=strict-prototypes]
     700                eifd.append("-Wno-error=strict-prototypes")
     701            if NETBSD:
     702                #see: http://trac.cython.org/ticket/395
     703                eifd += ["-fno-strict-aliasing"]
     704            elif FREEBSD:
     705                eifd += ["-Wno-error=unused-function"]
    475706        else:
    476             eifd = "-Werror-implicit-function-declaration"
    477         add_to_keywords(kw, 'extra_compile_args', eifd)
     707            #older versions of OSX ship an old gcc,
     708            #not much we can do with this:
     709            eifd = []
     710        for eif in eifd:
     711            add_to_keywords(kw, 'extra_compile_args', eif)
    478712    if PIC_ENABLED:
    479713        add_to_keywords(kw, 'extra_compile_args', "-fPIC")
     
    481715        add_to_keywords(kw, 'extra_compile_args', '-g')
    482716        add_to_keywords(kw, 'extra_compile_args', '-ggdb')
    483         kw['cython_gdb'] = True
    484         if get_gcc_version()>=4.8:
     717        if get_gcc_version()>=[4, 8]:
    485718            add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address')
    486719            add_to_keywords(kw, 'extra_link_args', '-fsanitize=address')
     720    if rpath and kw.get("libraries"):
     721        insert_into_keywords(kw, "library_dirs", rpath)
     722        insert_into_keywords(kw, "extra_link_args", "-Wl,-rpath=%s" % rpath)
    487723    #add_to_keywords(kw, 'include_dirs', '.')
    488724    if verbose_ENABLED:
    489         print("pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
     725        print("exec_pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
    490726    return kw
     727pkgconfig = exec_pkgconfig
    491728
    492729
    493730#*******************************************************************************
    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()
     731
     732
     733def get_base_conf_dir(install_dir, stripbuildroot=True):
     734    #in some cases we want to strip the buildroot (to generate paths in the config file)
     735    #but in other cases we want the buildroot path (when writing out the config files)
     736    #and in some cases, we don't have the install_dir specified (called from detect_xorg_setup, and that's fine too)
     737    #this is a bit hackish, but I can't think of a better way of detecting it
     738    #(ie: "$HOME/rpmbuild/BUILDROOT/xpra-0.15.0-0.fc21.x86_64/usr")
     739    dirs = (install_dir or sys.prefix).split(os.path.sep)
     740    if install_dir and stripbuildroot:
     741        pkgdir = os.environ.get("pkgdir")
     742        if "debian" in dirs and "tmp" in dirs:
     743            #ugly fix for stripping the debian tmp dir:
     744            #ie: "???/tmp/???/tags/v0.15.x/src/debian/tmp/" -> ""
     745            while "tmp" in dirs:
     746                dirs = dirs[dirs.index("tmp")+1:]
     747        elif "debian" in dirs:
     748            #same for recent debian versions:
     749            #ie: "xpra-2.0.2/debian/xpra/usr" -> "usr"
     750            i = dirs.index("debian")
     751            if dirs[i+1] == "xpra":
     752                dirs = dirs[i+2:]
     753        elif "BUILDROOT" in dirs:
     754            #strip rpm style build root:
     755            #[$HOME, "rpmbuild", "BUILDROOT", "xpra-$VERSION"] -> []
     756            dirs = dirs[dirs.index("BUILDROOT")+2:]
     757        elif pkgdir and install_dir.startswith(pkgdir):
     758            #arch build dir:
     759            dirs = install_dir.lstrip(pkgdir).split(os.path.sep)
     760        elif "usr" in dirs:
     761            #ie: ["some", "path", "to", "usr"] -> ["usr"]
     762            #assume "/usr" or "/usr/local" is the build root
     763            while "usr" in dirs[1:]:
     764                dirs = dirs[dirs[1:].index("usr")+1:]
     765        elif "image" in dirs:
     766            # Gentoo's "${PORTAGE_TMPDIR}/portage/${CATEGORY}/${PF}/image/_python2.7" -> ""
     767            while "image" in dirs:
     768                dirs = dirs[dirs.index("image")+2:]
     769    #now deal with the fact that "/etc" is used for the "/usr" prefix
     770    #but "/usr/local/etc" is used for the "/usr/local" prefix..
     771    if dirs and dirs[-1]=="usr":
     772        dirs = dirs[:-1]
     773    #is this an absolute path?
     774    if len(dirs)==0 or dirs[0]=="usr" or (install_dir or sys.prefix).startswith(os.path.sep):
     775        #ie: ["/", "usr"] or ["/", "usr", "local"]
     776        dirs.insert(0, os.path.sep)
     777    return dirs
     778
     779def get_conf_dir(install_dir, stripbuildroot=True):
     780    dirs = get_base_conf_dir(install_dir, stripbuildroot)
     781    dirs.append("etc")
     782    dirs.append("xpra")
     783    return os.path.join(*dirs)
     784
     785def detect_xorg_setup(install_dir=None):
     786    from xpra.scripts import config
     787    config.debug = config.warn
     788    conf_dir = get_conf_dir(install_dir)
     789    return config.detect_xvfb_command(conf_dir, None, Xdummy_ENABLED, Xdummy_wrapper_ENABLED)
     790
     791def build_xpra_conf(install_dir):
     792    #generates an actual config file from the template
     793    xvfb_command = detect_xorg_setup(install_dir)
     794    from xpra.platform.features import DEFAULT_ENV
     795    def bstr(b):
     796        if b is None:
     797            return "auto"
     798        return ["no", "yes"][int(b)]
     799    start_env = "\n".join("start-env = %s" % x for x in DEFAULT_ENV)
     800    conf_dir = get_conf_dir(install_dir)
     801    from xpra.platform.features import DEFAULT_SSH_COMMAND, DEFAULT_PULSEAUDIO_COMMAND, DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS
     802    from xpra.platform.paths import get_socket_dirs
     803    from xpra.scripts.config import get_default_key_shortcuts, get_default_systemd_run, DEFAULT_POSTSCRIPT_PRINTER, DEFAULT_PULSEAUDIO
     804    #remove build paths and user specific paths with UID ("/run/user/UID/Xpra"):
     805    socket_dirs = get_socket_dirs()
     806    if WIN32:
     807        bind = "Main"
    533808    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()
     809        if os.getuid()>0:
     810            #remove any paths containing the uid,
     811            #osx uses /var/tmp/$UID-Xpra,
     812            #but this should not be included in the default config for all users!
     813            #(the buildbot's uid!)
     814            socket_dirs = [x for x in socket_dirs if x.find(str(os.getuid()))<0]
     815        bind = "auto"
     816    #FIXME: we should probably get these values from the default config instead
     817    pdf, postscript = "", ""
     818    if POSIX and printing_ENABLED:
     819        try:
     820            if "/usr/sbin" not in sys.path:
     821                sys.path.append("/usr/sbin")
     822            from xpra.platform.pycups_printing import get_printer_definition
     823            print("probing cups printer definitions")
     824            pdf = get_printer_definition("pdf")
     825            postscript = get_printer_definition("postscript") or DEFAULT_POSTSCRIPT_PRINTER
     826            print("pdf=%s, postscript=%s" % (pdf, postscript))
     827        except Exception as e:
     828            print("could not probe for pdf/postscript printers: %s" % e)
     829    def pretty_cmd(cmd):
     830        return " ".join(cmd)
     831    #OSX doesn't have webcam support yet (no opencv builds on 10.5.x)
     832    #Ubuntu 16.10 has opencv builds that conflict with our private ffmpeg
     833    webcam = webcam_ENABLED and not (OSX or getUbuntuVersion()==[16, 10])
     834    #no python-avahi on RH / CentOS, need dbus module on *nix:
     835    mdns = mdns_ENABLED and (OSX or WIN32 or (not is_RH() and dbus_ENABLED))
     836    SUBS = {
     837            'xvfb_command'          : pretty_cmd(xvfb_command),
     838            'ssh_command'           : DEFAULT_SSH_COMMAND,
     839            'key_shortcuts'         : "".join(("key-shortcut = %s\n" % x) for x in get_default_key_shortcuts()),
     840            'remote_logging'        : "both",
     841            'start_env'             : start_env,
     842            'pulseaudio'            : bstr(DEFAULT_PULSEAUDIO),
     843            'pulseaudio_command'    : pretty_cmd(DEFAULT_PULSEAUDIO_COMMAND),
     844            'pulseaudio_configure_commands' : "\n".join(("pulseaudio-configure-commands = %s" % pretty_cmd(x)) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS),
     845            'conf_dir'              : conf_dir,
     846            'bind'                  : bind,
     847            'ssl_cert'              : ssl_cert or "",
     848            'ssl_key'               : ssl_key or "",
     849            'systemd_run'           : get_default_systemd_run(),
     850            'socket_dirs'           : "".join(("socket-dirs = %s\n" % x) for x in socket_dirs),
     851            'log_dir'               : "auto",
     852            'mdns'                  : bstr(mdns),
     853            'notifications'         : bstr(OSX or WIN32 or dbus_ENABLED),
     854            'dbus_proxy'            : bstr(not OSX and not WIN32 and dbus_ENABLED),
     855            'pdf_printer'           : pdf,
     856            'postscript_printer'    : postscript,
     857            'webcam'                : ["no", "auto"][webcam],
     858            'mousewheel'            : "on",
     859            'printing'              : bstr(printing_ENABLED),
     860            'dbus_control'          : bstr(dbus_ENABLED),
     861            'mmap'                  : bstr(True),
     862            }
     863    def convert_templates(subdirs=[]):
     864        dirname = os.path.join(*(["etc", "xpra"] + subdirs))
     865        #get conf dir for install, without stripping the build root
     866        target_dir = os.path.join(get_conf_dir(install_dir, stripbuildroot=False), *subdirs)
     867        print("convert_templates(%s) dirname=%s, target_dir=%s" % (subdirs, dirname, target_dir))
     868        if not os.path.exists(target_dir):
     869            try:
     870                os.makedirs(target_dir)
     871            except Exception as e:
     872                print("cannot create target dir '%s': %s" % (target_dir, e))
     873        for f in sorted(os.listdir(dirname)):
     874            if f.endswith("osx.conf.in") and not OSX:
     875                continue
     876            filename = os.path.join(dirname, f)
     877            if os.path.isdir(filename):
     878                convert_templates(subdirs+[f])
     879                continue
     880            if not f.endswith(".in"):
     881                continue
     882            with open(filename, "r") as f_in:
     883                template  = f_in.read()
     884            target_file = os.path.join(target_dir, f[:-len(".in")])
     885            print("generating %s from %s" % (target_file, f))
     886            with open(target_file, "w") as f_out:
     887                config_data = template % SUBS
     888                f_out.write(config_data)
     889    convert_templates()
    576890
    577891
     
    580894    #clean and sdist don't actually use cython,
    581895    #so skip this (and avoid errors)
    582     def pkgconfig(*pkgs_options, **ekw):
    583         return {}
     896    pkgconfig = no_pkgconfig
    584897    #always include everything in this case:
    585898    add_packages("xpra")
    586899    #ensure we remove the files we generate:
    587900    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",
     901                   "xpra/build_info.py",
     902                   "xpra/monotonic_time.c",
     903                   "xpra/gtk_common/gtk2/gdk_atoms.c",
     904                   "xpra/gtk_common/gtk2/gdk_bindings.c",
     905                   "xpra/gtk_common/gtk3/gdk_atoms.c",
     906                   "xpra/gtk_common/gtk3/gdk_bindings.c",
     907                   "xpra/x11/gtk2/constants.pxi",
     908                   "xpra/x11/gtk2/gdk_bindings.c",
     909                   "xpra/x11/gtk2/gdk_display_source.c",
     910                   "xpra/x11/gtk3/gdk_bindings.c",
     911                   "xpra/x11/gtk3/gdk_display_source.c",
    592912                   "xpra/x11/bindings/constants.pxi",
    593913                   "xpra/x11/bindings/wait_for_x_server.c",
     
    597917                   "xpra/x11/bindings/randr_bindings.c",
    598918                   "xpra/x11/bindings/core_bindings.c",
     919                   "xpra/x11/bindings/posix_display_source.c",
    599920                   "xpra/x11/bindings/ximage.c",
    600                    "xpra/net/rencode/rencode.c",
     921                   "xpra/x11/bindings/xi2_bindings.c",
     922                   "xpra/platform/win32/propsys.cpp",
     923                   "xpra/platform/darwin/gdk_bindings.c",
     924                   "xpra/platform/xposix/sd_listen.c",
     925                   "xpra/platform/xposix/netdev_query.c",
     926                   "xpra/net/bencode/cython_bencode.c",
     927                   "xpra/net/vsock.c",
     928                   "xpra/buffers/membuf.c",
    601929                   "xpra/codecs/vpx/encoder.c",
    602930                   "xpra/codecs/vpx/decoder.c",
    603931                   "xpra/codecs/nvenc/encoder.c",
    604                    "xpra/codecs/nvenc/constants.pxi",
     932                   "xpra/codecs/nvfbc/fbc_capture_linux.cpp",
     933                   "xpra/codecs/nvfbc/fbc_capture_win.cpp",
     934                   "xpra/codecs/cuda_common/ARGB_to_NV12.fatbin",
     935                   "xpra/codecs/cuda_common/ARGB_to_YUV444.fatbin",
     936                   "xpra/codecs/cuda_common/BGRA_to_NV12.fatbin",
     937                   "xpra/codecs/cuda_common/BGRA_to_YUV444.fatbin",
    605938                   "xpra/codecs/enc_x264/encoder.c",
    606939                   "xpra/codecs/enc_x265/encoder.c",
     940                   "xpra/codecs/jpeg/encoder.c",
     941                   "xpra/codecs/jpeg/decoder.c",
     942                   "xpra/codecs/enc_ffmpeg/encoder.c",
     943                   "xpra/codecs/v4l2/constants.pxi",
     944                   "xpra/codecs/v4l2/pusher.c",
     945                   "xpra/codecs/libav_common/av_log.c",
    607946                   "xpra/codecs/webp/encode.c",
    608                    "xpra/codecs/dec_avcodec/decoder.c",
    609                    "xpra/codecs/dec_avcodec/constants.pxi",
     947                   "xpra/codecs/webp/decode.c",
    610948                   "xpra/codecs/dec_avcodec2/decoder.c",
     949                   "xpra/codecs/csc_libyuv/colorspace_converter.cpp",
    611950                   "xpra/codecs/csc_swscale/colorspace_converter.c",
    612                    "xpra/codecs/csc_swscale/constants.pxi",
    613                    "xpra/codecs/csc_cython/colorspace_converter.c",
    614951                   "xpra/codecs/xor/cyxor.c",
    615952                   "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")
     953                   "xpra/codecs/nvapi_version.c",
     954                   "xpra/gtk_common/gdk_atoms.c",
     955                   "xpra/client/gtk3/cairo_workaround.c",
     956                   "xpra/server/cystats.c",
     957                   "xpra/server/window/region.c",
     958                   "xpra/server/window/motion.c",
     959                   "xpra/server/pam.c",
     960                   "etc/xpra/xpra.conf",
     961                   #special case for the generated xpra conf files in build (see #891):
     962                   "build/etc/xpra/xpra.conf"] + glob.glob("build/etc/xpra/conf.d/*.conf")
     963    for x in CLEAN_FILES:
     964        p, ext = os.path.splitext(x)
     965        if ext in (".c", ".cpp", ".pxi"):
     966            #clean the Cython annotated html files:
     967            CLEAN_FILES.append(p+".html")
     968            if WIN32 and ext!=".pxi":
     969                #on win32, the build creates ".pyd" files, clean those too:
     970                CLEAN_FILES.append(p+".pyd")
     971                #when building with python3, we need to clean files named like:
     972                #"xpra/codecs/csc_libyuv/colorspace_converter-cpython-36m.dll"
     973                filename = os.path.join(os.getcwd(), p.replace("/", os.path.sep)+"*.dll")
     974                CLEAN_FILES += glob.glob(filename)
    623975    if 'clean' in sys.argv:
    624976        CLEAN_FILES.append("xpra/build_info.py")
     
    630982            os.unlink(filename)
    631983
    632 from add_build_info import record_build_info, record_src_info, has_src_info
     984from add_build_info import record_build_info, BUILD_INFO_FILE, record_src_info, SRC_INFO_FILE, has_src_info
    633985
    634986if "clean" not in sys.argv:
    635987    # Add build info to build_info.py file:
    636988    record_build_info()
     989    # ensure it is included in the module list if it didn't exist before
     990    add_modules(BUILD_INFO_FILE)
    637991
    638992if "sdist" in sys.argv:
    639993    record_src_info()
    640994
    641 if "install" in sys.argv:
     995if "install" in sys.argv or "build" in sys.argv:
    642996    #if installing from source tree rather than
    643997    #from a source snapshot, we may not have a "src_info" file
     
    645999    if not has_src_info():
    6461000        record_src_info()
     1001        # ensure it is now included in the module list
     1002        add_modules(SRC_INFO_FILE)
    6471003
    6481004
     
    6631019    return m
    6641020
     1021
     1022def install_html5(install_dir="www"):
     1023    from setup_html5 import install_html5 as do_install_html5
     1024    do_install_html5(install_dir, minifier, html5_gzip_ENABLED, html5_brotli_ENABLED, verbose_ENABLED)
     1025
     1026
    6651027#*******************************************************************************
    6661028if 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"]
     1029    MINGW_PREFIX = os.environ.get("MINGW_PREFIX")
     1030    assert MINGW_PREFIX, "you must run this build from a MINGW environment"
    8821031    add_packages("xpra.platform.win32")
    8831032    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"]
     1033
     1034    #this is where the win32 gi installer will put things:
     1035    gnome_include_path = os.environ.get("MINGW_PREFIX")
     1036
     1037    #only add the cx_freeze specific options
     1038    #if we aren't just building the Cython bits with "build_ext":
     1039    if "build_ext" not in sys.argv:
     1040        #with cx_freeze, we don't use py_modules
     1041        del setup_options["py_modules"]
     1042        import cx_Freeze                            #@UnresolvedImport
     1043        from cx_Freeze import setup, Executable     #@UnresolvedImport @Reimport
     1044        CX5 = cx_Freeze.version>="5"
     1045        if CX5 and not hasattr(sys, "base_prefix"):
     1046            #workaround for broken sqlite hook with python 2.7, see:
     1047            #https://github.com/anthony-tuininga/cx_Freeze/pull/272
     1048            sys.base_prefix = sys.prefix
     1049
     1050        #cx_freeze doesn't use "data_files"...
     1051        del setup_options["data_files"]
     1052        #it wants source files first, then where they are placed...
     1053        #one item at a time (no lists)
     1054        #all in its own structure called "include_files" instead of "data_files"...
     1055        def add_data_files(target_dir, files):
     1056            if verbose_ENABLED:
     1057                print("add_data_files(%s, %s)" % (target_dir, files))
     1058            assert type(target_dir)==str
     1059            assert type(files) in (list, tuple)
     1060            for f in files:
     1061                target_file = os.path.join(target_dir, os.path.basename(f))
     1062                data_files.append((f, target_file))
     1063
     1064        #pass a potentially nested dictionary representing the tree
     1065        #of files and directories we do want to include
     1066        #relative to gnome_include_path
     1067        def add_dir(base, defs):
     1068            if verbose_ENABLED:
     1069                print("add_dir(%s, %s)" % (base, defs))
     1070            if type(defs) in (list, tuple):
     1071                for sub in defs:
     1072                    if type(sub)==dict:
     1073                        add_dir(base, sub)
     1074                    else:
     1075                        assert type(sub)==str
     1076                        filename = os.path.join(gnome_include_path, base, sub)
     1077                        if os.path.exists(filename):
     1078                            add_data_files(base, [filename])
     1079                        else:
     1080                            print("Warning: missing '%s'" % filename)
     1081            else:
     1082                assert type(defs)==dict
     1083                for d, sub in defs.items():
     1084                    assert type(sub) in (dict, list, tuple)
     1085                    #recurse down:
     1086                    add_dir(os.path.join(base, d), sub)
     1087
     1088        #convenience method for adding GI libs and "typelib" and "gir":
     1089        def add_gi(*libs):
     1090            if verbose_ENABLED:
     1091                print("add_gi(%s)" % str(libs))
     1092            add_dir('lib',      {"girepository-1.0":    ["%s.typelib" % x for x in libs]})
     1093            add_dir('share',    {"gir-1.0" :            ["%s.gir" % x for x in libs]})
     1094
     1095        def add_DLLs(*dll_names):
     1096            try:
     1097                do_add_DLLs(*dll_names)
     1098            except Exception as e:
     1099                print("Error: failed to add DLLs: %s" % (dll_names, ))
     1100                print(" %s" % e)
     1101                sys.exit(1)
     1102
     1103        def do_add_DLLs(*dll_names):
     1104            dll_names = list(dll_names)
     1105            dll_files = []
     1106            import re
     1107            version_re = re.compile("\-[0-9\.\-]+$")
     1108            dirs = os.environ.get("PATH").split(os.path.pathsep)
     1109            if os.path.exists(gnome_include_path):
     1110                dirs.insert(0, gnome_include_path)
     1111            if verbose_ENABLED:
     1112                print("add_DLLs: looking for %s in %s" % (dll_names, dirs))
     1113            for d in dirs:
     1114                if not os.path.exists(d):
     1115                    continue
     1116                for x in os.listdir(d):
     1117                    dll_path = os.path.join(d, x)
     1118                    x = x.lower()
     1119                    if os.path.isdir(dll_path) or not x.startswith("lib") or not x.endswith(".dll"):
     1120                        continue
     1121                    nameversion = x[3:-4]                       #strip "lib" and ".dll": "libatk-1.0-0.dll" -> "atk-1.0-0"
     1122                    if verbose_ENABLED:
     1123                        print("checking %s: %s" % (x, nameversion))
     1124                    m = version_re.search(nameversion)          #look for version part of filename
     1125                    if m:
     1126                        dll_version = m.group(0)                #found it, ie: "-1.0-0"
     1127                        dll_name = nameversion[:-len(dll_version)]  #ie: "atk"
     1128                        dll_version = dll_version.lstrip("-")   #ie: "1.0-0"
     1129                    else:
     1130                        dll_version = ""                        #no version
     1131                        dll_name = nameversion                  #ie: "libzzz.dll" -> "zzz"
     1132                    if dll_name in dll_names:
     1133                        #this DLL is on our list
     1134                        print("%s %s %s" % (dll_name.ljust(22), dll_version.ljust(10), x))
     1135                        dll_files.append(dll_path)
     1136                        dll_names.remove(dll_name)
     1137            if len(dll_names)>0:
     1138                print("some DLLs could not be found:")
     1139                for x in dll_names:
     1140                    print(" - lib%s*.dll" % x)
     1141            add_data_files("", dll_files)
     1142
     1143        #list of DLLs we want to include, without the "lib" prefix, or the version and extension
     1144        #(ie: "libatk-1.0-0.dll" -> "atk")
     1145        if sound_ENABLED or gtk3_ENABLED:
     1146            add_DLLs('gio', 'girepository', 'glib',
     1147                     'gnutls', 'gobject', 'gthread',
     1148                     'orc', 'stdc++',
     1149                     'winpthread',
     1150                     )
     1151        if gtk3_ENABLED:
     1152            add_DLLs('atk',
     1153                     'dbus', 'dbus-glib',
     1154                     'gdk', 'gdk_pixbuf', 'gtk',
     1155                     'cairo-gobject', 'pango', 'pangocairo', 'pangoft2', 'pangowin32',
     1156                     'harfbuzz', 'harfbuzz-gobject',
     1157                     'jasper', 'epoxy',
     1158                     'intl',
     1159                     'p11-kit',
     1160                     'jpeg', 'png16', 'rsvg', 'webp', 'tiff')
     1161            #these are missing in newer aio installers (sigh):
     1162            do_add_DLLs('javascriptcoregtk')
     1163            if opengl_ENABLED:
     1164                do_add_DLLs('gdkglext', 'gtkglext')
     1165
     1166        if gtk3_ENABLED:
     1167            add_dir('etc', ["fonts", "gtk-3.0", "pango", "pkcs11"])     #add "dbus-1"?
     1168            add_dir('lib', ["gdk-pixbuf-2.0", "gtk-3.0",
     1169                            "libvisual-0.4", "p11-kit", "pkcs11"])
     1170            add_dir('share', ["fontconfig", "fonts", "glib-2.0",        #add "dbus-1"?
     1171                              "p11-kit", "xml",
     1172                              {"icons"  : ["hicolor"]},
     1173                              {"locale" : ["en"]},
     1174                              {"themes" : ["Default"]}
     1175                             ])
     1176        if gtk3_ENABLED or sound_ENABLED:
     1177            add_dir('lib', ["gio"])
     1178            packages.append("gi")
     1179            add_gi("Gio-2.0", "GIRepository-2.0", "Glib-2.0", "GModule-2.0",
     1180                   "GObject-2.0")
     1181        if gtk3_ENABLED:
     1182            add_gi("Atk-1.0",
     1183                   "Notify-0.7",
     1184                   "fontconfig-2.0", "freetype2-2.0",
     1185                   "GDesktopEnums-3.0", "Soup-2.4",
     1186                   "GdkPixbuf-2.0", "Gdk-3.0", "Gtk-3.0",
     1187                   "HarfBuzz-0.0",
     1188                   "Libproxy-1.0", "libxml2-2.0",
     1189                   "cairo-1.0", "Pango-1.0", "PangoCairo-1.0", "PangoFT2-1.0",
     1190                   "Rsvg-2.0",
     1191                   "win32-1.0")
     1192            if opengl_ENABLED:
     1193                add_gi("GdkGLExt-3.0", "GtkGLExt-3.0", "GL-1.0")
     1194            add_DLLs('visual', 'curl', 'soup', 'openjpeg')
     1195        if server_ENABLED and not PYTHON3:
     1196            add_DLLs('sqlite3')
     1197
     1198        if gtk2_ENABLED:
     1199            add_dir('lib',      {
     1200                "gdk-pixbuf-2.0":    {
     1201                    "2.10.0"    :   {
     1202                        "loaders"   :
     1203                            ["libpixbufloader-%s.dll" % x for x in ("ico", "jpeg", "svg", "bmp", "png",)]
     1204                        },
     1205                    },
     1206                })
     1207
     1208        if sound_ENABLED:
     1209            add_dir("share", ["gst-plugins-bad", "gst-plugins-base", "gstreamer-1.0"])
     1210            add_gi("Gst-1.0", "GstAllocators-1.0", "GstAudio-1.0", "GstBase-1.0",
     1211                   "GstTag-1.0")
     1212            add_DLLs('gstreamer', 'orc-test')
     1213            for p in ("app", "audio", "base", "codecparsers", "fft", "net", "video",
     1214                      "pbutils", "riff", "sdp", "rtp", "rtsp", "tag", "uridownloader",
     1215                      #I think 'coreelements' needs those (otherwise we would exclude them):
     1216                      "basecamerabinsrc", "mpegts", "photography",
     1217                      ):
     1218                add_DLLs('gst%s' % p)
     1219            #DLLs needed by the plugins:
     1220            add_DLLs("faac", "faad", "flac", "mad", "mpg123")
     1221            #add the gstreamer plugins we need:
     1222            GST_PLUGINS = ("app",
     1223                           "cutter",
     1224                           #muxers:
     1225                           "gdp", "matroska", "ogg", "isomp4",
     1226                           "audioparsers", "audiorate", "audioconvert", "audioresample", "audiotestsrc",
     1227                           "coreelements", "directsoundsink", "directsoundsrc", "wasapi",
     1228                           #codecs:
     1229                           "opus", "opusparse", "flac", "lame", "mad", "mpg123", "speex", "faac", "faad",
     1230                           "volume", "vorbis", "wavenc", "wavpack", "wavparse",
     1231                           "autodetect",
     1232                           #untested: a52dec, voaacenc
     1233                           )
     1234            add_dir(os.path.join("lib", "gstreamer-1.0"), [("libgst%s.dll" % x) for x in GST_PLUGINS])
     1235            #END OF SOUND
     1236
     1237        if server_ENABLED:
     1238            #used by proxy server:
     1239            external_includes += ["multiprocessing", "setproctitle"]
     1240
     1241        external_includes += ["encodings"]
     1242        if client_ENABLED:
     1243            #for parsing "open-command":
     1244            external_includes += ["shlex"]
     1245            #for version check:
     1246            external_includes += [
     1247                                  "ftplib", "fileinput",
     1248                                  ]
     1249            if PYTHON3:
     1250                external_includes += ["urllib", "http.cookiejar", "http.client"]
     1251            else:
     1252                external_includes += ["urllib2", "cookielib", "httplib"]
     1253
     1254        if PYTHON3:
     1255            #hopefully, cx_Freeze will fix this horror:
     1256            #(we shouldn't have to deal with DLL dependencies)
     1257            import site
     1258            lib_python = os.path.dirname(site.getsitepackages()[0])
     1259            lib_dynload_dir = os.path.join(lib_python, "lib-dynload")
     1260            add_data_files('', glob.glob("%s/zlib*dll" % lib_dynload_dir))
     1261            for x in ("io", "codecs", "abc", "_weakrefset", "encodings"):
     1262                add_data_files("", glob.glob("%s/%s*" % (lib_python, x)))
     1263        #ensure that cx_freeze won't automatically grab other versions that may lay on our path:
     1264        os.environ["PATH"] = gnome_include_path+";"+os.environ.get("PATH", "")
     1265        bin_excludes = ["MSVCR90.DLL", "MFC100U.DLL"]
     1266        cx_freeze_options = {
     1267                            "includes"          : external_includes,
     1268                            "packages"          : packages,
     1269                            "include_files"     : data_files,
     1270                            "excludes"          : excludes,
     1271                            "include_msvcr"     : True,
     1272                            "bin_excludes"      : bin_excludes,
     1273                            }
     1274        if not CX5:
     1275            cx_freeze_options.update({
     1276                            "compressed"        : True,
     1277                            "create_shared_zip" : zip_ENABLED,
     1278                            })
     1279        else:
     1280            #cx_Freeze v5 workarounds:
     1281            if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
     1282                add_packages("numpy.core._methods", "numpy.lib.format")
     1283
     1284        setup_options["options"] = {"build_exe" : cx_freeze_options}
     1285        executables = []
     1286        setup_options["executables"] = executables
     1287
     1288        def add_exe(script, icon, base_name, base="Console"):
     1289            kwargs = {}
     1290            if not CX5:
     1291                kwargs = {
     1292                    "compress"              : True,
     1293                    "copyDependentFiles"    : True,
     1294                    "appendScriptToExe"     : False,
     1295                    "appendScriptToLibrary" : True,
     1296                    }
     1297            executables.append(Executable(
     1298                        script                  = script,
     1299                        initScript              = None,
     1300                        #targetDir               = "dist",
     1301                        icon                    = "win32/%s" % icon,
     1302                        targetName              = "%s.exe" % base_name,
     1303                        base                    = base,
     1304                        **kwargs))
     1305
     1306        def add_console_exe(script, icon, base_name):
     1307            add_exe(script, icon, base_name)
     1308        def add_gui_exe(script, icon, base_name):
     1309            add_exe(script, icon, base_name, base="Win32GUI")
     1310        def add_service_exe(script, icon, base_name):
     1311            add_exe(script, icon, base_name, base="Win32Service")
     1312
     1313        #UI applications (detached from shell: no text output if ran from cmd.exe)
     1314        if (client_ENABLED or server_ENABLED) and (gtk2_ENABLED or gtk3_ENABLED):
     1315            add_gui_exe("scripts/xpra",                         "xpra_txt.ico",     "Xpra")
     1316            add_gui_exe("scripts/xpra_launcher",                "xpra.ico",         "Xpra-Launcher")
     1317            add_gui_exe("xpra/gtk_common/gtk_view_keyboard.py", "keyboard.ico",     "GTK_Keyboard_Test")
     1318            add_gui_exe("xpra/scripts/bug_report.py",           "bugs.ico",         "Bug_Report")
     1319            add_gui_exe("xpra/platform/win32/gdi_screen_capture.py", "screenshot.ico", "Screenshot")
     1320        if server_ENABLED:
     1321            add_gui_exe("scripts/auth_dialog",                  "authentication.ico", "Auth_Dialog")
     1322        if gtk2_ENABLED:
     1323            #these need porting..
     1324            add_gui_exe("xpra/gtk_common/gtk_view_clipboard.py","clipboard.ico",    "GTK_Clipboard_Test")
     1325        if mdns_ENABLED and (gtk2_ENABLED or gtk3_ENABLED):
     1326            add_gui_exe("xpra/client/gtk_base/mdns_gui.py",     "mdns.ico",         "Xpra_Browser")
     1327        #Console: provide an Xpra_cmd.exe we can run from the cmd.exe shell
     1328        add_console_exe("scripts/xpra",                     "xpra_txt.ico",     "Xpra_cmd")
     1329        add_console_exe("xpra/scripts/version.py",          "information.ico",  "Version_info")
     1330        add_console_exe("xpra/net/net_util.py",             "network.ico",      "Network_info")
     1331        if gtk2_ENABLED or gtk3_ENABLED:
     1332            add_console_exe("xpra/scripts/gtk_info.py",         "gtk.ico",          "GTK_info")
     1333            add_console_exe("xpra/gtk_common/keymap.py",        "keymap.ico",       "Keymap_info")
     1334            add_console_exe("xpra/platform/keyboard.py",        "keymap.ico",       "Keyboard_info")
     1335            add_gui_exe("xpra/client/gtk_base/example/tray.py", "xpra.ico",         "SystemTray_Test")
     1336            add_gui_exe("xpra/client/gtk_base/u2f_tool.py",     "authentication.ico", "U2F_Tool")
     1337        if client_ENABLED or server_ENABLED:
     1338            add_console_exe("win32/python_execfile.py",         "python.ico",       "Python_execfile")
     1339            add_console_exe("xpra/scripts/config.py",           "gears.ico",        "Config_info")
     1340        if server_ENABLED:
     1341            add_console_exe("xpra/server/auth/sqlite_auth.py",  "sqlite.ico",        "SQLite_auth_tool")
     1342            add_console_exe("xpra/server/auth/win32_auth.py",   "authentication.ico", "System-Auth-Test")
     1343            add_console_exe("xpra/server/auth/ldap_auth.py",    "authentication.ico", "LDAP-Auth-Test")
     1344            add_console_exe("xpra/server/auth/ldap3_auth.py",   "authentication.ico", "LDAP3-Auth-Test")
     1345            add_console_exe("win32/service/proxy.py",           "xpra_txt.ico",      "Xpra-Proxy")
     1346            add_console_exe("xpra/platform/win32/lsa_logon_lib.py", "xpra_txt.ico",     "System-Logon-Test")
     1347        if client_ENABLED:
     1348            add_console_exe("xpra/codecs/loader.py",            "encoding.ico",     "Encoding_info")
     1349            add_console_exe("xpra/platform/paths.py",           "directory.ico",    "Path_info")
     1350            add_console_exe("xpra/platform/features.py",        "features.ico",     "Feature_info")
     1351        if client_ENABLED:
     1352            add_console_exe("xpra/platform/gui.py",             "browse.ico",       "NativeGUI_info")
     1353            add_console_exe("xpra/platform/win32/gui.py",       "loop.ico",         "Events_Test")
     1354        if sound_ENABLED:
     1355            add_console_exe("xpra/sound/gstreamer_util.py",     "gstreamer.ico",    "GStreamer_info")
     1356            add_console_exe("scripts/xpra",                     "speaker.ico",      "Xpra_Audio")
     1357            add_console_exe("xpra/platform/win32/directsound.py", "speaker.ico",      "Audio_Devices")
     1358            #add_console_exe("xpra/sound/src.py",                "microphone.ico",   "Sound_Record")
     1359            #add_console_exe("xpra/sound/sink.py",               "speaker.ico",      "Sound_Play")
     1360        if opengl_ENABLED:
     1361            if PYTHON3:
     1362                add_console_exe("xpra/client/gl/gl_check.py",   "opengl.ico",       "OpenGL_check")
     1363            else:
     1364                add_console_exe("xpra/client/gl/gtk_base/gtkgl_check.py", "opengl.ico", "OpenGL_check")
     1365        if webcam_ENABLED:
     1366            add_console_exe("xpra/platform/webcam.py",          "webcam.ico",    "Webcam_info")
     1367            add_console_exe("xpra/scripts/show_webcam.py",          "webcam.ico",    "Webcam_Test")
     1368        if printing_ENABLED:
     1369            add_console_exe("xpra/platform/printing.py",        "printer.ico",     "Print")
     1370            add_console_exe("xpra/platform/win32/pdfium.py",    "printer.ico",     "PDFIUM_Print")
     1371            add_DLLs("pdfium")  #libpdfium.dll
     1372        if nvenc_ENABLED:
     1373            add_console_exe("xpra/codecs/nv_util.py",                   "nvidia.ico",   "NVidia_info")
     1374        if nvfbc_ENABLED:
     1375            add_console_exe("xpra/codecs/nvfbc/capture.py",             "nvidia.ico",   "NvFBC_capture")
     1376        if nvfbc_ENABLED or nvenc_ENABLED:
     1377            add_console_exe("xpra/codecs/cuda_common/cuda_context.py",  "cuda.ico",     "CUDA_info")
     1378
     1379        if example_ENABLED:
     1380            add_gui_exe("xpra/client/gtk_base/example/colors.py",               "encoding.ico",     "Colors")
     1381            add_gui_exe("xpra/client/gtk_base/example/colors_gradient.py",      "encoding.ico",     "Colors-Gradient")
     1382            if not PYTHON3:
     1383                add_gui_exe("xpra/client/gtk_base/example/gl_colors_gradient.py",   "encoding.ico",     "OpenGL-Colors-Gradient")
     1384            add_gui_exe("xpra/client/gtk_base/example/colors_plain.py",         "encoding.ico",     "Colors-Plain")
     1385            add_gui_exe("xpra/client/gtk_base/example/bell.py",                 "bell.ico",         "Bell")
     1386            add_gui_exe("xpra/client/gtk_base/example/transparent_colors.py",   "transparent.ico",  "Transparent-Colors")
     1387            add_gui_exe("xpra/client/gtk_base/example/transparent_window.py",   "transparent.ico",  "Transparent-Window")
     1388            add_gui_exe("xpra/client/gtk_base/example/fontrendering.py",        "font.ico",         "Font-Rendering")
     1389
     1390        #FIXME: how do we figure out what target directory to use?
     1391        print("calling build_xpra_conf in-place")
     1392        #building etc files in-place:
     1393        build_xpra_conf(".")
     1394        add_data_files('etc/xpra', glob.glob("etc/xpra/*conf"))
     1395        add_data_files('etc/xpra', glob.glob("etc/xpra/nvenc*.keys"))
     1396        add_data_files('etc/xpra', glob.glob("etc/xpra/nvfbc*.keys"))
     1397        add_data_files('etc/xpra/conf.d', glob.glob("etc/xpra/conf.d/*conf"))
     1398        #build minified html5 client in temporary build dir:
     1399        if "clean" not in sys.argv and html5_ENABLED:
     1400            install_html5(os.path.join(install, "www"), )
     1401            for k,v in glob_recurse("build/www").items():
     1402                if (k!=""):
     1403                    k = os.sep+k
     1404                add_data_files('www'+k, v)
     1405
     1406    if client_ENABLED or server_ENABLED:
     1407        add_data_files('',      ['COPYING', 'README', 'win32/website.url'])
     1408        add_data_files('icons', glob.glob('win32\\*.ico') + glob.glob('icons\\*.*'))
     1409
     1410    if webcam_ENABLED:
     1411        add_data_files('',      ['win32\\DirectShow.tlb'])
     1412
    9071413    remove_packages(*external_excludes)
     1414    external_includes.append("pyu2f")
     1415    external_includes.append("mmap")
     1416    external_includes.append("comtypes")    #used by webcam and netdev_query
     1417    remove_packages("comtypes.gen")         #this is generated at runtime
     1418                                            #but we still have to remove the empty directory by hand
     1419                                            #afterwards because cx_freeze does weird things (..)
    9081420    remove_packages(#not used on win32:
    909                     "mmap",
    9101421                    #we handle GL separately below:
    9111422                    "OpenGL", "OpenGL_accelerate",
     
    9131424                    "ctypes.macholib")
    9141425
    915     if not cyxor_ENABLED or opengl_ENABLED:
     1426    if webcam_ENABLED:
     1427        external_includes.append("cv2")
     1428    else:
     1429        remove_packages("cv2")
     1430
     1431    if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
    9161432        #we need numpy for opengl or as a fallback for the Cython xor module
    917         py2exe_includes.append("numpy")
     1433        external_includes.append("numpy")
    9181434    else:
    919         remove_packages("numpy",
    920                         "unittest", "difflib",  #avoid numpy warning (not an error)
     1435        remove_packages("unittest", "difflib",  #avoid numpy warning (not an error)
    9211436                        "pydoc")
    9221437
    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:
     1438    #make sure we don't include the gstreamer 0.10 "pygst" bindings:
     1439    remove_packages("pygst", "gst", "gst.extend")
     1440
     1441    #add subset of PyOpenGL modules (only when installing):
     1442    if opengl_ENABLED and ("install_exe" in sys.argv or "install" in sys.argv):
    9291443        #for this hack to work, you must add "." to the sys.path
    9301444        #so python can load OpenGL from the install directory
    9311445        #(further complicated by the fact that "." is the "frozen" path...)
     1446        #but we re-add those two directories to the library.zip as part of the build script
    9321447        import OpenGL, OpenGL_accelerate        #@UnresolvedImport
    933         import shutil
    934         print("*** copy PyOpenGL modules ***")
     1448        print("*** copying PyOpenGL modules to %s ***" % install)
    9351449        for module_name, module in {"OpenGL" : OpenGL, "OpenGL_accelerate" : OpenGL_accelerate}.items():
    9361450            module_dir = os.path.dirname(module.__file__ )
    9371451            try:
    9381452                shutil.copytree(
    939                     module_dir, os.path.join("dist", module_name),
    940                     ignore = shutil.ignore_patterns("Tk")
     1453                    module_dir, os.path.join(install, module_name),
     1454                    ignore = shutil.ignore_patterns("Tk", "AGL", "EGL", "GLX", "GLX.*", "_GLX.*", "GLE", "GLES1", "GLES2", "GLES3")
    9411455                )
    942             except WindowsError, error:     #@UndefinedVariable
    943                 if not "already exists" in str( error ):
     1456            except Exception as e:
     1457                if not isinstance(e, WindowsError) or (not "already exists" in str(e)): #@UndefinedVariable
    9441458                    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 
     1459
     1460    add_data_files('', glob.glob("win32\\bundle-extra\\*"))
     1461    add_data_files('', ["bell.wav"])
     1462    add_data_files('http-headers', glob.glob("http-headers\\*"))
     1463
     1464    #END OF win32
    9831465#*******************************************************************************
    9841466else:
    9851467    #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"]))
     1468    scripts += ["scripts/xpra", "scripts/xpra_launcher", "scripts/xpra_browser", "scripts/xpra_udev_product_version", "scripts/xpra_signal_listener"]
     1469    if POSIX and not OSX:
     1470        libexec_scripts = []
     1471        from xpra.os_util import is_Fedora, is_CentOS
     1472        if is_Fedora() or is_CentOS():
     1473            libexec = "libexec"
     1474        else:
     1475            libexec = "lib"
     1476        if xdg_open_ENABLED:
     1477            libexec_scripts += ["scripts/xdg-open", "scripts/gnome-open", "scripts/gvfs-open"]
     1478        if server_ENABLED:
     1479            libexec_scripts.append("scripts/auth_dialog")
     1480        if libexec_scripts:
     1481            add_data_files("%s/xpra/" % libexec, libexec_scripts)
     1482    man_path = "share/man"
     1483    if OPENBSD:
     1484        man_path = "man"
     1485    add_data_files("%s/man1" % man_path,  ["man/xpra.1", "man/xpra_launcher.1", "man/xpra_browser.1"])
     1486    add_data_files("share/xpra",          ["README", "COPYING"])
     1487    add_data_files("share/xpra/icons",    glob.glob("icons/*"))
     1488    add_data_files("share/applications",  ["xdg/xpra-launcher.desktop", "xdg/xpra-browser.desktop", "xdg/xpra.desktop"])
     1489    add_data_files("share/mime/packages", ["xdg/application-x-xpraconfig.xml"])
     1490    add_data_files("share/icons",         ["xdg/xpra.png", "xdg/xpra-mdns.png"])
     1491    add_data_files("share/appdata",       ["xdg/xpra.appdata.xml"])
     1492    add_data_files('share/xpra/',         ["bell.wav"])
     1493    add_data_files('share/xpra/http-headers', glob.glob("http-headers/*"))
     1494
     1495    #here, we override build and install so we can
     1496    #generate our /etc/xpra/xpra.conf
     1497    class build_override(build):
     1498        def run(self):
     1499            build.run(self)
     1500            self.run_command("build_conf")
     1501
     1502    class build_conf(build):
     1503        def run(self):
     1504            try:
     1505                build_base = self.distribution.command_obj['build'].build_base
     1506            except:
     1507                build_base = self.build_base
     1508            build_xpra_conf(build_base)
     1509
     1510    class install_data_override(install_data):
     1511        def run(self):
     1512            print("install_data_override: install_dir=%s" % self.install_dir)
     1513            if html5_ENABLED:
     1514                install_html5(os.path.join(self.install_dir, "share/xpra/www"))
     1515            install_data.run(self)
     1516
     1517            root_prefix = self.install_dir.rstrip("/")
     1518            if root_prefix.endswith("/usr"):
     1519                root_prefix = root_prefix[:-4]    #ie: "/" or "/usr/src/rpmbuild/BUILDROOT/xpra-0.18.0-0.20160513r12573.fc23.x86_64/"
     1520            build_xpra_conf(root_prefix)
     1521
     1522            def copytodir(src, dst_dir, dst_name=None, chmod=0o644):
     1523                #convert absolute paths:
     1524                if dst_dir.startswith("/"):
     1525                    dst_dir = root_prefix+dst_dir
     1526                else:
     1527                    dst_dir = self.install_dir.rstrip("/")+"/"+dst_dir
     1528                #make sure the target directory exists:
     1529                self.mkpath(dst_dir)
     1530                #generate the target filename:
     1531                filename = os.path.basename(src)
     1532                dst_file = os.path.join(dst_dir, dst_name or filename)
     1533                #copy it
     1534                print("copying %s -> %s (%s)" % (src, dst_dir, oct(chmod)))
     1535                shutil.copyfile(src, dst_file)
     1536                if chmod:
     1537                    os.chmod(dst_file, chmod)
     1538
     1539            if printing_ENABLED and POSIX:
     1540                #install "/usr/lib/cups/backend" with 0700 permissions:
     1541                copytodir("cups/xpraforwarder", "lib/cups/backend", chmod=0o700)
     1542
     1543            if x11_ENABLED:
     1544                #install xpra_Xdummy if we need it:
     1545                xvfb_command = detect_xorg_setup()
     1546                if any(x.find("xpra_Xdummy")>=0 for x in (xvfb_command or [])) or Xdummy_wrapper_ENABLED is True:
     1547                    copytodir("scripts/xpra_Xdummy", "bin", chmod=0o755)
     1548                #install xorg*.conf, cuda.conf and nvenc.keys:
     1549                etc_xpra_files = ["xorg.conf"]
     1550                if uinput_ENABLED:
     1551                    etc_xpra_files.append("xorg-uinput.conf")
     1552                if nvenc_ENABLED or nvfbc_ENABLED:
     1553                    etc_xpra_files.append("cuda.conf")
     1554                if nvenc_ENABLED:
     1555                    etc_xpra_files.append("nvenc.keys")
     1556                if nvfbc_ENABLED:
     1557                    etc_xpra_files.append("nvfbc.keys")
     1558                for x in etc_xpra_files:
     1559                    copytodir("etc/xpra/%s" % x, "/etc/xpra")
     1560                copytodir("etc/X11/xorg.conf.d/90-xpra-virtual.conf", "/etc/X11/xorg.conf.d/")
     1561
     1562            if pam_ENABLED:
     1563                copytodir("etc/pam.d/xpra", "/etc/pam.d")
     1564
     1565            systemd_dir = "/lib/systemd/system"
     1566            if service_ENABLED:
     1567                #Linux init service:
     1568                if os.path.exists("/bin/systemctl"):
     1569                    if sd_listen_ENABLED:
     1570                        copytodir("service/xpra.service", systemd_dir)
     1571                    else:
     1572                        copytodir("service/xpra-nosocketactivation.service", systemd_dir, dst_name="xpra.service")
     1573                else:
     1574                    copytodir("service/xpra", "/etc/init.d")
     1575                if os.path.exists("/etc/sysconfig"):
     1576                    copytodir("etc/sysconfig/xpra", "/etc/sysconfig")
     1577                elif os.path.exists("/etc/default"):
     1578                    copytodir("etc/sysconfig/xpra", "/etc/default")
     1579            if sd_listen_ENABLED:
     1580                copytodir("service/xpra.socket", systemd_dir)
     1581            if dbus_ENABLED and proxy_ENABLED:
     1582                copytodir("dbus/xpra.conf", "/etc/dbus-1/system.d")
     1583
     1584
     1585    # add build_conf to build step
     1586    cmdclass.update({
     1587             'build'        : build_override,
     1588             'build_conf'   : build_conf,
     1589             'install_data' : install_data_override,
     1590             })
    9971591
    9981592    if OSX:
     1593        #pyobjc needs email.parser
     1594        external_includes += ["email", "uu", "urllib", "objc", "cups", "six"]
     1595        external_includes += ["kerberos", "future", "pyu2f"]
     1596        if not PYTHON3:
     1597            external_includes += ["urllib2"]
    9991598        #OSX package names (ie: gdk-x11-2.0 -> gdk-2.0, etc)
    10001599        PYGTK_PACKAGES += ["gdk-2.0", "gtk+-2.0"]
    10011600        add_packages("xpra.platform.darwin")
     1601        remove_packages("xpra.platform.win32", "xpra.platform.xposix")
     1602        #for u2f on python2:
     1603        if not PYTHON3:
     1604            modules.append("UserList")
     1605            modules.append("UserString")
     1606        #to support GStreamer 1.x we need this:
     1607        modules.append("importlib")
    10021608    else:
    10031609        PYGTK_PACKAGES += ["gdk-x11-2.0", "gtk+-x11-2.0"]
    10041610        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")
     1611        remove_packages("xpra.platform.win32", "xpra.platform.darwin")
     1612        #not supported by all distros, but doesn't hurt to install them anyway:
     1613        for x in ("tmpfiles.d", "sysusers.d"):
     1614            add_data_files("lib/%s" % x, ["%s/xpra.conf" % x])
     1615        if uinput_ENABLED:
     1616            add_data_files("lib/udev/rules.d/", ["udev/rules.d/71-xpra-virtual-pointer.rules"])
    10081617
    10091618    #gentoo does weird things, calls --no-compile with build *and* install
     
    10121621    #otherwise we use the flags to skip pkgconfig
    10131622    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))
     1623        pkgconfig = no_pkgconfig
    10331624
    10341625    if OSX and "py2app" in sys.argv:
     
    10451636        remove_packages(*external_excludes)
    10461637
    1047         Plist = {"CFBundleDocumentTypes" : {
    1048                         "CFBundleTypeExtensions"    : ["Xpra"],
    1049                         "CFBundleTypeName"          : "Xpra Session Config File",
    1050                         "CFBundleName"              : "Xpra",
    1051                         "CFBundleTypeRole"          : "Viewer",
    1052                         }}
     1638        try:
     1639            from xpra.src_info import REVISION
     1640        except:
     1641            REVISION = "unknown"
     1642        Plist = {
     1643            "CFBundleDocumentTypes" : {
     1644                "CFBundleTypeExtensions"    : ["Xpra"],
     1645                "CFBundleTypeName"          : "Xpra Session Config File",
     1646                "CFBundleName"              : "Xpra",
     1647                "CFBundleTypeRole"          : "Viewer",
     1648                },
     1649            "CFBundleGetInfoString" : "%s-r%s (c) 2012-2018 http://xpra.org/" % (XPRA_VERSION, REVISION),
     1650            "CFBundleIdentifier"            : "org.xpra.xpra",
     1651            }
    10531652        #Note: despite our best efforts, py2app will not copy all the modules we need
    10541653        #so the make-app.sh script still has to hack around this problem.
    10551654        add_modules(*external_includes)
     1655        #needed by python-lz4:
     1656        add_modules("distutils")
    10561657        py2app_options = {
    10571658            'iconfile'          : '../osx/xpra.icns',
     
    10651666            }
    10661667        setup_options["options"] = {"py2app": py2app_options}
    1067         setup_options["app"]     = ["xpra/client/gtk2/client_launcher.py"]
     1668        setup_options["app"]     = ["xpra/client/gtk_base/client_launcher.py"]
     1669
     1670    if OSX:
     1671        #simply adding the X11 path to PKG_CONFIG_PATH breaks things in mysterious ways,
     1672        #so instead we have to query each package seperately and merge the results:
     1673        def osx_pkgconfig(*pkgs_options, **ekw):
     1674            kw = dict(ekw)
     1675            for pkg in pkgs_options:
     1676                saved_pcp = os.environ.get("PKG_CONFIG_PATH")
     1677                if pkg.lower().startswith("x"):
     1678                    os.environ["PKG_CONFIG_PATH"] = "/usr/X11/lib/pkgconfig"
     1679                #print("exec_pkgconfig(%s, %s)", pkg, kw)
     1680                kw = exec_pkgconfig(pkg, **kw)
     1681                os.environ["PKG_CONFIG_PATH"] = saved_pcp
     1682            return kw
     1683
     1684        pkgconfig = osx_pkgconfig
    10681685
    10691686
    10701687if 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 
     1688    if WIN32 or OSX:
     1689        external_includes.append("websockify")
     1690        external_includes.append("numpy")
     1691        external_includes.append("ssl")
     1692        external_includes.append("_ssl")
     1693        if not PYTHON3:
     1694            external_includes.append("mimetypes")
     1695            external_includes.append("mimetools")
     1696            external_includes.append("BaseHTTPServer")
     1697
     1698
     1699if annotate_ENABLED:
     1700    from Cython.Compiler import Options
     1701    Options.annotate = True
    10761702
    10771703
    10781704#*******************************************************************************
    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")
     1705buffers_c = "xpra/buffers/buffers.c"
     1706memalign_c = "xpra/buffers/memalign.c"
     1707xxhash_c = "xpra/buffers/xxhash.c"
     1708membuffers_c = [memalign_c, buffers_c, xxhash_c]
     1709
     1710add_packages("xpra.buffers")
     1711buffers_pkgconfig = pkgconfig(optimize=3)
     1712cython_add(Extension("xpra.buffers.membuf",
     1713            ["xpra/buffers/membuf.pyx"]+membuffers_c, **buffers_pkgconfig))
     1714
     1715
     1716toggle_packages(dbus_ENABLED, "xpra.dbus")
     1717toggle_packages(mdns_ENABLED, "xpra.net.mdns")
     1718toggle_packages(server_ENABLED or proxy_ENABLED, "xpra.server", "xpra.server.auth")
     1719toggle_packages(rfb_ENABLED, "xpra.server.rfb")
     1720toggle_packages(proxy_ENABLED, "xpra.server.proxy")
     1721toggle_packages(server_ENABLED, "xpra.server.window")
     1722toggle_packages(server_ENABLED or shadow_ENABLED, "xpra.server.mixins", "xpra.server.source")
     1723toggle_packages(shadow_ENABLED, "xpra.server.shadow")
     1724toggle_packages(server_ENABLED or client_ENABLED, "xpra.clipboard")
     1725toggle_packages(x11_ENABLED and dbus_ENABLED and server_ENABLED, "xpra.x11.dbus")
     1726toggle_packages(client_ENABLED or server_ENABLED, "xpra.notifications")
     1727
     1728#cannot use toggle here as cx_Freeze will complain if we try to exclude this module:
     1729if dbus_ENABLED and server_ENABLED:
     1730    add_packages("xpra.server.dbus")
     1731
     1732if OSX:
     1733    if PYTHON3:
     1734        quartz_pkgconfig = pkgconfig("gtk+-3.0", "pygobject-3.0")
     1735        add_to_keywords(quartz_pkgconfig, 'extra_compile_args',
     1736                    "-ObjC",
     1737                    "-framework", "AppKit",
     1738                    "-I/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/")
     1739        cython_add(Extension("xpra.platform.darwin.gdk3_bindings",
     1740                ["xpra/platform/darwin/gdk3_bindings.pyx"],
     1741                language="objc",
     1742                **quartz_pkgconfig
     1743                ))
     1744    else:
     1745        quartz_pkgconfig = pkgconfig(*PYGTK_PACKAGES)
     1746        add_to_keywords(quartz_pkgconfig, 'extra_compile_args',
     1747                    '-mmacosx-version-min=10.10',
     1748                    '-framework', 'Foundation',
     1749                    '-framework', 'AppKit',
     1750                    '-ObjC',
     1751                    "-I/System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/Cocoa.h")
     1752        cython_add(Extension("xpra.platform.darwin.gdk_bindings",
     1753                ["xpra/platform/darwin/gdk_bindings.pyx", "xpra/platform/darwin/nsevent_glue.m"],
     1754                language="objc",
     1755                **quartz_pkgconfig
     1756                ))
     1757
     1758monotonic_time_pkgconfig = pkgconfig()
     1759if not OSX and not WIN32 and not OPENBSD:
     1760    add_to_keywords(monotonic_time_pkgconfig, 'extra_link_args', "-lrt")
     1761cython_add(Extension("xpra.monotonic_time",
     1762            ["xpra/monotonic_time.pyx", "xpra/monotonic_ctime.c"],
     1763            **monotonic_time_pkgconfig
     1764            ))
     1765
     1766
     1767toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.bindings")
    10841768if x11_ENABLED:
    10851769    make_constants("xpra", "x11", "bindings", "constants")
    1086     make_constants("xpra", "x11", "gtk_x11", "constants")
     1770    if gtk2_ENABLED:
     1771        make_constants("xpra", "x11", "constants", pxi_file="xpra/x11/gtk2/constants.pxi")
     1772    if gtk3_ENABLED:
     1773        make_constants("xpra", "x11", "constants", pxi_file="xpra/x11/gtk3/constants.pxi")
    10871774
    10881775    cython_add(Extension("xpra.x11.bindings.wait_for_x_server",
     
    10981785                **pkgconfig("x11")
    10991786                ))
     1787    cython_add(Extension("xpra.x11.bindings.posix_display_source",
     1788                ["xpra/x11/bindings/posix_display_source.pyx"],
     1789                **pkgconfig("x11")
     1790                ))
     1791
    11001792    cython_add(Extension("xpra.x11.bindings.randr_bindings",
    11011793                ["xpra/x11/bindings/randr_bindings.pyx"],
     
    11041796    cython_add(Extension("xpra.x11.bindings.keyboard_bindings",
    11051797                ["xpra/x11/bindings/keyboard_bindings.pyx"],
    1106                 **pkgconfig("x11", "xtst", "xfixes")
     1798                **pkgconfig("x11", "xtst", "xfixes", "xkbfile")
    11071799                ))
    11081800
    11091801    cython_add(Extension("xpra.x11.bindings.window_bindings",
    11101802                ["xpra/x11/bindings/window_bindings.pyx"],
    1111                 **pkgconfig("xtst", "xfixes", "xcomposite", "xdamage")
     1803                **pkgconfig("x11", "xtst", "xfixes", "xcomposite", "xdamage", "xext")
    11121804                ))
    11131805    cython_add(Extension("xpra.x11.bindings.ximage",
    11141806                ["xpra/x11/bindings/ximage.pyx"],
    1115                 **pkgconfig("xcomposite", "xdamage", "xext")
     1807                **pkgconfig("x11", "xext", "xcomposite")
    11161808                ))
    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)
     1809if xinput_ENABLED:
     1810    cython_add(Extension("xpra.x11.bindings.xi2_bindings",
     1811                ["xpra/x11/bindings/xi2_bindings.pyx"],
     1812                **pkgconfig("x11", "xi")
    11221813                ))
    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)
     1814
     1815toggle_packages(gtk_x11_ENABLED, "xpra.x11.gtk_x11")
     1816if gtk_x11_ENABLED:
     1817    toggle_packages(PYTHON3, "xpra.x11.gtk3")
     1818    toggle_packages(not PYTHON3, "xpra.x11.gtk2", "xpra.x11.gtk2.models")
     1819    if PYTHON3:
     1820        #GTK3 display source:
     1821        cython_add(Extension("xpra.x11.gtk3.gdk_display_source",
     1822                    ["xpra/x11/gtk3/gdk_display_source.pyx"],
     1823                    **pkgconfig("gdk-3.0")
     1824                    ))
     1825        cython_add(Extension("xpra.x11.gtk3.gdk_bindings",
     1826                    ["xpra/x11/gtk3/gdk_bindings.pyx"],
     1827                    **pkgconfig("gdk-3.0")
     1828                    ))
     1829    else:
     1830        #GTK2:
     1831        cython_add(Extension("xpra.x11.gtk2.gdk_display_source",
     1832                    ["xpra/x11/gtk2/gdk_display_source.pyx"],
     1833                    **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1834                    ))
     1835        GDK_BINDINGS_PACKAGES = PYGTK_PACKAGES + ["x11", "xext", "xfixes", "xdamage"]
     1836        cython_add(Extension("xpra.x11.gtk2.gdk_bindings",
     1837                    ["xpra/x11/gtk2/gdk_bindings.pyx"],
     1838                    **pkgconfig(*GDK_BINDINGS_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1839                    ))
     1840
     1841toggle_packages(not PYTHON3 and (gtk2_ENABLED or gtk_x11_ENABLED), "xpra.gtk_common.gtk2")
     1842if gtk2_ENABLED or (gtk_x11_ENABLED and not PYTHON3):
     1843    cython_add(Extension("xpra.gtk_common.gtk2.gdk_bindings",
     1844                ["xpra/gtk_common/gtk2/gdk_bindings.pyx"],
     1845                **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
    11271846                ))
    1128 
    1129 
    1130 toggle_packages(argb_ENABLED, "xpra.codecs.argb")
    1131 if argb_ENABLED:
     1847elif gtk3_ENABLED or (gtk_x11_ENABLED and PYTHON3):
     1848    cython_add(Extension("xpra.gtk_common.gtk3.gdk_bindings",
     1849                ["xpra/gtk_common/gtk3/gdk_bindings.pyx"],
     1850                **pkgconfig("gtk+-3.0", "pygobject-3.0")
     1851                ))
     1852
     1853if client_ENABLED and gtk3_ENABLED:
     1854    #cairo workaround:
     1855    if OSX:
     1856        pycairo = "py3cairo"
     1857    else:
     1858        pycairo = "pycairo"
     1859    cython_add(Extension("xpra.client.gtk3.cairo_workaround",
     1860                ["xpra/client/gtk3/cairo_workaround.pyx"],
     1861                **pkgconfig(pycairo)
     1862                ))
     1863
     1864if client_ENABLED or server_ENABLED:
     1865    add_packages("xpra.codecs.argb")
     1866    argb_pkgconfig = pkgconfig(optimize=3)
    11321867    cython_add(Extension("xpra.codecs.argb.argb",
    1133                 ["xpra/codecs/argb/argb.pyx"]))
     1868                ["xpra/codecs/argb/argb.pyx"], **argb_pkgconfig))
     1869
     1870
     1871#build tests, but don't install them:
     1872toggle_packages(tests_ENABLED, "unit")
    11341873
    11351874
    11361875if bundle_tests_ENABLED:
    11371876    #bundle the tests directly (not in library.zip):
    1138     for k,v in glob_recurse("tests").items():
     1877    for k,v in glob_recurse("unit").items():
    11391878        if (k!=""):
    11401879            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:
     1880        add_data_files("unit"+k, v)
     1881
     1882#python-cryptography needs workarounds for bundling:
     1883if crypto_ENABLED and (OSX or WIN32):
     1884    external_includes.append("_ssl")
     1885    external_includes.append("cffi")
     1886    external_includes.append("_cffi_backend")
     1887    external_includes.append("cryptography")
     1888    external_includes.append("idna")
     1889    external_includes.append("idna.idnadata")
     1890    external_includes.append("pkg_resources._vendor.packaging")
     1891    external_includes.append("pkg_resources._vendor.packaging.requirements")
     1892    external_includes.append("pkg_resources._vendor.pyparsing")
     1893    add_modules("cryptography.hazmat.bindings._openssl")
     1894    add_modules("cryptography.hazmat.bindings._constant_time")
     1895    add_modules("cryptography.hazmat.bindings._padding")
     1896    add_modules("cryptography.hazmat.backends.openssl")
     1897    add_modules("cryptography.fernet")
     1898    if WIN32:
     1899        external_includes.append("appdirs")
     1900
     1901#special case for client: cannot use toggle_packages which would include gtk3, etc:
    11441902if client_ENABLED:
    1145     add_modules("xpra.client", "xpra.client.notifications")
    1146 toggle_packages((client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED)) or server_ENABLED, "xpra.gtk_common")
     1903    add_modules("xpra.client", "xpra.client.mixins")
     1904    add_modules("xpra.scripts.gtk_info")
     1905    add_modules("xpra.scripts.show_webcam")
     1906toggle_packages((client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED)) or (PYTHON3 and sound_ENABLED) or server_ENABLED, "xpra.gtk_common")
    11471907toggle_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")
     1908toggle_packages(client_ENABLED and gtk3_ENABLED, "xpra.client.gtk3")
     1909toggle_packages((client_ENABLED and gtk3_ENABLED) or (sound_ENABLED and WIN32 and (MINGW_PREFIX or PYTHON3)), "gi")
    11501910toggle_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")
     1911toggle_packages(client_ENABLED and opengl_ENABLED and gtk2_ENABLED, "xpra.client.gl.gtk2")
     1912toggle_packages(client_ENABLED and opengl_ENABLED and gtk3_ENABLED, "xpra.client.gl.gtk3")
     1913toggle_packages(client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED) and example_ENABLED, "xpra.client.gtk_base.example")
     1914if client_ENABLED and WIN32 and MINGW_PREFIX:
     1915    propsys_pkgconfig = pkgconfig()
     1916    if debug_ENABLED:
     1917        add_to_keywords(propsys_pkgconfig, 'extra_compile_args', "-DDEBUG")
     1918    add_to_keywords(propsys_pkgconfig, 'extra_link_args', "-luuid", "-lshlwapi", "-lole32", "-static-libgcc")
     1919    cython_add(Extension("xpra.platform.win32.propsys",
     1920                ["xpra/platform/win32/propsys.pyx", "xpra/platform/win32/setappid.cpp"],
     1921                language="c++",
     1922                **propsys_pkgconfig))
     1923
     1924if client_ENABLED or server_ENABLED:
     1925    add_modules("xpra.codecs")
     1926toggle_packages(client_ENABLED or server_ENABLED, "xpra.keyboard")
     1927if client_ENABLED or server_ENABLED:
     1928    add_modules("xpra.scripts.config", "xpra.scripts.parsing", "xpra.scripts.exec_util", "xpra.scripts.fdproxy", "xpra.scripts.version")
     1929if server_ENABLED or proxy_ENABLED:
     1930    add_modules("xpra.scripts.server")
     1931if WIN32 and client_ENABLED and (gtk2_ENABLED or gtk3_ENABLED):
     1932    add_modules("xpra.scripts.gtk_info")
     1933
     1934toggle_packages(not WIN32, "xpra.platform.pycups_printing")
     1935#we can't just include "xpra.client.gl" because cx_freeze then do the wrong thing
     1936#and tries to include both gtk3 and gtk2, and fails hard..
     1937for x in ("gl_check", "gl_colorspace_conversions", "gl_window_backing_base", "gl_drivers"):
     1938    toggle_packages(client_ENABLED and opengl_ENABLED, "xpra.client.gl.%s" % x)
     1939toggle_packages(client_ENABLED and opengl_ENABLED and (gtk2_ENABLED or gtk3_ENABLED), "xpra.client.gl.gtk_base")
     1940
     1941
     1942toggle_modules(sound_ENABLED, "xpra.sound")
     1943toggle_modules(sound_ENABLED and not (OSX or WIN32), "xpra.sound.pulseaudio")
    11541944
    11551945toggle_packages(clipboard_ENABLED, "xpra.clipboard")
    11561946if 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:
     1947    if PYTHON3:
     1948        cython_add(Extension("xpra.gtk_common.gtk3.gdk_atoms",
     1949                             ["xpra/gtk_common/gtk3/gdk_atoms.pyx"],
     1950                             **pkgconfig("gtk+-3.0")
     1951                             ))
     1952    else:
     1953        cython_add(Extension("xpra.gtk_common.gtk2.gdk_atoms",
     1954                             ["xpra/gtk_common/gtk2/gdk_atoms.pyx"],
     1955                             **pkgconfig(*PYGTK_PACKAGES, ignored_tokens=gtk2_ignored_tokens)
     1956                             ))
     1957
     1958toggle_packages(client_ENABLED or server_ENABLED, "xpra.codecs.xor")
     1959if client_ENABLED or server_ENABLED:
    11631960    cython_add(Extension("xpra.codecs.xor.cyxor",
    11641961                ["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")
     1962                **pkgconfig(optimize=3)))
     1963
     1964if server_ENABLED or shadow_ENABLED:
     1965    O3_pkgconfig = pkgconfig(optimize=3)
     1966    cython_add(Extension("xpra.server.cystats",
     1967                ["xpra/server/cystats.pyx"],
     1968                **O3_pkgconfig))
     1969    cython_add(Extension("xpra.server.window.region",
     1970                ["xpra/server/window/region.pyx"],
     1971                **O3_pkgconfig))
     1972    cython_add(Extension("xpra.server.window.motion",
     1973                ["xpra/server/window/motion.pyx"],
     1974                **O3_pkgconfig))
     1975
     1976if sd_listen_ENABLED:
     1977    sdp = pkgconfig("libsystemd")
     1978    cython_add(Extension("xpra.platform.xposix.sd_listen",
     1979                ["xpra/platform/xposix/sd_listen.pyx"],
     1980                **sdp))
     1981
     1982
    11781983toggle_packages(enc_proxy_ENABLED, "xpra.codecs.enc_proxy")
    11791984
     1985toggle_packages(nvfbc_ENABLED, "xpra.codecs.nvfbc")
     1986if nvfbc_ENABLED:
     1987    nvfbc_pkgconfig = pkgconfig("nvfbc")
     1988    #add_to_keywords(nvfbc_pkgconfig, 'extra_compile_args', "-Wno-endif-labels")
     1989    platform = sys.platform.rstrip("0123456789")
     1990    cython_add(Extension("xpra.codecs.nvfbc.fbc_capture_%s" % platform,
     1991                         ["xpra/codecs/nvfbc/fbc_capture_%s.pyx" % platform],
     1992                         language="c++",
     1993                         **nvfbc_pkgconfig))
     1994
    11801995toggle_packages(nvenc_ENABLED, "xpra.codecs.nvenc")
     1996toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.cuda_common")
     1997toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.nv_util")
     1998
     1999if nvenc_ENABLED and cuda_kernels_ENABLED:
     2000    #find nvcc:
     2001    path_options = os.environ.get("PATH", "").split(os.path.pathsep)
     2002    if WIN32:
     2003        nvcc_exe = "nvcc.exe"
     2004        path_options = [
     2005                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin",
     2006                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v8.0\\bin",
     2007                         "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v7.5\\bin",
     2008                         ] + path_options
     2009        #pycuda may link against curand, find it and ship it:
     2010        for p in path_options:
     2011            if os.path.exists(p):
     2012                add_data_files("", glob.glob("%s\\curand64*.dll" % p))
     2013                break
     2014    else:
     2015        nvcc_exe = "nvcc"
     2016        for v in ("", "-9.0", "-8.0", "-7.5"):
     2017            path_options += ["/usr/local/cuda%s/bin" % v, "/opt/cuda%s/bin" % v]
     2018    options = [os.path.join(x, nvcc_exe) for x in path_options]
     2019    def which(cmd):
     2020        try:
     2021            code, out, _ = get_status_output(["which", cmd])
     2022            if code==0:
     2023                return out
     2024        except:
     2025            pass
     2026    #prefer the one we find on the $PATH, if any:
     2027    try:
     2028        v = which(nvcc_exe)
     2029        if v and (v not in options):
     2030            options.insert(0, v)
     2031    except:
     2032        pass
     2033    nvcc_versions = {}
     2034    for filename in options:
     2035        if not os.path.exists(filename):
     2036            continue
     2037        code, out, err = get_status_output([filename, "--version"])
     2038        if code==0:
     2039            vpos = out.rfind(", V")
     2040            if vpos>0:
     2041                version = out[vpos+3:].strip("\n")
     2042                version_str = " version %s" % version
     2043            else:
     2044                version = "0"
     2045                version_str = " unknown version!"
     2046            print("found CUDA compiler: %s%s" % (filename, version_str))
     2047            nvcc_versions[version] = filename
     2048    assert nvcc_versions, "cannot find nvcc compiler!"
     2049    #choose the most recent one:
     2050    version, nvcc = list(reversed(sorted(nvcc_versions.items())))[0]
     2051    if len(nvcc_versions)>1:
     2052        print(" using version %s from %s" % (version, nvcc))
     2053    if WIN32:
     2054        cuda_path = os.path.dirname(nvcc)           #strip nvcc.exe
     2055        cuda_path = os.path.dirname(cuda_path)      #strip /bin/
     2056    #first compile the cuda kernels
     2057    #(using the same cuda SDK for both nvenc modules for now..)
     2058    #TODO:
     2059    # * compile directly to output directory instead of using data files?
     2060    # * detect which arches we want to build for? (does it really matter much?)
     2061    kernels = ("ARGB_to_NV12", "ARGB_to_YUV444", "BGRA_to_NV12", "BGRA_to_YUV444")
     2062    for kernel in kernels:
     2063        cuda_src = "xpra/codecs/cuda_common/%s.cu" % kernel
     2064        cuda_bin = "xpra/codecs/cuda_common/%s.fatbin" % kernel
     2065        if os.path.exists(cuda_bin) and (cuda_rebuild_ENABLED is False):
     2066            continue
     2067        reason = should_rebuild(cuda_src, cuda_bin)
     2068        if not reason:
     2069            continue
     2070        cmd = [nvcc,
     2071               '-fatbin',
     2072               #"-cubin",
     2073               #"-arch=compute_30", "-code=compute_30,sm_30,sm_35",
     2074               #"-gencode=arch=compute_50,code=sm_50",
     2075               #"-gencode=arch=compute_52,code=sm_52",
     2076               #"-gencode=arch=compute_52,code=compute_52",
     2077               "-c", cuda_src,
     2078               "-o", cuda_bin]
     2079        #GCC 6 uses C++11 by default:
     2080        if get_gcc_version()>=[6, 0]:
     2081            cmd.append("-std=c++11")
     2082        CL_VERSION = os.environ.get("CL_VERSION")
     2083        if CL_VERSION:
     2084            cmd += ["--use-local-env", "--cl-version", CL_VERSION]
     2085            #-ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cl.exe"
     2086            cmd += ["--machine", "32"]
     2087        if WIN32:
     2088            #cmd += ["--compiler-bindir", "C:\\msys64\\mingw64\\bin\\g++.exe"]
     2089            #cmd += ["--input-drive-prefix", "/"]
     2090            #cmd += ["--dependency-drive-prefix", "/"]
     2091            cmd += ["-I%s" % os.path.abspath("win32")]
     2092        comp_code_options = [(30, 30), (35, 35)]
     2093        #see: http://docs.nvidia.com/cuda/maxwell-compatibility-guide/#building-maxwell-compatible-apps-using-cuda-6-0
     2094        if version!="0" and version<"7.5":
     2095            print("CUDA version %s is very unlikely to work")
     2096            print("try upgrading to version 7.5 or later")
     2097        if version>="7.5":
     2098            comp_code_options.append((50, 50))
     2099            comp_code_options.append((52, 52))
     2100            comp_code_options.append((53, 53))
     2101        if version>="8.0":
     2102            comp_code_options.append((60, 60))
     2103            comp_code_options.append((61, 61))
     2104            comp_code_options.append((62, 62))
     2105        if version>="9.0":
     2106            comp_code_options.append((70, 70))
     2107        for arch, code in comp_code_options:
     2108            cmd.append("-gencode=arch=compute_%s,code=sm_%s" % (arch, code))
     2109        print("CUDA compiling %s (%s)" % (kernel.ljust(16), reason))
     2110        print(" %s" % " ".join("'%s'" % x for x in cmd))
     2111        c, stdout, stderr = get_status_output(cmd)
     2112        if c!=0:
     2113            print("Error: failed to compile CUDA kernel %s" % kernel)
     2114            print(stdout or "")
     2115            print(stderr or "")
     2116            sys.exit(1)
     2117    CUDA_BIN = "share/xpra/cuda"
     2118    if WIN32:
     2119        CUDA_BIN = "CUDA"
     2120    add_data_files(CUDA_BIN, ["xpra/codecs/cuda_common/%s.fatbin" % x for x in kernels])
     2121
    11812122if 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))
     2123    nvencmodule = "nvenc"
     2124    nvenc_pkgconfig = pkgconfig(nvencmodule, ignored_flags=["-l", "-L"])
     2125    #don't link against libnvidia-encode, we load it dynamically:
     2126    libraries = nvenc_pkgconfig.get("libraries", [])
     2127    if "nvidia-encode" in libraries:
     2128        libraries.remove("nvidia-encode")
     2129    if PYTHON3 and get_gcc_version()>=[6, 2]:
     2130        #with gcc 6.2 on Fedora:
     2131        #xpra/codecs/nvenc/encoder.c: In function '__Pyx_PyInt_LshiftObjC':
     2132        #xpra/codecs/nvenc/encoder.c:45878:34: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
     2133        #    if (unlikely(!(b < sizeof(long)*8 && a == x >> b)) && a) {
     2134        add_to_keywords(nvenc_pkgconfig, 'extra_compile_args', "-Wno-sign-compare")
     2135    cython_add(Extension("xpra.codecs.%s.encoder" % nvencmodule,
     2136                         ["xpra/codecs/%s/encoder.pyx" % nvencmodule],
     2137                         **nvenc_pkgconfig))
    11872138
    11882139toggle_packages(enc_x264_ENABLED, "xpra.codecs.enc_x264")
    11892140if enc_x264_ENABLED:
    1190     x264_pkgconfig = pkgconfig("x264", static=x264_static_ENABLED)
     2141    x264_pkgconfig = pkgconfig("x264")
     2142    if get_gcc_version()>=[6, 0]:
     2143        add_to_keywords(x264_pkgconfig, 'extra_compile_args', "-Wno-unused-variable")
    11912144    cython_add(Extension("xpra.codecs.enc_x264.encoder",
    11922145                ["xpra/codecs/enc_x264/encoder.pyx"],
    1193                 **x264_pkgconfig), min_version=(0, 16))
     2146                **x264_pkgconfig))
    11942147
    11952148toggle_packages(enc_x265_ENABLED, "xpra.codecs.enc_x265")
    11962149if enc_x265_ENABLED:
    1197     x265_pkgconfig = pkgconfig("x265", static=x265_static_ENABLED)
     2150    x265_pkgconfig = pkgconfig("x265")
    11982151    cython_add(Extension("xpra.codecs.enc_x265.encoder",
    11992152                ["xpra/codecs/enc_x265/encoder.pyx"],
    1200                 **x265_pkgconfig), min_version=(0, 16))
     2153                **x265_pkgconfig))
     2154
     2155toggle_packages(pillow_ENABLED, "xpra.codecs.pillow")
     2156if pillow_ENABLED:
     2157    external_includes += ["PIL", "PIL.Image", "PIL.WebPImagePlugin"]
    12012158
    12022159toggle_packages(webp_ENABLED, "xpra.codecs.webp")
     
    12042161    webp_pkgconfig = pkgconfig("webp")
    12052162    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))
     2163                    ["xpra/codecs/webp/encode.pyx"],
     2164                    **webp_pkgconfig))
     2165    cython_add(Extension("xpra.codecs.webp.decode",
     2166                ["xpra/codecs/webp/decode.pyx"],
     2167                **webp_pkgconfig))
     2168
     2169toggle_packages(jpeg_ENABLED, "xpra.codecs.jpeg")
     2170if jpeg_ENABLED:
     2171    jpeg_pkgconfig = pkgconfig("libturbojpeg")
     2172    cython_add(Extension("xpra.codecs.jpeg.encoder",
     2173                ["xpra/codecs/jpeg/encoder.pyx"],
     2174                **jpeg_pkgconfig))
     2175    cython_add(Extension("xpra.codecs.jpeg.decoder",
     2176                ["xpra/codecs/jpeg/decoder.pyx"],
     2177                **jpeg_pkgconfig))
     2178
     2179#swscale and avcodec2 use libav_common/av_log:
     2180libav_common = dec_avcodec2_ENABLED or csc_swscale_ENABLED
     2181toggle_packages(libav_common, "xpra.codecs.libav_common")
     2182if libav_common:
     2183    avutil_pkgconfig = pkgconfig("avutil")
     2184    cython_add(Extension("xpra.codecs.libav_common.av_log",
     2185                ["xpra/codecs/libav_common/av_log.pyx"],
     2186                **avutil_pkgconfig))
     2187
    12162188
    12172189toggle_packages(dec_avcodec2_ENABLED, "xpra.codecs.dec_avcodec2")
    12182190if dec_avcodec2_ENABLED:
    1219     avcodec2_pkgconfig = pkgconfig("avcodec", "avutil", static=avcodec2_static_ENABLED)
     2191    avcodec2_pkgconfig = pkgconfig("avcodec", "avutil", "avformat")
    12202192    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 
     2193                ["xpra/codecs/dec_avcodec2/decoder.pyx", "xpra/codecs/dec_avcodec2/register_compat.c"],
     2194                **avcodec2_pkgconfig))
     2195
     2196
     2197toggle_packages(csc_libyuv_ENABLED, "xpra.codecs.csc_libyuv")
     2198if csc_libyuv_ENABLED:
     2199    libyuv_pkgconfig = pkgconfig("libyuv")
     2200    cython_add(Extension("xpra.codecs.csc_libyuv.colorspace_converter",
     2201                ["xpra/codecs/csc_libyuv/colorspace_converter.pyx"],
     2202                language="c++",
     2203                **libyuv_pkgconfig))
    12242204
    12252205toggle_packages(csc_swscale_ENABLED, "xpra.codecs.csc_swscale")
    12262206if csc_swscale_ENABLED:
    1227     make_constants("xpra", "codecs", "csc_swscale", "constants")
    1228     swscale_pkgconfig = pkgconfig("swscale", static=swscale_static_ENABLED)
     2207    swscale_pkgconfig = pkgconfig("swscale", "avutil")
    12292208    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))
     2209                ["xpra/codecs/csc_swscale/colorspace_converter.pyx"],
     2210                **swscale_pkgconfig))
     2211
    12392212
    12402213toggle_packages(vpx_ENABLED, "xpra.codecs.vpx")
    12412214if vpx_ENABLED:
    1242     vpx_pkgconfig = pkgconfig("vpx", static=vpx_static_ENABLED)
     2215    vpx_pkgconfig = pkgconfig("vpx")
    12432216    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))
     2217                ["xpra/codecs/vpx/encoder.pyx"],
     2218                **vpx_pkgconfig))
    12462219    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))
     2220                ["xpra/codecs/vpx/decoder.pyx"],
     2221                **vpx_pkgconfig))
     2222
     2223toggle_packages(enc_ffmpeg_ENABLED, "xpra.codecs.enc_ffmpeg")
     2224if enc_ffmpeg_ENABLED:
     2225    ffmpeg_pkgconfig = pkgconfig("libavcodec", "libavformat", "libavutil")
     2226    cython_add(Extension("xpra.codecs.enc_ffmpeg.encoder",
     2227                ["xpra/codecs/enc_ffmpeg/encoder.pyx"],
     2228                **ffmpeg_pkgconfig))
     2229
     2230toggle_packages(v4l2_ENABLED, "xpra.codecs.v4l2")
     2231if v4l2_ENABLED:
     2232    v4l2_pkgconfig = pkgconfig()
     2233    #fuly warning: cython makes this difficult,
     2234    #we have to figure out if "device_caps" exists in the headers:
     2235    ENABLE_DEVICE_CAPS = False
     2236    if os.path.exists("/usr/include/linux/videodev2.h"):
     2237        hdata = open("/usr/include/linux/videodev2.h").read()
     2238        ENABLE_DEVICE_CAPS = hdata.find("device_caps")>=0
     2239    kwargs = {"ENABLE_DEVICE_CAPS" : ENABLE_DEVICE_CAPS}
     2240    make_constants("xpra", "codecs", "v4l2", "constants", **kwargs)
     2241    cython_add(Extension("xpra.codecs.v4l2.pusher",
     2242                ["xpra/codecs/v4l2/pusher.pyx"],
     2243                **v4l2_pkgconfig))
    12622244
    12632245
    12642246toggle_packages(bencode_ENABLED, "xpra.net.bencode")
     2247toggle_packages(bencode_ENABLED and cython_bencode_ENABLED, "xpra.net.bencode.cython_bencode")
    12652248if 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")
     2249    bencode_pkgconfig = pkgconfig(optimize=3)
    12722250    cython_add(Extension("xpra.net.bencode.cython_bencode",
    12732251                ["xpra/net/bencode/cython_bencode.pyx"],
    12742252                **bencode_pkgconfig))
    12752253
     2254if netdev_ENABLED:
     2255    netdev_pkgconfig = pkgconfig()
     2256    cython_add(Extension("xpra.platform.xposix.netdev_query",
     2257                ["xpra/platform/xposix/netdev_query.pyx"],
     2258                **netdev_pkgconfig))
     2259
     2260if vsock_ENABLED:
     2261    vsock_pkgconfig = pkgconfig()
     2262    cython_add(Extension("xpra.net.vsock",
     2263                ["xpra/net/vsock.pyx"],
     2264                **vsock_pkgconfig))
     2265
     2266if pam_ENABLED:
     2267    pam_pkgconfig = pkgconfig()
     2268    add_to_keywords(pam_pkgconfig, 'extra_compile_args', "-I/usr/include/pam", "-I/usr/include/security")
     2269    add_to_keywords(pam_pkgconfig, 'extra_link_args', "-lpam", "-lpam_misc")
     2270    cython_add(Extension("xpra.server.pam",
     2271                ["xpra/server/pam.pyx"],
     2272                **pam_pkgconfig))
     2273
    12762274
    12772275if ext_modules:
    1278     setup_options["ext_modules"] = ext_modules
     2276    from Cython.Build import cythonize
     2277    #this causes Cython to fall over itself:
     2278    #gdb_debug=debug_ENABLED
     2279    setup_options["ext_modules"] = cythonize(ext_modules, gdb_debug=False)
    12792280if cmdclass:
    12802281    setup_options["cmdclass"] = cmdclass
     
    12832284
    12842285
    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 
    12932286def main():
    12942287    if OSX or WIN32 or debug_ENABLED:
     2288        print()
    12952289        print("setup options:")
     2290        if verbose_ENABLED:
     2291            print("setup_options=%s" % (setup_options,))
     2292        try:
     2293            from xpra.util import repr_ellipsized as pv
     2294        except:
     2295            def pv(v):
     2296                return str(v)
    12962297        for k,v in setup_options.items():
    1297             print_option("", k, v)
     2298            print_option("", k, pv(v))
    12982299        print("")
    12992300
Note: See TracChangeset for help on using the changeset viewer.