xpra icon
Bug tracker and wiki

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


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/setup.py

    r6000 r26563  
    22
    33# This file is part of Xpra.
    4 # Copyright (C) 2010-2014 Antoine Martin <antoine@devloop.org.uk>
     4# Copyright (C) 2010-2019 Antoine Martin <antoine@xpra.org>
    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
     
    88
    99##############################################################################
    10 # FIXME: Cython.Distutils.build_ext leaves crud in the source directory.  (So
    11 # does the make_constants hack.)
    12 
    13 import commands
     10# FIXME: Cython.Distutils.build_ext leaves crud in the source directory.
     11
     12import ssl
     13import sys
    1414import glob
     15import shutil
     16import os.path
     17
    1518from distutils.core import setup
    1619from distutils.extension import Extension
    17 import subprocess, sys, traceback
    18 import os.path
    19 import stat
     20from distutils.command.build import build
     21from distutils.command.install_data import install_data
     22
     23import xpra
     24from xpra.os_util import (
     25    get_status_output,
     26    BITS, WIN32, OSX, LINUX, POSIX, NETBSD, FREEBSD, OPENBSD,
     27    is_Ubuntu, is_Debian, is_Fedora, is_CentOS, is_RedHat,
     28    )
     29
     30if sys.version_info<(3, 6):
     31    raise Exception("xpra no longer supports Python versions older than 3.6")
     32#we don't support versions of Python without the new ssl code:
     33if not hasattr(ssl, "SSLContext"):
     34    print("Warning: xpra requires a Python version with ssl.SSLContext support")
     35    print(" SSL support will not be available!")
    2036
    2137print(" ".join(sys.argv))
    2238
    23 import xpra
    24 from xpra.platform.features import LOCAL_SERVERS_SUPPORTED, SHADOW_SUPPORTED
    25 
    26 WIN32 = sys.platform.startswith("win")
    27 OSX = sys.platform.startswith("darwin")
    28 
    29 
     39#*******************************************************************************
     40# build options, these may get modified further down..
     41#
     42data_files = []
     43modules = []
     44packages = []       #used by py2app
     45excludes = []       #only used by cx_freeze on win32
     46ext_modules = []
     47cmdclass = {}
     48scripts = []
     49description = "multi-platform screen and application forwarding system"
     50long_description = "Xpra is a multi platform persistent remote display server and client for " + \
     51            "forwarding applications and desktop screens. Also known as 'screen for X11'."
     52url = "https://xpra.org/"
     53
     54
     55XPRA_VERSION = xpra.__version__         #@UndefinedVariable
     56setup_options = {
     57                 "name"             : "xpra",
     58                 "version"          : XPRA_VERSION,
     59                 "license"          : "GPLv2+",
     60                 "author"           : "Antoine Martin",
     61                 "author_email"     : "antoine@xpra.org",
     62                 "url"              : url,
     63                 "download_url"     : "https://xpra.org/src/",
     64                 "description"      : description,
     65                 "long_description" : long_description,
     66                 "data_files"       : data_files,
     67                 "py_modules"       : modules,
     68                 }
     69
     70
     71if "pkg-info" in sys.argv:
     72    with open("PKG-INFO", "wb") as f:
     73        pkg_info_values = setup_options.copy()
     74        pkg_info_values.update({
     75                                "metadata_version"  : "1.1",
     76                                "summary"           :  description,
     77                                "home_page"         : url,
     78                                })
     79        for k in ("Metadata-Version", "Name", "Version", "Summary", "Home-page",
     80                  "Author", "Author-email", "License", "Download-URL", "Description"):
     81            v = pkg_info_values[k.lower().replace("-", "_")]
     82            f.write(b"%s: %s\n" % (k, v))
     83    sys.exit(0)
     84
     85
     86print("Xpra version %s" % XPRA_VERSION)
    3087#*******************************************************************************
    3188# Most of the options below can be modified on the command line
     
    3390# only the default values are specified here:
    3491#*******************************************************************************
     92
     93PKG_CONFIG = os.environ.get("PKG_CONFIG", "pkg-config")
     94has_pkg_config = False
     95if PKG_CONFIG:
     96    v = get_status_output([PKG_CONFIG, "--version"])
     97    has_pkg_config = v[0]==0 and v[1]
     98    if has_pkg_config:
     99        print("found pkg-config version: %s" % v[1].strip("\n\r"))
     100    else:
     101        print("WARNING: pkg-config not found!")
     102
     103for arg in list(sys.argv):
     104    if arg.startswith("--pkg-config-path="):
     105        pcp = arg[len("--pkg-config-path="):]
     106        pcps = [pcp] + os.environ.get("PKG_CONFIG_PATH", "").split(os.path.pathsep)
     107        os.environ["PKG_CONFIG_PATH"] = os.path.pathsep.join([x for x in pcps if x])
     108        print("using PKG_CONFIG_PATH=%s" % (os.environ["PKG_CONFIG_PATH"], ))
     109        sys.argv.remove(arg)
     110
     111def no_pkgconfig(*_pkgs_options, **_ekw):
     112    return {}
     113
    35114def 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 
     115    return get_status_output([PKG_CONFIG] + [str(x) for x in args])[0]==0
     116
     117def pkg_config_version(req_version, pkgname):
     118    cmd = [PKG_CONFIG, "--modversion", pkgname]
     119    r, out, _ = get_status_output(cmd)
     120    if r!=0 or not out:
     121        return False
     122    from distutils.version import LooseVersion
     123    return LooseVersion(out)>=LooseVersion(req_version)
     124
     125def is_RH():
     126    try:
     127        with open("/etc/redhat-release", mode='rb') as f:
     128            data = f.read()
     129        return data.startswith("CentOS") or data.startswith("RedHat")
     130    except:
     131        pass
     132    return False
     133
     134DEFAULT = True
     135if "--minimal" in sys.argv:
     136    sys.argv.remove("--minimal")
     137    DEFAULT = False
     138
     139from xpra.platform.features import LOCAL_SERVERS_SUPPORTED, SHADOW_SUPPORTED
     140shadow_ENABLED = SHADOW_SUPPORTED and DEFAULT
     141server_ENABLED = (LOCAL_SERVERS_SUPPORTED or shadow_ENABLED) and DEFAULT
     142rfb_ENABLED = server_ENABLED
     143service_ENABLED = LINUX and server_ENABLED
     144sd_listen_ENABLED = POSIX and pkg_config_ok("--exists", "libsystemd")
     145proxy_ENABLED  = DEFAULT
     146client_ENABLED = DEFAULT
     147scripts_ENABLED = not WIN32
     148cython_ENABLED = DEFAULT
     149modules_ENABLED = DEFAULT
     150data_ENABLED = DEFAULT
     151
     152x11_ENABLED = DEFAULT and not WIN32 and not OSX
     153xinput_ENABLED = x11_ENABLED
     154uinput_ENABLED = x11_ENABLED
     155dbus_ENABLED = DEFAULT and x11_ENABLED and not (OSX or WIN32)
     156gtk_x11_ENABLED = DEFAULT and not WIN32 and not OSX
     157gtk3_ENABLED = DEFAULT and client_ENABLED
     158opengl_ENABLED = DEFAULT and client_ENABLED
     159html5_ENABLED = DEFAULT
     160html5_gzip_ENABLED = DEFAULT
     161html5_brotli_ENABLED = DEFAULT
     162minify_ENABLED = html5_ENABLED
     163pam_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"))
     164
     165xdg_open_ENABLED        = (LINUX or FREEBSD) and DEFAULT
     166netdev_ENABLED          = LINUX and DEFAULT
     167vsock_ENABLED           = LINUX and os.path.exists("/usr/include/linux/vm_sockets.h")
     168bencode_ENABLED         = DEFAULT
     169cython_bencode_ENABLED  = DEFAULT
     170clipboard_ENABLED       = DEFAULT
     171Xdummy_ENABLED          = None if POSIX else False  #None means auto-detect
     172Xdummy_wrapper_ENABLED  = None if POSIX else False  #None means auto-detect
     173if WIN32 or OSX:
     174    Xdummy_ENABLED = False
     175sound_ENABLED           = DEFAULT
     176printing_ENABLED        = DEFAULT
     177crypto_ENABLED          = DEFAULT
     178mdns_ENABLED            = DEFAULT
     179websockets_ENABLED      = DEFAULT
     180
     181enc_proxy_ENABLED       = DEFAULT
     182enc_x264_ENABLED        = DEFAULT and pkg_config_ok("--exists", "x264")
     183#crashes on 32-bit windows:
     184enc_x265_ENABLED        = (not WIN32) and pkg_config_ok("--exists", "x265")
     185pillow_ENABLED          = DEFAULT
     186webp_ENABLED            = DEFAULT and pkg_config_version("0.5", "libwebp")
     187jpeg_encoder_ENABLED    = DEFAULT and pkg_config_version("1.2", "libturbojpeg")
     188jpeg_decoder_ENABLED    = DEFAULT and pkg_config_version("1.4", "libturbojpeg")
     189vpx_ENABLED             = DEFAULT and pkg_config_version("1.4", "vpx")
     190enc_ffmpeg_ENABLED      = DEFAULT and pkg_config_version("58.18", "libavcodec")
     191#opencv currently broken on 32-bit windows (crashes on load):
     192webcam_ENABLED          = DEFAULT and not OSX and (not WIN32 or BITS==64)
     193notifications_ENABLED   = DEFAULT
     194keyboard_ENABLED        = DEFAULT
     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        = DEFAULT
    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         = "--skip-build" not in sys.argv
    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",
    104             "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")
     218SWITCHES = [
     219    "cython", "modules", "data",
     220    "enc_x264", "enc_x265", "enc_ffmpeg",
     221    "nvenc", "cuda_kernels", "cuda_rebuild", "nvfbc",
     222    "vpx", "webp", "pillow", "jpeg_encoder", "jpeg_decoder",
     223    "v4l2",
     224    "dec_avcodec2", "csc_swscale",
     225    "csc_libyuv",
     226    "bencode", "cython_bencode", "vsock", "netdev", "mdns",
     227    "clipboard",
     228    "scripts",
     229    "server", "client", "dbus", "x11", "xinput", "uinput", "sd_listen",
     230    "gtk_x11", "service",
     231    "gtk3", "example",
     232    "html5", "minify", "html5_gzip", "html5_brotli",
     233    "pam", "xdg_open",
     234    "sound", "opengl", "printing", "webcam", "notifications", "keyboard",
     235    "rebuild",
     236    "annotate", "warn", "strict",
     237    "shadow", "proxy", "rfb",
     238    "debug", "PIC",
     239    "Xdummy", "Xdummy_wrapper", "verbose", "tests", "bundle_tests",
     240    ]
    109241HELP = "-h" in sys.argv or "--help" in sys.argv
    110242if HELP:
     
    120252            default_str = "auto-detect"
    121253        print("%s or %s (default: %s)" % (with_str.ljust(25), without_str.ljust(30), default_str))
     254    print("  --pkg-config-path=PATH")
     255    print("  --rpath=PATH")
    122256    sys.exit(0)
    123257
     258install = None
     259rpath = None
     260ssl_cert = None
     261ssl_key = None
     262minifier = None
     263share_xpra = None
    124264filtered_args = []
    125265for arg in sys.argv:
    126     #deprecated flag:
    127     if arg == "--enable-Xdummy":
    128         Xdummy_ENABLED = True
     266    matched = False
     267    for x in ("rpath", "ssl-cert", "ssl-key", "install", "share-xpra"):
     268        varg = "--%s=" % x
     269        if arg.startswith(varg):
     270            value = arg[len(varg):]
     271            globals()[x.replace("-", "_")] = value
     272            #remove these arguments from sys.argv,
     273            #except for --install=PATH
     274            matched = x!="install"
     275            break
     276    if matched:
    129277        continue
    130     matched = False
    131278    for x in SWITCHES:
    132         if arg=="--with-%s" % x:
     279        with_str = "--with-%s" % x
     280        without_str = "--without-%s" % x
     281        if arg.startswith(with_str+"="):
     282            vars()["%s_ENABLED" % x] = arg[len(with_str)+1:]
     283            matched = True
     284            break
     285        elif arg==with_str:
    133286            vars()["%s_ENABLED" % x] = True
    134287            matched = True
    135288            break
    136         elif arg=="--without-%s" % x:
     289        elif arg==without_str:
    137290            vars()["%s_ENABLED" % x] = False
    138291            matched = True
     
    145298    for x in SWITCHES:
    146299        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)
    150 
     300    print("build switches:")
     301    for k in sorted(SWITCHES):
     302        v = switches_info[k]
     303        print("* %s : %s" % (str(k).ljust(20), {None : "Auto", True : "Y", False : "N"}.get(v, v)))
     304
     305    if (enc_ffmpeg_ENABLED or enc_x264_ENABLED or enc_x265_ENABLED or
     306        nvenc_ENABLED or OSX or x11_ENABLED):
     307        assert cython_ENABLED
    151308    #sanity check the flags:
    152     if clipboard_ENABLED and not server_ENABLED and not gtk2_ENABLED and not gtk3_ENABLED:
     309    if clipboard_ENABLED and not server_ENABLED and not gtk3_ENABLED:
    153310        print("Warning: clipboard can only be used with the server or one of the gtk clients!")
    154311        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
    164312    if x11_ENABLED and WIN32:
    165313        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:
     314    if gtk_x11_ENABLED and not x11_ENABLED:
     315        print("Error: you must enable x11 to support gtk_x11!")
     316        exit(1)
     317    if client_ENABLED and not gtk3_ENABLED:
    167318        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)
    174 
     319    if DEFAULT and (not client_ENABLED and not server_ENABLED):
     320        print("Warning: you probably want to build at least the client or server!")
     321    if DEFAULT and not pillow_ENABLED:
     322        print("Warning: including Python Pillow is VERY STRONGLY recommended")
     323    if minify_ENABLED and WIN32:
     324        print("Warning: minifier is not supported on MS Windows")
     325        minify_ENABLED = False
     326    if html5_ENABLED and minify_ENABLED:
     327        r = get_status_output(["uglifyjs", "--version"])[0]
     328        if r==0:
     329            minifier = "uglifyjs"
     330        else:
     331            print("Warning: uglifyjs failed and return %i" % r)
     332            try:
     333                import yuicompressor
     334                assert yuicompressor
     335                minifier = "yuicompressor"
     336            except ImportError as e:
     337                print("Warning: yuicompressor module not found, cannot minify")
     338                minify_ENABLED = False
     339    if DEFAULT and (not enc_x264_ENABLED and not vpx_ENABLED):
     340        print("Warning: no x264 and no vpx support!")
     341        print(" you should enable at least one of these two video encodings")
     342
     343if install is None and WIN32:
     344    install = os.environ.get("MINGW_PREFIX", sys.prefix or "dist")
     345if share_xpra is None:
     346    share_xpra = os.path.join("share", "xpra")
    175347
    176348#*******************************************************************************
    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",
     349# default sets:
     350
     351external_includes = ["hashlib",
    204352                     "ctypes", "platform"]
     353
     354
     355if gtk3_ENABLED or sound_ENABLED:
     356    external_includes += ["gi"]
    205357
    206358external_excludes = [
    207359                    #Tcl/Tk
    208                     "Tkconstants", "Tkinter", "tcl",
     360                    "Tkconstants", "tkinter", "tcl",
    209361                    #PIL bits that import TK:
    210                     "_imagingtk", "PIL._imagingtk", "ImageTk", "PIL.ImageTk", "FixTk",
     362                    "PIL._tkinter_finder", "_imagingtk", "PIL._imagingtk", "ImageTk", "PIL.ImageTk", "FixTk",
    211363                    #formats we don't use:
    212364                    "GimpGradientFile", "GimpPaletteFile", "BmpImagePlugin", "TiffImagePlugin",
    213365                    #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"
     366                    "curses", "pdb",
     367                    "tty",
     368                    "setuptools", "doctest"
     369                    "nose", "pytest", "_pytest", "pluggy", "more_itertools", "apipkg", "py", "funcsigs",
     370                    "Cython", "cython", "pyximport",
     371                    "pydoc_data",
    219372                    ]
    220 
     373if not html5_ENABLED and not crypto_ENABLED:
     374    external_excludes += ["ssl", "_ssl"]
     375if not html5_ENABLED:
     376    external_excludes += ["BaseHTTPServer", "mimetypes"]
     377if not html5_ENABLED and not client_ENABLED:
     378    external_excludes += ["mimetools"]
     379
     380if not client_ENABLED and not server_ENABLED:
     381    excludes += ["PIL"]
     382if not dbus_ENABLED:
     383    excludes += ["dbus"]
    221384
    222385
    223386#because of differences in how we specify packages and modules
    224 #for distutils / py2app and py2exe
     387#for distutils / py2app and cx_freeze
    225388#use the following functions, which should get the right
    226389#data in the global variables "packages", "modules" and "excludes"
     
    253416
    254417def add_modules(*mods):
     418    def add(v):
     419        global modules
     420        if v not in modules:
     421            modules.append(v)
     422    do_add_modules(add, *mods)
     423
     424def do_add_modules(op, *mods):
    255425    """ adds the packages and any .py module found in the packages to the "modules" list
    256426    """
    257427    global modules
    258428    for x in mods:
    259         if x not in modules:
    260             modules.append(x)
     429        #ugly path stripping:
     430        if x.startswith("./"):
     431            x = x[2:]
     432        if x.endswith(".py"):
     433            x = x[:-3]
     434            x = x.replace("/", ".") #.replace("\\", ".")
    261435        pathname = os.path.sep.join(x.split("."))
     436        #is this a file module?
     437        f = "%s.py" % pathname
     438        if os.path.exists(f) and os.path.isfile(f):
     439            op(x)
    262440        if os.path.exists(pathname) and os.path.isdir(pathname):
    263441            #add all file modules found in this directory
    264442            for f in os.listdir(pathname):
    265                 if f.endswith(".py") and f.find("Copy ")<0:
     443                #make sure we only include python files,
     444                #and ignore eclipse copies
     445                if f.endswith(".py") and not f.startswith("Copy ")<0:
    266446                    fname = os.path.join(pathname, f)
    267447                    if os.path.isfile(fname):
    268448                        modname = "%s.%s" % (x, f.replace(".py", ""))
    269                         modules.append(modname)
     449                        op(modname)
    270450
    271451def toggle_packages(enabled, *module_names):
     
    275455        remove_packages(*module_names)
    276456
     457def toggle_modules(enabled, *module_names):
     458    if enabled:
     459        def op(v):
     460            global modules
     461            if v not in modules:
     462                modules.append(v)
     463        do_add_modules(op, *module_names)
     464    else:
     465        remove_packages(*module_names)
     466
     467
    277468#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 
     469if modules_ENABLED:
     470    add_modules("xpra", "xpra.platform", "xpra.net")
     471    add_modules("xpra.scripts.main")
     472
     473
     474def add_data_files(target_dir, files):
     475    #this is overriden below because cx_freeze uses the opposite structure (files first...). sigh.
     476    assert isinstance(target_dir, str)
     477    assert isinstance(files, (list, tuple))
     478    data_files.append((target_dir, files))
     479
     480
     481#for pretty printing of options:
     482def print_option(prefix, k, v):
     483    if isinstance(v, dict):
     484        print("%s* %s:" % (prefix, k))
     485        for kk,vv in v.items():
     486            print_option(" "+prefix, kk, vv)
     487    else:
     488        print("%s* %s=%s" % (prefix, k, v))
    284489
    285490#*******************************************************************************
    286491# Utility methods for building with Cython
     492def cython_version_compare(min_version):
     493    from distutils.version import LooseVersion
     494    assert cython_ENABLED
     495    from Cython.Compiler.Version import version as cython_version
     496    return LooseVersion(cython_version) >= LooseVersion(min_version)
     497
    287498def cython_version_check(min_version):
    288     try:
     499    if not cython_version_compare(min_version):
    289500        from Cython.Compiler.Version import version as cython_version
    290     except ImportError, e:
    291         sys.exit("ERROR: Cannot find Cython: %s" % e)
    292     from distutils.version import LooseVersion
    293     if LooseVersion(cython_version) < LooseVersion(".".join([str(x) for x in min_version])):
    294501        sys.exit("ERROR: Your version of Cython is too old to build this package\n"
    295502                 "You have version %s\n"
    296503                 "Please upgrade to Cython %s or better"
    297                  % (cython_version, ".".join([str(part) for part in min_version])))
    298 
    299 def cython_add(extension, min_version=(0, 14, 0)):
     504                 % (cython_version, min_version))
     505
     506def cython_add(extension, min_version="0.20"):
    300507    #gentoo does weird things, calls --no-compile with build *and* install
    301508    #then expects to find the cython modules!? ie:
    302     #python2.7 setup.py build -b build-2.7 install --no-compile --root=/var/tmp/portage/x11-wm/xpra-0.7.0/temp/images/2.7
     509    #python2.7 setup.py build -b build-2.7 install --no-compile \
     510    #    --root=/var/tmp/portage/x11-wm/xpra-0.7.0/temp/images/2.7
    303511    if "--no-compile" in sys.argv and not ("build" in sys.argv and "install" in sys.argv):
    304512        return
    305     global ext_modules, cmdclass
     513    assert cython_ENABLED, "cython compilation is disabled"
    306514    cython_version_check(min_version)
    307515    from Cython.Distutils import build_ext
    308516    ext_modules.append(extension)
    309     cmdclass = {'build_ext': build_ext}
     517    global cmdclass
     518    cmdclass['build_ext'] = build_ext
     519
     520def insert_into_keywords(kw, key, *args):
     521    values = kw.setdefault(key, [])
     522    for arg in args:
     523        values.insert(0, arg)
    310524
    311525def add_to_keywords(kw, key, *args):
     
    319533
    320534
     535def checkdirs(*dirs):
     536    for d in dirs:
     537        if not os.path.exists(d) or not os.path.isdir(d):
     538            raise Exception("cannot find a directory which is required for building: '%s'" % d)
     539
    321540PYGTK_PACKAGES = ["pygobject-2.0", "pygtk-2.0"]
    322541
     
    324543def get_gcc_version():
    325544    global GCC_VERSION
    326     if len(GCC_VERSION)==0:
    327         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:
     545    if not GCC_VERSION:
     546        cc = os.environ.get("CC", "gcc")
     547        r, _, err = get_status_output([cc]+["-v"])
     548        if r==0:
    332549            V_LINE = "gcc version "
    333             for line in output.decode("utf8").splitlines():
     550            for line in err.splitlines():
    334551                if line.startswith(V_LINE):
    335552                    v_str = line[len(V_LINE):].split(" ")[0]
     
    337554                        try:
    338555                            GCC_VERSION.append(int(p))
    339                         except:
     556                        except ValueError:
    340557                            break
    341558                    print("found gcc version: %s" % ".".join([str(x) for x in GCC_VERSION]))
     
    343560    return GCC_VERSION
    344561
    345 def make_constants_pxi(constants_path, pxi_path):
    346     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):
    384     base = os.path.join(os.getcwd(), *paths)
    385     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"
    394     if reason:
    395         if verbose_ENABLED:
    396             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
     562
     563def should_rebuild(src_file, bin_file):
     564    if not os.path.exists(bin_file):
     565        return "no file"
     566    if rebuild_ENABLED:
     567        if os.path.getctime(bin_file)<os.path.getctime(src_file):
     568            return "binary file out of date"
     569        if os.path.getctime(bin_file)<os.path.getctime(__file__):
     570            return "newer build file"
     571    return None
     572
    414573
    415574# 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 
     575def exec_pkgconfig(*pkgs_options, **ekw):
    423576    kw = dict(ekw)
    424     if len(pkgs_options)>0:
     577    optimize = kw.pop("optimize", None)
     578    if optimize and not debug_ENABLED:
     579        if isinstance(optimize, bool):
     580            optimize = int(optimize)*3
     581        add_to_keywords(kw, 'extra_compile_args', "-O%i" % optimize)
     582    ignored_flags = kw.pop("ignored_flags", [])
     583    ignored_tokens = kw.pop("ignored_tokens", [])
     584
     585    #for distros that don't patch distutils,
     586    #we have to add the python cflags:
     587    if not (is_Fedora() or is_Debian() or is_CentOS() or is_RedHat()):
     588        import shlex
     589        import sysconfig
     590        for cflag in shlex.split(sysconfig.get_config_var('CFLAGS') or ''):
     591            add_to_keywords(kw, 'extra_compile_args', cflag)
     592
     593    def add_tokens(s, extra="extra_link_args", extra_map={"-W" : "extra_compile_args"}):
     594        if not s:
     595            return
     596        flag_map = {'-I': 'include_dirs',
     597                    '-L': 'library_dirs',
     598                    '-l': 'libraries'}
     599        for token in s.split():
     600            if token in ignored_tokens:
     601                pass
     602            elif token[:2] in ignored_flags:
     603                pass
     604            elif token[:2] in flag_map:
     605                if len(token)>2:
     606                    add_to_keywords(kw, flag_map.get(token[:2]), token[2:])
     607                else:
     608                    print("Warning: invalid token '%s'" % token)
     609            else:
     610                extra_name = extra_map.get(token, extra)
     611                add_to_keywords(kw, extra_name, token)
     612
     613    if pkgs_options:
    425614        package_names = []
    426615        #find out which package name to use from potentially many options
     
    429618            #for this package options, find the ones that work
    430619            valid_option = None
    431             if type(package_options)==str:
     620            if isinstance(package_options, str):
    432621                options = [package_options]     #got given just one string
    433                 if not package_options.startswith("lib"):
    434                     options.append("lib%s" % package_options)
    435622            else:
    436                 assert type(package_options)==list
     623                assert isinstance(package_options, list)
    437624                options = package_options       #got given a list of options
    438625            for option in options:
    439626                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:
     627                r = get_status_output(cmd)[0]
     628                if r==0:
    443629                    valid_option = option
    444630                    break
    445631            if not valid_option:
    446                 sys.exit("ERROR: cannot find a valid pkg-config package for %s" % (options,))
     632                raise Exception("ERROR: cannot find a valid pkg-config entry for %s using PKG_CONFIG_PATH=%s" %
     633                                (" or ".join(options), os.environ.get("PKG_CONFIG_PATH", "(empty)")))
    447634            package_names.append(valid_option)
    448635        if verbose_ENABLED and list(pkgs_options)!=list(package_names):
    449             print("pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
    450         flag_map = {'-I': 'include_dirs',
    451                     '-L': 'library_dirs',
    452                     '-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))
     636            print("exec_pkgconfig(%s,%s) using package names=%s" % (pkgs_options, ekw, package_names))
     637        pkg_config_cmd = ["pkg-config", "--libs", "--cflags", "%s" % (" ".join(package_names),)]
     638        r, pkg_config_out, err = get_status_output(pkg_config_cmd)
     639        if r!=0:
     640            sys.exit("ERROR: call to '%s' failed (err=%s)" % (" ".join(cmd), err))
     641        add_tokens(pkg_config_out)
    468642    if warn_ENABLED:
    469643        add_to_keywords(kw, 'extra_compile_args', "-Wall")
    470644        add_to_keywords(kw, 'extra_link_args', "-Wall")
    471645    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"
     646        if os.environ.get("CC", "").find("clang")>=0:
     647            #clang emits too many warnings with cython code,
     648            #so we can't enable Werror without turning off some warnings:
     649            #this list of flags should allow clang to build the whole source tree,
     650            #as of Cython 0.26 + clang 4.0. Other version combinations may require
     651            #(un)commenting other switches.
     652            eifd = ["-Werror",
     653                    #"-Wno-unneeded-internal-declaration",
     654                    #"-Wno-unknown-attributes",
     655                    #"-Wno-unused-function",
     656                    #"-Wno-self-assign",
     657                    #"-Wno-sometimes-uninitialized",
     658                    #cython adds rpath to the compilation command??
     659                    #and the "-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1" is also ignored by clang:
     660                    "-Wno-deprecated-register",
     661                    "-Wno-unused-command-line-argument",
     662                    ]
     663        elif get_gcc_version()>=[4, 4]:
     664            eifd = ["-Werror"]
     665            if NETBSD:
     666                #see: http://trac.cython.org/ticket/395
     667                eifd += ["-fno-strict-aliasing"]
     668            elif FREEBSD:
     669                eifd += ["-Wno-error=unused-function"]
    475670        else:
    476             eifd = "-Werror-implicit-function-declaration"
    477         add_to_keywords(kw, 'extra_compile_args', eifd)
     671            #older versions of OSX ship an old gcc,
     672            #not much we can do with this:
     673            eifd = []
     674        for eif in eifd:
     675            add_to_keywords(kw, 'extra_compile_args', eif)
     676    if sys.version_info>=(3,7):
     677        #we'll switch to the "new" buffer interface eventually
     678        #until then, silence those deprecation warnings:
     679        add_to_keywords(kw, 'extra_compile_args', "-Wno-error=deprecated-declarations")
    478680    if PIC_ENABLED:
    479681        add_to_keywords(kw, 'extra_compile_args', "-fPIC")
     
    481683        add_to_keywords(kw, 'extra_compile_args', '-g')
    482684        add_to_keywords(kw, 'extra_compile_args', '-ggdb')
    483         kw['cython_gdb'] = True
    484         if get_gcc_version()>=4.8:
     685        if get_gcc_version()>=[4, 8] and not WIN32:
    485686            add_to_keywords(kw, 'extra_compile_args', '-fsanitize=address')
    486687            add_to_keywords(kw, 'extra_link_args', '-fsanitize=address')
     688    if rpath and kw.get("libraries"):
     689        insert_into_keywords(kw, "library_dirs", rpath)
     690        insert_into_keywords(kw, "extra_link_args", "-Wl,-rpath=%s" % rpath)
     691    add_tokens(os.environ.get("CFLAGS"), "extra_compile_args", {})
     692    add_tokens(os.environ.get("LDFLAGS"), "extra_link_args", {})
    487693    #add_to_keywords(kw, 'include_dirs', '.')
    488694    if verbose_ENABLED:
    489         print("pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
     695        print("exec_pkgconfig(%s,%s)=%s" % (pkgs_options, ekw, kw))
    490696    return kw
     697pkgconfig = exec_pkgconfig
    491698
    492699
    493700#*******************************************************************************
    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()
     701
     702
     703def get_base_conf_dir(install_dir, stripbuildroot=True):
     704    #in some cases we want to strip the buildroot (to generate paths in the config file)
     705    #but in other cases we want the buildroot path (when writing out the config files)
     706    #and in some cases, we don't have the install_dir specified (called from detect_xorg_setup, and that's fine too)
     707    #this is a bit hackish, but I can't think of a better way of detecting it
     708    #(ie: "$HOME/rpmbuild/BUILDROOT/xpra-0.15.0-0.fc21.x86_64/usr")
     709    dirs = (install_dir or sys.prefix).split(os.path.sep)
     710    if install_dir and stripbuildroot:
     711        pkgdir = os.environ.get("pkgdir")
     712        if "debian" in dirs and "tmp" in dirs:
     713            #ugly fix for stripping the debian tmp dir:
     714            #ie: "???/tmp/???/tags/v0.15.x/src/debian/tmp/" -> ""
     715            while "tmp" in dirs:
     716                dirs = dirs[dirs.index("tmp")+1:]
     717        elif "debian" in dirs:
     718            #same for recent debian versions:
     719            #ie: "xpra-2.0.2/debian/xpra/usr" -> "usr"
     720            i = dirs.index("debian")
     721            while i>=0 and len(dirs)>i+1:
     722                if dirs[i+1] == "xpra":
     723                    dirs = dirs[i+2:]
     724                i = dirs.index("debian")
     725        elif "BUILDROOT" in dirs:
     726            #strip rpm style build root:
     727            #[$HOME, "rpmbuild", "BUILDROOT", "xpra-$VERSION"] -> []
     728            dirs = dirs[dirs.index("BUILDROOT")+2:]
     729        elif "pkg" in dirs:
     730            #archlinux
     731            #ie: "/build/xpra/pkg/xpra/etc" -> "etc"
     732            i = dirs.index("pkg")
     733            while i>=0 and len(dirs)>i+1:
     734                if dirs[i+1] == "xpra":
     735                    dirs = dirs[i+2:]
     736                i = dirs.index("pkg")
     737        elif pkgdir and install_dir.startswith(pkgdir):
     738            #arch build dir:
     739            dirs = install_dir.lstrip(pkgdir).split(os.path.sep)
     740        elif "usr" in dirs:
     741            #ie: ["some", "path", "to", "usr"] -> ["usr"]
     742            #assume "/usr" or "/usr/local" is the build root
     743            while "usr" in dirs[1:]:
     744                dirs = dirs[dirs[1:].index("usr")+1:]
     745        elif "image" in dirs:
     746            # Gentoo's "${PORTAGE_TMPDIR}/portage/${CATEGORY}/${PF}/image/_python2.7" -> ""
     747            while "image" in dirs:
     748                dirs = dirs[dirs.index("image")+2:]
     749    #now deal with the fact that "/etc" is used for the "/usr" prefix
     750    #but "/usr/local/etc" is used for the "/usr/local" prefix..
     751    if dirs and dirs[-1]=="usr":
     752        dirs = dirs[:-1]
     753    #is this an absolute path?
     754    if not dirs or dirs[0]=="usr" or (install_dir or sys.prefix).startswith(os.path.sep):
     755        #ie: ["/", "usr"] or ["/", "usr", "local"]
     756        dirs.insert(0, os.path.sep)
     757    return dirs
     758
     759def get_conf_dir(install_dir, stripbuildroot=True):
     760    dirs = get_base_conf_dir(install_dir, stripbuildroot)
     761    dirs.append("etc")
     762    dirs.append("xpra")
     763    return os.path.join(*dirs)
     764
     765def detect_xorg_setup(install_dir=None):
     766    from xpra.scripts import config
     767    config.debug = config.warn
     768    conf_dir = get_conf_dir(install_dir)
     769    return config.detect_xvfb_command(conf_dir, None, Xdummy_ENABLED, Xdummy_wrapper_ENABLED)
     770
     771def build_xpra_conf(install_dir):
     772    #generates an actual config file from the template
     773    xvfb_command = detect_xorg_setup(install_dir)
     774    fake_xinerama = "no"
     775    if POSIX and not OSX and not (is_Debian() or is_Ubuntu()):
     776        from xpra.x11.fakeXinerama import find_libfakeXinerama
     777        fake_xinerama = find_libfakeXinerama() or "auto"
     778    from xpra.platform.features import DEFAULT_ENV
     779    def bstr(b):
     780        if b is None:
     781            return "auto"
     782        return "yes" if int(b) else "no"
     783    start_env = "\n".join("start-env = %s" % x for x in DEFAULT_ENV)
     784    conf_dir = get_conf_dir(install_dir)
     785    from xpra.platform.features import DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS
     786    from xpra.platform.paths import get_socket_dirs
     787    from xpra.scripts.config import (
     788        xvfb_cmd_str,
     789        get_default_key_shortcuts, get_default_systemd_run, get_default_pulseaudio_command,
     790        DEFAULT_POSTSCRIPT_PRINTER, DEFAULT_PULSEAUDIO,
     791        )
     792    #remove build paths and user specific paths with UID ("/run/user/UID/Xpra"):
     793    socket_dirs = get_socket_dirs()
     794    if WIN32:
     795        bind = "Main"
    533796    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()
     797        if os.getuid()>0:
     798            #remove any paths containing the uid,
     799            #osx uses /var/tmp/$UID-Xpra,
     800            #but this should not be included in the default config for all users!
     801            #(the buildbot's uid!)
     802            socket_dirs = [x for x in socket_dirs if x.find(str(os.getuid()))<0]
     803        bind = "auto"
     804    #FIXME: we should probably get these values from the default config instead
     805    pdf, postscript = "", ""
     806    if POSIX and printing_ENABLED:
     807        try:
     808            if "/usr/sbin" not in sys.path:
     809                sys.path.append("/usr/sbin")
     810            from xpra.platform.pycups_printing import get_printer_definition
     811            print("probing cups printer definitions")
     812            pdf = get_printer_definition("pdf")
     813            postscript = get_printer_definition("postscript") or DEFAULT_POSTSCRIPT_PRINTER
     814            print("pdf=%s, postscript=%s" % (pdf, postscript))
     815        except Exception as e:
     816            print("could not probe for pdf/postscript printers: %s" % e)
     817    def pretty_cmd(cmd):
     818        return " ".join(cmd)
     819    #OSX doesn't have webcam support yet (no opencv builds on 10.5.x)
     820    webcam = webcam_ENABLED and not OSX
     821    #no python-avahi on RH / CentOS, need dbus module on *nix:
     822    mdns = mdns_ENABLED and (OSX or WIN32 or (not is_RH() and dbus_ENABLED))
     823    SUBS = {
     824            'xvfb_command'          : xvfb_cmd_str(xvfb_command),
     825            'fake_xinerama'         : fake_xinerama,
     826            'ssh_command'           : "auto",
     827            'key_shortcuts'         : "".join(("key-shortcut = %s\n" % x) for x in get_default_key_shortcuts()),
     828            'remote_logging'        : "both",
     829            'start_env'             : start_env,
     830            'pulseaudio'            : bstr(DEFAULT_PULSEAUDIO),
     831            'pulseaudio_command'    : pretty_cmd(get_default_pulseaudio_command()),
     832            'pulseaudio_configure_commands' : "\n".join(("pulseaudio-configure-commands = %s" % pretty_cmd(x)) for x in DEFAULT_PULSEAUDIO_CONFIGURE_COMMANDS),
     833            'conf_dir'              : conf_dir,
     834            'bind'                  : bind,
     835            'ssl_cert'              : ssl_cert or "",
     836            'ssl_key'               : ssl_key or "",
     837            'systemd_run'           : get_default_systemd_run(),
     838            'socket_dirs'           : "".join(("socket-dirs = %s\n" % x) for x in socket_dirs),
     839            'log_dir'               : "auto",
     840            'mdns'                  : bstr(mdns),
     841            'notifications'         : bstr(OSX or WIN32 or dbus_ENABLED),
     842            'dbus_proxy'            : bstr(not OSX and not WIN32 and dbus_ENABLED),
     843            'pdf_printer'           : pdf,
     844            'postscript_printer'    : postscript,
     845            'webcam'                : ["no", "auto"][webcam],
     846            'mousewheel'            : "on",
     847            'printing'              : bstr(printing_ENABLED),
     848            'dbus_control'          : bstr(dbus_ENABLED),
     849            'mmap'                  : bstr(True),
     850            'opengl'                : "probe",
     851            }
     852    def convert_templates(subdirs):
     853        dirname = os.path.join(*(["etc", "xpra"] + subdirs))
     854        #get conf dir for install, without stripping the build root
     855        target_dir = os.path.join(get_conf_dir(install_dir, stripbuildroot=False), *subdirs)
     856        print("convert_templates(%s) dirname=%s, target_dir=%s" % (subdirs, dirname, target_dir))
     857        if not os.path.exists(target_dir):
     858            try:
     859                os.makedirs(target_dir)
     860            except Exception as e:
     861                print("cannot create target dir '%s': %s" % (target_dir, e))
     862        for f in sorted(os.listdir(dirname)):
     863            if f.endswith("osx.conf.in") and not OSX:
     864                continue
     865            filename = os.path.join(dirname, f)
     866            if os.path.isdir(filename):
     867                convert_templates(subdirs+[f])
     868                continue
     869            if not f.endswith(".in"):
     870                continue
     871            with open(filename, "r") as f_in:
     872                template  = f_in.read()
     873            target_file = os.path.join(target_dir, f[:-len(".in")])
     874            print("generating %s from %s" % (target_file, f))
     875            with open(target_file, "w") as f_out:
     876                config_data = template % SUBS
     877                f_out.write(config_data)
     878    convert_templates([])
    576879
    577880
    578881#*******************************************************************************
    579 if 'clean' in sys.argv or 'sdist' in sys.argv:
     882def clean():
    580883    #clean and sdist don't actually use cython,
    581884    #so skip this (and avoid errors)
    582     def pkgconfig(*pkgs_options, **ekw):
    583         return {}
     885    global pkgconfig
     886    pkgconfig = no_pkgconfig
    584887    #always include everything in this case:
    585888    add_packages("xpra")
    586889    #ensure we remove the files we generate:
    587890    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",
    592                    "xpra/x11/bindings/constants.pxi",
     891                   "xpra/build_info.py",
     892                   "xpra/monotonic_time.c",
     893                   "xpra/gtk_common/gtk3/gdk_atoms.c",
     894                   "xpra/gtk_common/gtk3/gdk_bindings.c",
     895                   "xpra/x11/gtk3/gdk_bindings.c",
     896                   "xpra/x11/gtk3/gdk_display_source.c",
    593897                   "xpra/x11/bindings/wait_for_x_server.c",
    594898                   "xpra/x11/bindings/keyboard_bindings.c",
     
    597901                   "xpra/x11/bindings/randr_bindings.c",
    598902                   "xpra/x11/bindings/core_bindings.c",
     903                   "xpra/x11/bindings/posix_display_source.c",
    599904                   "xpra/x11/bindings/ximage.c",
    600                    "xpra/net/rencode/rencode.c",
     905                   "xpra/x11/bindings/xi2_bindings.c",
     906                   "xpra/platform/win32/propsys.cpp",
     907                   "xpra/platform/darwin/gdk_bindings.c",
     908                   "xpra/platform/xposix/sd_listen.c",
     909                   "xpra/platform/xposix/netdev_query.c",
     910                   "xpra/net/bencode/cython_bencode.c",
     911                   "xpra/net/vsock.c",
     912                   "xpra/buffers/membuf.c",
    601913                   "xpra/codecs/vpx/encoder.c",
    602914                   "xpra/codecs/vpx/decoder.c",
    603915                   "xpra/codecs/nvenc/encoder.c",
    604                    "xpra/codecs/nvenc/constants.pxi",
     916                   "xpra/codecs/nvfbc/fbc_capture_linux.cpp",
     917                   "xpra/codecs/nvfbc/fbc_capture_win.cpp",
    605918                   "xpra/codecs/enc_x264/encoder.c",
    606919                   "xpra/codecs/enc_x265/encoder.c",
    607                    "xpra/codecs/webp/encode.c",
    608                    "xpra/codecs/dec_avcodec/decoder.c",
    609                    "xpra/codecs/dec_avcodec/constants.pxi",
     920                   "xpra/codecs/jpeg/encoder.c",
     921                   "xpra/codecs/jpeg/decoder.c",
     922                   "xpra/codecs/enc_ffmpeg/encoder.c",
     923                   "xpra/codecs/v4l2/pusher.c",
     924                   "xpra/codecs/v4l2/constants.pxi",
     925                   "xpra/codecs/libav_common/av_log.c",
     926                   "xpra/codecs/webp/encoder.c",
     927                   "xpra/codecs/webp/decoder.c",
    610928                   "xpra/codecs/dec_avcodec2/decoder.c",
     929                   "xpra/codecs/csc_libyuv/colorspace_converter.cpp",
    611930                   "xpra/codecs/csc_swscale/colorspace_converter.c",
    612                    "xpra/codecs/csc_swscale/constants.pxi",
    613                    "xpra/codecs/csc_cython/colorspace_converter.c",
    614931                   "xpra/codecs/xor/cyxor.c",
    615932                   "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")
     933                   "xpra/codecs/nvapi_version.c",
     934                   "xpra/gtk_common/gdk_atoms.c",
     935                   "xpra/client/gtk3/cairo_workaround.c",
     936                   "xpra/server/cystats.c",
     937                   "xpra/rectangle.c",
     938                   "xpra/server/window/motion.c",
     939                   "xpra/server/pam.c",
     940                   "etc/xpra/xpra.conf",
     941                   #special case for the generated xpra conf files in build (see #891):
     942                   "build/etc/xpra/xpra.conf"] + glob.glob("build/etc/xpra/conf.d/*.conf")
     943    if cuda_rebuild_ENABLED:
     944        CLEAN_FILES += [
     945            "xpra/codecs/cuda_common/ARGB_to_NV12.fatbin",
     946            "xpra/codecs/cuda_common/ARGB_to_YUV444.fatbin",
     947            "xpra/codecs/cuda_common/BGRA_to_NV12.fatbin",
     948            "xpra/codecs/cuda_common/BGRA_to_YUV444.fatbin",
     949            ]
     950    for x in CLEAN_FILES:
     951        p, ext = os.path.splitext(x)
     952        if ext in (".c", ".cpp", ".pxi"):
     953            #clean the Cython annotated html files:
     954            CLEAN_FILES.append(p+".html")
     955            if WIN32:
     956                #on win32, the build creates ".pyd" files, clean those too:
     957                CLEAN_FILES.append(p+".pyd")
     958                #when building with python3, we need to clean files named like:
     959                #"xpra/codecs/csc_libyuv/colorspace_converter-cpython-36m.dll"
     960                filename = os.path.join(os.getcwd(), p.replace("/", os.path.sep)+"*.dll")
     961                CLEAN_FILES += glob.glob(filename)
    623962    if 'clean' in sys.argv:
    624963        CLEAN_FILES.append("xpra/build_info.py")
     
    630969            os.unlink(filename)
    631970
    632 from add_build_info import record_build_info, record_src_info, has_src_info
     971if 'clean' in sys.argv or 'sdist' in sys.argv:
     972    clean()
     973
     974from add_build_info import record_build_info, BUILD_INFO_FILE, record_src_info, SRC_INFO_FILE, has_src_info
    633975
    634976if "clean" not in sys.argv:
    635977    # Add build info to build_info.py file:
    636978    record_build_info()
     979    if modules_ENABLED:
     980        # ensure it is included in the module list if it didn't exist before
     981        add_modules(BUILD_INFO_FILE)
    637982
    638983if "sdist" in sys.argv:
    639984    record_src_info()
    640985
    641 if "install" in sys.argv:
     986if "install" in sys.argv or "build" in sys.argv:
    642987    #if installing from source tree rather than
    643988    #from a source snapshot, we may not have a "src_info" file
    644989    #so create one:
    645     if not has_src_info():
     990    if not has_src_info() and modules_ENABLED:
    646991        record_src_info()
     992        # ensure it is now included in the module list
     993        add_modules(SRC_INFO_FILE)
    647994
    648995
     
    6591006        for f in files:
    6601007            dirname = root[len(srcdir)+1:]
    661             filename = os.path.join(root, f)
    662             m.setdefault(dirname, []).append(filename)
     1008            m.setdefault(dirname, []).append(os.path.join(root, f))
    6631009    return m
     1010
     1011
     1012def install_html5(install_dir="www"):
     1013    from setup_html5 import install_html5 as do_install_html5
     1014    do_install_html5(install_dir, minifier, html5_gzip_ENABLED, html5_brotli_ENABLED, verbose_ENABLED)
     1015
    6641016
    6651017#*******************************************************************************
    6661018if 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"]
    882     add_packages("xpra.platform.win32")
     1019    MINGW_PREFIX = os.environ.get("MINGW_PREFIX")
     1020    assert MINGW_PREFIX, "you must run this build from a MINGW environment"
     1021    if modules_ENABLED:
     1022        add_packages("xpra.platform.win32", "xpra.platform.win32.namedpipes")
    8831023    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"]
     1024
     1025    #this is where the win32 gi installer will put things:
     1026    gnome_include_path = os.environ.get("MINGW_PREFIX")
     1027
     1028    #only add the cx_freeze specific options
     1029    #only if we are packaging:
     1030    if "install_exe" in sys.argv:
     1031        #with cx_freeze, we don't use py_modules
     1032        del setup_options["py_modules"]
     1033        from cx_Freeze import setup, Executable     #@UnresolvedImport @Reimport
     1034        if not hasattr(sys, "base_prefix"):
     1035            #workaround for broken sqlite hook with python 2.7, see:
     1036            #https://github.com/anthony-tuininga/cx_Freeze/pull/272
     1037            sys.base_prefix = sys.prefix
     1038
     1039        #cx_freeze doesn't use "data_files"...
     1040        del setup_options["data_files"]
     1041        #it wants source files first, then where they are placed...
     1042        #one item at a time (no lists)
     1043        #all in its own structure called "include_files" instead of "data_files"...
     1044        def add_data_files(target_dir, files):
     1045            if verbose_ENABLED:
     1046                print("add_data_files(%s, %s)" % (target_dir, files))
     1047            assert isinstance(target_dir, str)
     1048            assert isinstance(files, (list, tuple))
     1049            for f in files:
     1050                target_file = os.path.join(target_dir, os.path.basename(f))
     1051                data_files.append((f, target_file))
     1052
     1053        #pass a potentially nested dictionary representing the tree
     1054        #of files and directories we do want to include
     1055        #relative to gnome_include_path
     1056        def add_dir(base, defs):
     1057            if verbose_ENABLED:
     1058                print("add_dir(%s, %s)" % (base, defs))
     1059            if isinstance(defs, (list, tuple)):
     1060                for sub in defs:
     1061                    if isinstance(sub, dict):
     1062                        add_dir(base, sub)
     1063                    else:
     1064                        assert isinstance(sub, str)
     1065                        filename = os.path.join(gnome_include_path, base, sub)
     1066                        if os.path.exists(filename):
     1067                            add_data_files(base, [filename])
     1068                        else:
     1069                            print("Warning: missing '%s'" % filename)
     1070            else:
     1071                assert isinstance(defs, dict)
     1072                for d, sub in defs.items():
     1073                    assert isinstance(sub, (dict, list, tuple))
     1074                    #recurse down:
     1075                    add_dir(os.path.join(base, d), sub)
     1076
     1077        def add_gi_typelib(*libs):
     1078            if verbose_ENABLED:
     1079                print("add_gi_typelib(%s)" % str(libs))
     1080            add_dir('lib',      {"girepository-1.0":    ["%s.typelib" % x for x in libs]})
     1081        def add_gi_gir(*libs):
     1082            if verbose_ENABLED:
     1083                print("add_gi_gir(%s)" % str(libs))
     1084            add_dir('share',    {"gir-1.0" :            ["%s.gir" % x for x in libs]})
     1085        #convenience method for adding GI libs and "typelib" and "gir":
     1086        def add_gi(*libs):
     1087            add_gi_typelib(*libs)
     1088            add_gi_gir(*libs)
     1089
     1090        def add_DLLs(*dll_names):
     1091            try:
     1092                do_add_DLLs(*dll_names)
     1093            except Exception as e:
     1094                print("Error: failed to add DLLs: %s" % (dll_names, ))
     1095                print(" %s" % e)
     1096                sys.exit(1)
     1097
     1098        def do_add_DLLs(*dll_names):
     1099            dll_names = list(dll_names)
     1100            dll_files = []
     1101            import re
     1102            version_re = re.compile(r"-[0-9\.-]+$")
     1103            dirs = os.environ.get("PATH").split(os.path.pathsep)
     1104            if os.path.exists(gnome_include_path):
     1105                dirs.insert(0, gnome_include_path)
     1106            if verbose_ENABLED:
     1107                print("add_DLLs: looking for %s in %s" % (dll_names, dirs))
     1108            for d in dirs:
     1109                if not os.path.exists(d):
     1110                    continue
     1111                for x in os.listdir(d):
     1112                    dll_path = os.path.join(d, x)
     1113                    x = x.lower()
     1114                    if os.path.isdir(dll_path) or not x.startswith("lib") or not x.endswith(".dll"):
     1115                        continue
     1116                    #strip "lib" and ".dll": "libatk-1.0-0.dll" -> "atk-1.0-0"
     1117                    nameversion = x[3:-4]
     1118                    if verbose_ENABLED:
     1119                        print("checking %s: %s" % (x, nameversion))
     1120                    m = version_re.search(nameversion)          #look for version part of filename
     1121                    if m:
     1122                        dll_version = m.group(0)                #found it, ie: "-1.0-0"
     1123                        dll_name = nameversion[:-len(dll_version)]  #ie: "atk"
     1124                        dll_version = dll_version.lstrip("-")   #ie: "1.0-0"
     1125                    else:
     1126                        dll_version = ""                        #no version
     1127                        dll_name = nameversion                  #ie: "libzzz.dll" -> "zzz"
     1128                    if dll_name in dll_names:
     1129                        #this DLL is on our list
     1130                        print("%s %s %s" % (dll_name.ljust(22), dll_version.ljust(10), x))
     1131                        dll_files.append(dll_path)
     1132                        dll_names.remove(dll_name)
     1133            if dll_names:
     1134                print("some DLLs could not be found:")
     1135                for x in dll_names:
     1136                    print(" - lib%s*.dll" % x)
     1137            add_data_files("", dll_files)
     1138
     1139        #list of DLLs we want to include, without the "lib" prefix, or the version and extension
     1140        #(ie: "libatk-1.0-0.dll" -> "atk")
     1141        if sound_ENABLED or gtk3_ENABLED:
     1142            add_DLLs('gio', 'girepository', 'glib',
     1143                     'gnutls', 'gobject', 'gthread',
     1144                     'orc', 'stdc++',
     1145                     'winpthread',
     1146                     )
     1147        if gtk3_ENABLED:
     1148            add_DLLs('atk',
     1149                     #'dbus', 'dbus-glib',
     1150                     'gdk', 'gdk_pixbuf', 'gtk',
     1151                     'cairo-gobject', 'pango', 'pangocairo', 'pangoft2', 'pangowin32',
     1152                     'harfbuzz', 'harfbuzz-gobject',
     1153                     'jasper', 'epoxy',
     1154                     'intl',
     1155                     'p11-kit',
     1156                     'jpeg', 'png16', 'rsvg', 'webp', 'tiff')
     1157
     1158        if gtk3_ENABLED:
     1159            add_dir('etc', ["fonts", "gtk-3.0", "pkcs11"])     #add "dbus-1"?
     1160            add_dir('lib', ["gdk-pixbuf-2.0", "gtk-3.0",
     1161                            "p11-kit", "pkcs11"])
     1162            add_dir('share', ["fontconfig", "fonts", "glib-2.0",        #add "dbus-1"?
     1163                              "p11-kit", "xml",
     1164                              {"locale" : ["en"]},
     1165                              {"themes" : ["Default"]}
     1166                             ])
     1167            ICONS = ["24x24", "48x48", "scalable", "cursors", "index.theme"]
     1168            for theme in ("Adwaita", ): #"hicolor"
     1169                add_dir("share/icons/"+theme, ICONS)
     1170            add_dir("share/themes/Windows-10", [
     1171                "CREDITS", "LICENSE.md", "README.md",
     1172                "gtk-3.20", "index.theme"])
     1173        if gtk3_ENABLED or sound_ENABLED:
     1174            #causes warnings:
     1175            #add_dir('lib', ["gio"])
     1176            packages.append("gi")
     1177            add_gi_typelib("Gio-2.0", "GIRepository-2.0", "Glib-2.0", "GModule-2.0",
     1178                   "GObject-2.0")
     1179        if gtk3_ENABLED:
     1180            add_gi("Atk-1.0",
     1181                   "Notify-0.7",
     1182                   "GDesktopEnums-3.0", "Soup-2.4",
     1183                   "GdkPixbuf-2.0", "Gdk-3.0", "Gtk-3.0",
     1184                   "HarfBuzz-0.0",
     1185                   "Pango-1.0", "PangoCairo-1.0", "PangoFT2-1.0",
     1186                   "Rsvg-2.0",
     1187                   )
     1188            add_gi_typelib("cairo-1.0",
     1189                           "fontconfig-2.0", "freetype2-2.0",
     1190                           "libproxy-1.0", "libxml2-2.0")
     1191            #we no longer support GtkGL:
     1192            #if opengl_ENABLED:
     1193            #    add_gi("GdkGLExt-3.0", "GtkGLExt-3.0", "GL-1.0")
     1194            add_DLLs('curl', 'soup')
     1195
     1196        if client_ENABLED:
     1197            #svg pixbuf loader:
     1198            add_DLLs("rsvg", "croco")
     1199
     1200        if sound_ENABLED:
     1201            add_dir("share", ["gst-plugins-base", "gstreamer-1.0"])
     1202            add_gi("Gst-1.0", "GstAllocators-1.0", "GstAudio-1.0", "GstBase-1.0",
     1203                   "GstTag-1.0")
     1204            add_DLLs('gstreamer', 'orc-test')
     1205            for p in ("app", "audio", "base", "codecparsers", "fft", "net", "video",
     1206                      "pbutils", "riff", "sdp", "rtp", "rtsp", "tag", "uridownloader",
     1207                      #I think 'coreelements' needs those (otherwise we would exclude them):
     1208                      "basecamerabinsrc", "mpegts", "photography",
     1209                      ):
     1210                add_DLLs('gst%s' % p)
     1211            #DLLs needed by the plugins:
     1212            add_DLLs("faac", "faad", "flac", "mpg123")      #"mad" is no longer included?
     1213            #add the gstreamer plugins we need:
     1214            GST_PLUGINS = ("app",
     1215                           "cutter",
     1216                           #muxers:
     1217                           "gdp", "matroska", "ogg", "isomp4",
     1218                           "audioparsers", "audiorate", "audioconvert", "audioresample", "audiotestsrc",
     1219                           "coreelements", "directsound", "directsoundsrc", "wasapi",
     1220                           #codecs:
     1221                           "opus", "opusparse", "flac", "lame", "mpg123", "speex", "faac", "faad",
     1222                           "volume", "vorbis", "wavenc", "wavpack", "wavparse",
     1223                           "autodetect",
     1224                           #no longer available: "mad"
     1225                           #untested: a52dec, voaacenc
     1226                           )
     1227            add_dir(os.path.join("lib", "gstreamer-1.0"), [("libgst%s.dll" % x) for x in GST_PLUGINS])
     1228            #END OF SOUND
     1229
     1230        if server_ENABLED:
     1231            #used by proxy server:
     1232            external_includes += ["multiprocessing", "setproctitle"]
     1233
     1234        external_includes += ["encodings"]
     1235        if client_ENABLED:
     1236            #for parsing "open-command":
     1237            external_includes += ["shlex"]
     1238            #for version check:
     1239            external_includes += [
     1240                                  "ftplib", "fileinput",
     1241                                  ]
     1242            external_includes += ["urllib", "http.cookiejar", "http.client"]
     1243
     1244        if dec_avcodec2_ENABLED:
     1245            #why isn't this one picked up automatically?
     1246            add_DLLs("x265")
     1247
     1248        #hopefully, cx_Freeze will fix this horror:
     1249        #(we shouldn't have to deal with DLL dependencies)
     1250        import site
     1251        lib_python = os.path.dirname(site.getsitepackages()[0])
     1252        lib_dynload_dir = os.path.join(lib_python, "lib-dynload")
     1253        add_data_files('', glob.glob("%s/zlib*dll" % lib_dynload_dir))
     1254        for x in ("io", "codecs", "abc", "_weakrefset", "encodings"):
     1255            add_data_files("lib/", glob.glob("%s/%s*" % (lib_python, x)))
     1256        #ensure that cx_freeze won't automatically grab other versions that may lay on our path:
     1257        os.environ["PATH"] = gnome_include_path+";"+os.environ.get("PATH", "")
     1258        bin_excludes = ["MSVCR90.DLL", "MFC100U.DLL"]
     1259        cx_freeze_options = {
     1260                            "includes"          : external_includes,
     1261                            "packages"          : packages,
     1262                            "include_files"     : data_files,
     1263                            "excludes"          : excludes,
     1264                            "include_msvcr"     : True,
     1265                            "bin_excludes"      : bin_excludes,
     1266                            }
     1267        #cx_Freeze v5 workarounds:
     1268        if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
     1269            add_packages("numpy.core._methods", "numpy.lib.format")
     1270
     1271        setup_options["options"] = {"build_exe" : cx_freeze_options}
     1272        executables = []
     1273        setup_options["executables"] = executables
     1274
     1275        def add_exe(script, icon, base_name, base="Console"):
     1276            executables.append(Executable(
     1277                        script                  = script,
     1278                        initScript              = None,
     1279                        #targetDir               = "dist",
     1280                        icon                    = "icons/%s" % icon,
     1281                        targetName              = "%s.exe" % base_name,
     1282                        base                    = base,
     1283                        ))
     1284
     1285        def add_console_exe(script, icon, base_name):
     1286            add_exe(script, icon, base_name)
     1287        def add_gui_exe(script, icon, base_name):
     1288            add_exe(script, icon, base_name, base="Win32GUI")
     1289        def add_service_exe(script, icon, base_name):
     1290            add_exe(script, icon, base_name, base="Win32Service")
     1291
     1292        #UI applications (detached from shell: no text output if ran from cmd.exe)
     1293        if (client_ENABLED or server_ENABLED) and gtk3_ENABLED:
     1294            add_gui_exe("scripts/xpra",                         "xpra.ico",         "Xpra")
     1295            add_gui_exe("win32/service/shadow_server.py",       "server-notconnected.ico",    "Xpra-Shadow")
     1296            add_gui_exe("scripts/xpra_launcher",                "xpra.ico",         "Xpra-Launcher")
     1297            add_console_exe("scripts/xpra_launcher",            "xpra.ico",         "Xpra-Launcher-Debug")
     1298            add_gui_exe("xpra/gtk_common/gtk_view_keyboard.py", "keyboard.ico",     "GTK_Keyboard_Test")
     1299            add_gui_exe("xpra/scripts/bug_report.py",           "bugs.ico",         "Bug_Report")
     1300            add_gui_exe("xpra/platform/win32/gdi_screen_capture.py", "screenshot.ico", "Screenshot")
     1301        if server_ENABLED:
     1302            add_gui_exe("scripts/auth_dialog",                  "authentication.ico", "Auth_Dialog")
     1303        if mdns_ENABLED and gtk3_ENABLED:
     1304            add_gui_exe("xpra/client/gtk_base/mdns_gui.py",     "mdns.ico",         "Xpra_Browser")
     1305        #Console: provide an Xpra_cmd.exe we can run from the cmd.exe shell
     1306        add_console_exe("scripts/xpra",                     "xpra_txt.ico",     "Xpra_cmd")
     1307        add_console_exe("xpra/scripts/version.py",          "information.ico",  "Version_info")
     1308        add_console_exe("xpra/net/net_util.py",             "network.ico",      "Network_info")
     1309        if gtk3_ENABLED:
     1310            add_console_exe("xpra/scripts/gtk_info.py",         "gtk.ico",          "GTK_info")
     1311            add_console_exe("xpra/gtk_common/keymap.py",        "keymap.ico",       "Keymap_info")
     1312            add_console_exe("xpra/platform/keyboard.py",        "keymap.ico",       "Keyboard_info")
     1313            add_gui_exe("xpra/client/gtk_base/example/tray.py", "xpra.ico",         "SystemTray_Test")
     1314            add_gui_exe("xpra/client/gtk_base/u2f_tool.py",     "authentication.ico", "U2F_Tool")
     1315        if client_ENABLED or server_ENABLED:
     1316            add_console_exe("win32/python_exec.py",             "python.ico",       "Python_exec_cmd")
     1317            add_console_exe("win32/python_execfile.py",         "python.ico",       "Python_execfile_cmd")
     1318            add_console_exe("win32/python_execfile.py",         "python.ico",       "Python_execfile_gui")
     1319            add_console_exe("xpra/scripts/config.py",           "gears.ico",        "Config_info")
     1320        if server_ENABLED:
     1321            add_console_exe("xpra/server/auth/sqlite_auth.py",  "sqlite.ico",        "SQLite_auth_tool")
     1322            add_console_exe("xpra/server/auth/sql_auth.py",     "sql.ico",           "SQL_auth_tool")
     1323            add_console_exe("xpra/server/auth/win32_auth.py",   "authentication.ico", "System-Auth-Test")
     1324            add_console_exe("xpra/server/auth/ldap_auth.py",    "authentication.ico", "LDAP-Auth-Test")
     1325            add_console_exe("xpra/server/auth/ldap3_auth.py",   "authentication.ico", "LDAP3-Auth-Test")
     1326            add_console_exe("win32/service/proxy.py",           "xpra_txt.ico",     "Xpra-Proxy_cmd")
     1327            add_gui_exe("win32/service/proxy.py",               "xpra.ico",         "Xpra-Proxy")
     1328            add_console_exe("xpra/platform/win32/lsa_logon_lib.py", "xpra_txt.ico",     "System-Logon-Test")
     1329        if client_ENABLED:
     1330            add_console_exe("xpra/codecs/loader.py",            "encoding.ico",     "Encoding_info")
     1331            add_console_exe("xpra/platform/paths.py",           "directory.ico",    "Path_info")
     1332            add_console_exe("xpra/platform/features.py",        "features.ico",     "Feature_info")
     1333        if client_ENABLED:
     1334            add_console_exe("xpra/platform/gui.py",             "browse.ico",       "NativeGUI_info")
     1335            add_console_exe("xpra/platform/win32/gui.py",       "loop.ico",         "Events_Test")
     1336        if sound_ENABLED:
     1337            add_console_exe("xpra/sound/gstreamer_util.py",     "gstreamer.ico",    "GStreamer_info")
     1338            add_console_exe("scripts/xpra",                     "speaker.ico",      "Xpra_Audio")
     1339            add_console_exe("xpra/platform/win32/directsound.py", "speaker.ico",      "Audio_Devices")
     1340            #add_console_exe("xpra/sound/src.py",                "microphone.ico",   "Sound_Record")
     1341            #add_console_exe("xpra/sound/sink.py",               "speaker.ico",      "Sound_Play")
     1342        if opengl_ENABLED:
     1343            add_console_exe("xpra/client/gl/gl_check.py",   "opengl.ico",       "OpenGL_check")
     1344        if webcam_ENABLED:
     1345            add_console_exe("xpra/platform/webcam.py",          "webcam.ico",    "Webcam_info")
     1346            add_console_exe("xpra/scripts/show_webcam.py",          "webcam.ico",    "Webcam_Test")
     1347        if printing_ENABLED:
     1348            add_console_exe("xpra/platform/printing.py",        "printer.ico",     "Print")
     1349            add_console_exe("xpra/platform/win32/pdfium.py",    "printer.ico",     "PDFIUM_Print")
     1350            add_DLLs("pdfium")  #libpdfium.dll
     1351        if nvenc_ENABLED:
     1352            add_console_exe("xpra/codecs/nv_util.py",                   "nvidia.ico",   "NVidia_info")
     1353        if nvfbc_ENABLED:
     1354            add_console_exe("xpra/codecs/nvfbc/capture.py",             "nvidia.ico",   "NvFBC_capture")
     1355        if nvfbc_ENABLED or nvenc_ENABLED:
     1356            add_console_exe("xpra/codecs/cuda_common/cuda_context.py",  "cuda.ico",     "CUDA_info")
     1357
     1358        if example_ENABLED:
     1359            add_gui_exe("xpra/client/gtk_base/example/colors.py",               "encoding.ico",     "Colors")
     1360            add_gui_exe("xpra/client/gtk_base/example/colors_gradient.py",      "encoding.ico",     "Colors-Gradient")
     1361            add_gui_exe("xpra/client/gtk_base/example/colors_plain.py",         "encoding.ico",     "Colors-Plain")
     1362            add_gui_exe("xpra/client/gtk_base/example/bell.py",                 "bell.ico",         "Bell")
     1363            add_gui_exe("xpra/client/gtk_base/example/transparent_colors.py",   "transparent.ico",  "Transparent-Colors")
     1364            add_gui_exe("xpra/client/gtk_base/example/transparent_window.py",   "transparent.ico",  "Transparent-Window")
     1365            add_gui_exe("xpra/client/gtk_base/example/fontrendering.py",        "font.ico",         "Font-Rendering")
     1366
     1367    if ("install_exe" in sys.argv) or ("install" in sys.argv):
     1368        #FIXME: how do we figure out what target directory to use?
     1369        print("calling build_xpra_conf in-place")
     1370        #building etc files in-place:
     1371        if data_ENABLED:
     1372            build_xpra_conf(".")
     1373            add_data_files('etc/xpra', glob.glob("etc/xpra/*conf"))
     1374            add_data_files('etc/xpra', glob.glob("etc/xpra/nvenc*.keys"))
     1375            add_data_files('etc/xpra', glob.glob("etc/xpra/nvfbc*.keys"))
     1376            add_data_files('etc/xpra/conf.d', glob.glob("etc/xpra/conf.d/*conf"))
     1377        #build minified html5 client in temporary build dir:
     1378        if "clean" not in sys.argv and html5_ENABLED:
     1379            install_html5(os.path.join(install, "www"), )
     1380            for k,v in glob_recurse("build/www").items():
     1381                if k!="":
     1382                    k = os.sep+k
     1383                add_data_files('www'+k, v)
     1384
     1385    if data_ENABLED:
     1386        add_data_files("",              ["win32/website.url"])
     1387        add_data_files("",              ["win32\\DirectShow.tlb"])
     1388
    9071389    remove_packages(*external_excludes)
     1390    external_includes.append("pyu2f")
     1391    external_includes.append("mmap")
     1392    external_includes.append("comtypes")    #used by webcam and netdev_query
     1393    remove_packages("comtypes.gen")         #this is generated at runtime
     1394                                            #but we still have to remove the empty directory by hand
     1395                                            #afterwards because cx_freeze does weird things (..)
    9081396    remove_packages(#not used on win32:
    909                     "mmap",
    9101397                    #we handle GL separately below:
    9111398                    "OpenGL", "OpenGL_accelerate",
     
    9131400                    "ctypes.macholib")
    9141401
    915     if not cyxor_ENABLED or opengl_ENABLED:
     1402    if webcam_ENABLED and False:
     1403        external_includes.append("cv2")
     1404    else:
     1405        remove_packages("cv2")
     1406
     1407    if opengl_ENABLED or nvenc_ENABLED or nvfbc_ENABLED:
    9161408        #we need numpy for opengl or as a fallback for the Cython xor module
    917         py2exe_includes.append("numpy")
     1409        external_includes.append("numpy")
    9181410    else:
    919         remove_packages("numpy",
    920                         "unittest", "difflib",  #avoid numpy warning (not an error)
     1411        remove_packages("unittest", "difflib",  #avoid numpy warning (not an error)
    9211412                        "pydoc")
    9221413
    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:
     1414    #make sure we don't include the gstreamer 0.10 "pygst" bindings:
     1415    remove_packages("pygst", "gst", "gst.extend")
     1416
     1417    #add subset of PyOpenGL modules (only when installing):
     1418    if opengl_ENABLED and "install_exe" in sys.argv:
    9291419        #for this hack to work, you must add "." to the sys.path
    9301420        #so python can load OpenGL from the install directory
    9311421        #(further complicated by the fact that "." is the "frozen" path...)
    932         import OpenGL, OpenGL_accelerate        #@UnresolvedImport
    933         import shutil
    934         print("*** copy PyOpenGL modules ***")
    935         for module_name, module in {"OpenGL" : OpenGL, "OpenGL_accelerate" : OpenGL_accelerate}.items():
     1422        #but we re-add those two directories to the library.zip as part of the build script
     1423        import OpenGL
     1424        print("*** copying PyOpenGL modules to %s ***" % install)
     1425        glmodules = {
     1426            "OpenGL" : OpenGL,
     1427            }
     1428        try:
     1429            import OpenGL_accelerate        #@UnresolvedImport
     1430        except ImportError as e:
     1431            print("Warning: missing OpenGL_accelerate module")
     1432            print(" %s" % e)
     1433        else:
     1434            glmodules["OpenGL_accelerate"] = OpenGL_accelerate
     1435        for module_name, module in glmodules.items():
    9361436            module_dir = os.path.dirname(module.__file__ )
    9371437            try:
    9381438                shutil.copytree(
    939                     module_dir, os.path.join("dist", module_name),
    940                     ignore = shutil.ignore_patterns("Tk")
     1439                    module_dir, os.path.join(install, "lib", module_name),
     1440                    ignore = shutil.ignore_patterns(
     1441                        "Tk", "AGL", "EGL",
     1442                        "GLX", "GLX.*", "_GLX.*",
     1443                        "GLE", "GLES1", "GLES2", "GLES3",
     1444                        )
    9411445                )
    942             except WindowsError, error:     #@UndefinedVariable
    943                 if not "already exists" in str( error ):
     1446                print("copied %s to %s/%s" % (module_dir, install, module_name))
     1447            except Exception as e:
     1448                if not isinstance(e, WindowsError) or ("already exists" not in str(e)): #@UndefinedVariable
    9441449                    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 
     1450
     1451        add_data_files('', glob.glob("win32\\bundle-extra\\*"))
     1452
     1453    #END OF win32
    9831454#*******************************************************************************
    9841455else:
    9851456    #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"]))
     1457    if is_Fedora() or is_CentOS() or is_RedHat() or FREEBSD:
     1458        libexec = "libexec"
     1459    else:
     1460        libexec = "lib"
     1461    if LINUX:
     1462        if scripts_ENABLED:
     1463            scripts += ["scripts/xpra_udev_product_version", "scripts/xpra_signal_listener"]
     1464        libexec_scripts = []
     1465        if xdg_open_ENABLED:
     1466            libexec_scripts += ["scripts/xdg-open", "scripts/gnome-open", "scripts/gvfs-open"]
     1467        if server_ENABLED:
     1468            libexec_scripts.append("scripts/auth_dialog")
     1469        if libexec_scripts:
     1470            add_data_files("%s/xpra/" % libexec, libexec_scripts)
     1471    if data_ENABLED:
     1472        man_path = "share/man"
     1473        if OPENBSD or FREEBSD:
     1474            man_path = "man"
     1475        add_data_files("%s/man1" % man_path,  ["man/xpra.1", "man/xpra_launcher.1"])
     1476        add_data_files("share/applications",  glob.glob("xdg/*.desktop"))
     1477        add_data_files("share/mime/packages", ["xdg/application-x-xpraconfig.xml"])
     1478        add_data_files("share/icons",         ["xdg/xpra.png", "xdg/xpra-mdns.png", "xdg/xpra-shadow.png"])
     1479        add_data_files("share/metainfo",      ["xdg/xpra.appdata.xml"])
     1480
     1481    #here, we override build and install so we can
     1482    #generate our /etc/xpra/xpra.conf
     1483    class build_override(build):
     1484        def run(self):
     1485            build.run(self)
     1486            self.run_command("build_conf")
     1487
     1488    class build_conf(build):
     1489        def run(self):
     1490            try:
     1491                build_base = self.distribution.command_obj['build'].build_base
     1492            except:
     1493                build_base = self.build_base
     1494            build_xpra_conf(build_base)
     1495
     1496    class install_data_override(install_data):
     1497        def run(self):
     1498            print("install_data_override: install_dir=%s" % self.install_dir)
     1499            if html5_ENABLED:
     1500                install_html5(os.path.join(self.install_dir, "%s/www" % share_xpra))
     1501            install_data.run(self)
     1502
     1503            root_prefix = self.install_dir.rstrip("/")
     1504            if root_prefix.endswith("/usr"):
     1505                root_prefix = root_prefix[:-4]    #ie: "/" or "/usr/src/rpmbuild/BUILDROOT/xpra-0.18.0-0.20160513r12573.fc23.x86_64/"
     1506            build_xpra_conf(root_prefix)
     1507
     1508            def copytodir(src, dst_dir, dst_name=None, chmod=0o644):
     1509                #convert absolute paths:
     1510                if dst_dir.startswith("/"):
     1511                    dst_dir = root_prefix+dst_dir
     1512                else:
     1513                    dst_dir = self.install_dir.rstrip("/")+"/"+dst_dir
     1514                #make sure the target directory exists:
     1515                self.mkpath(dst_dir)
     1516                #generate the target filename:
     1517                filename = os.path.basename(src)
     1518                dst_file = os.path.join(dst_dir, dst_name or filename)
     1519                #copy it
     1520                print("copying %s -> %s (%s)" % (src, dst_dir, oct(chmod)))
     1521                shutil.copyfile(src, dst_file)
     1522                if chmod:
     1523                    os.chmod(dst_file, chmod)
     1524
     1525            if printing_ENABLED and POSIX:
     1526                #install "/usr/lib/cups/backend" with 0700 permissions:
     1527                lib_cups = "lib/cups"
     1528                if FREEBSD:
     1529                    lib_cups = "libexec/cups"
     1530                copytodir("cups/xpraforwarder", "%s/backend" % lib_cups, chmod=0o700)
     1531
     1532            if x11_ENABLED:
     1533                #install xpra_Xdummy if we need it:
     1534                xvfb_command = detect_xorg_setup()
     1535                if any(x.find("xpra_Xdummy")>=0 for x in (xvfb_command or [])) or Xdummy_wrapper_ENABLED is True:
     1536                    copytodir("scripts/xpra_Xdummy", "bin", chmod=0o755)
     1537                #install xorg*.conf, cuda.conf and nvenc.keys:
     1538                etc_xpra_files = ["xorg.conf"]
     1539                if uinput_ENABLED:
     1540                    etc_xpra_files.append("xorg-uinput.conf")
     1541                if nvenc_ENABLED or nvfbc_ENABLED:
     1542                    etc_xpra_files.append("cuda.conf")
     1543                if nvenc_ENABLED:
     1544                    etc_xpra_files.append("nvenc.keys")
     1545                if nvfbc_ENABLED:
     1546                    etc_xpra_files.append("nvfbc.keys")
     1547                for x in etc_xpra_files:
     1548                    copytodir("etc/xpra/%s" % x, "/etc/xpra")
     1549                copytodir("etc/X11/xorg.conf.d/90-xpra-virtual.conf", "/etc/X11/xorg.conf.d/")
     1550
     1551            if pam_ENABLED:
     1552                copytodir("etc/pam.d/xpra", "/etc/pam.d")
     1553
     1554            systemd_dir = "/lib/systemd/system"
     1555            if service_ENABLED:
     1556                #Linux init service:
     1557                if os.path.exists("/bin/systemctl"):
     1558                    if sd_listen_ENABLED:
     1559                        copytodir("service/xpra.service", systemd_dir)
     1560                    else:
     1561                        copytodir("service/xpra-nosocketactivation.service", systemd_dir, dst_name="xpra.service")
     1562                else:
     1563                    copytodir("service/xpra", "/etc/init.d")
     1564                if os.path.exists("/etc/sysconfig"):
     1565                    copytodir("etc/sysconfig/xpra", "/etc/sysconfig")
     1566                elif os.path.exists("/etc/default"):
     1567                    copytodir("etc/sysconfig/xpra", "/etc/default")
     1568            if sd_listen_ENABLED:
     1569                copytodir("service/xpra.socket", systemd_dir)
     1570            if dbus_ENABLED and proxy_ENABLED:
     1571                copytodir("dbus/xpra.conf", "/etc/dbus-1/system.d")
     1572
     1573
     1574    # add build_conf to build step
     1575    cmdclass.update({
     1576             'build'        : build_override,
     1577             'build_conf'   : build_conf,
     1578             'install_data' : install_data_override,
     1579             })
    9971580
    9981581    if OSX:
     1582        #pyobjc needs email.parser
     1583        external_includes += ["email", "uu", "urllib", "objc", "cups", "six"]
     1584        external_includes += ["kerberos", "future", "pyu2f", "paramiko", "nacl"]
    9991585        #OSX package names (ie: gdk-x11-2.0 -> gdk-2.0, etc)
    10001586        PYGTK_PACKAGES += ["gdk-2.0", "gtk+-2.0"]
    10011587        add_packages("xpra.platform.darwin")
     1588        remove_packages("xpra.platform.win32", "xpra.platform.xposix")
     1589        #to support GStreamer 1.x we need this:
     1590        modules.append("importlib")
    10021591    else:
    10031592        PYGTK_PACKAGES += ["gdk-x11-2.0", "gtk+-x11-2.0"]
    10041593        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")
     1594        remove_packages("xpra.platform.win32", "xpra.platform.darwin")
     1595        if data_ENABLED:
     1596            #not supported by all distros, but doesn't hurt to install them anyway:
     1597            for x in ("tmpfiles.d", "sysusers.d"):
     1598                add_data_files("lib/%s" % x, ["%s/xpra.conf" % x])
     1599            if uinput_ENABLED:
     1600                add_data_files("lib/udev/rules.d/", ["udev/rules.d/71-xpra-virtual-pointer.rules"])
    10081601
    10091602    #gentoo does weird things, calls --no-compile with build *and* install
    10101603    #then expects to find the cython modules!? ie:
    1011     #> python2.7 setup.py build -b build-2.7 install --no-compile --root=/var/tmp/portage/x11-wm/xpra-0.7.0/temp/images/2.7
     1604    #> python2.7 setup.py build -b build-2.7 install --no-compile \
     1605    # --root=/var/tmp/portage/x11-wm/xpra-0.7.0/temp/images/2.7
    10121606    #otherwise we use the flags to skip pkgconfig
    10131607    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))
     1608        pkgconfig = no_pkgconfig
    10331609
    10341610    if OSX and "py2app" in sys.argv:
     
    10391615        del setup_options["py_modules"]
    10401616        scripts = []
    1041         def cython_add(*args, **kwargs):
     1617        def cython_add(*_args, **_kwargs):
    10421618            pass
    10431619
     
    10451621        remove_packages(*external_excludes)
    10461622
    1047         Plist = {"CFBundleDocumentTypes" : {
    1048                         "CFBundleTypeExtensions"    : ["Xpra"],
    1049                         "CFBundleTypeName"          : "Xpra Session Config File",
    1050                         "CFBundleName"              : "Xpra",
    1051                         "CFBundleTypeRole"          : "Viewer",
    1052                         }}
     1623        try:
     1624            from xpra.src_info import REVISION
     1625        except ImportError:
     1626            REVISION = "unknown"
     1627        Plist = {
     1628            "CFBundleDocumentTypes" : {
     1629                "CFBundleTypeExtensions"    : ["Xpra"],
     1630                "CFBundleTypeName"          : "Xpra Session Config File",
     1631                "CFBundleName"              : "Xpra",
     1632                "CFBundleTypeRole"          : "Viewer",
     1633                },
     1634            "CFBundleGetInfoString" : "%s-r%s (c) 2012-2020 https://xpra.org/" % (XPRA_VERSION, REVISION),
     1635            "CFBundleIdentifier"            : "org.xpra.xpra",
     1636            }
    10531637        #Note: despite our best efforts, py2app will not copy all the modules we need
    10541638        #so the make-app.sh script still has to hack around this problem.
    10551639        add_modules(*external_includes)
     1640        #needed by python-lz4:
     1641        add_modules("distutils")
    10561642        py2app_options = {
    10571643            'iconfile'          : '../osx/xpra.icns',
     
    10651651            }
    10661652        setup_options["options"] = {"py2app": py2app_options}
    1067         setup_options["app"]     = ["xpra/client/gtk2/client_launcher.py"]
     1653        setup_options["app"]     = ["xpra/scripts/main.py"]
     1654
     1655    if OSX:
     1656        #simply adding the X11 path to PKG_CONFIG_PATH breaks things in mysterious ways,
     1657        #so instead we have to query each package seperately and merge the results:
     1658        def osx_pkgconfig(*pkgs_options, **ekw):
     1659            kw = dict(ekw)
     1660            for pkg in pkgs_options:
     1661                saved_pcp = os.environ.get("PKG_CONFIG_PATH")
     1662                if pkg.lower().startswith("x"):
     1663                    os.environ["PKG_CONFIG_PATH"] = "/usr/X11/lib/pkgconfig"
     1664                #print("exec_pkgconfig(%s, %s)", pkg, kw)
     1665                kw = exec_pkgconfig(pkg, **kw)
     1666                os.environ["PKG_CONFIG_PATH"] = saved_pcp
     1667            return kw
     1668
     1669        pkgconfig = osx_pkgconfig
     1670
     1671
     1672if scripts_ENABLED:
     1673    scripts += ["scripts/xpra", "scripts/xpra_launcher"]
     1674toggle_modules(WIN32, "xpra/scripts/win32_service")
     1675
     1676if data_ENABLED:
     1677    add_data_files(share_xpra,                      ["README", "COPYING"])
     1678    add_data_files(share_xpra,                      ["bell.wav"])
     1679    add_data_files("%s/http-headers" % share_xpra,   glob.glob("http-headers/*"))
     1680    ICONS = glob.glob("icons/*")
     1681    if WIN32:
     1682        ICONS += glob.glob("icons/*ico")
     1683    add_data_files("%s/icons" % share_xpra,          ICONS)
     1684
     1685    add_data_files("%s/content-type" % share_xpra,   glob.glob("content-type/*"))
     1686    add_data_files("%s/content-categories" % share_xpra, glob.glob("content-categories/*"))
     1687    add_data_files("%s/css" % share_xpra,            glob.glob("css/*"))
    10681688
    10691689
    10701690if 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 
     1691    if WIN32 or OSX:
     1692        external_includes.append("numpy")
     1693        external_includes.append("ssl")
     1694        external_includes.append("_ssl")
     1695
     1696
     1697if annotate_ENABLED:
     1698    from Cython.Compiler import Options
     1699    Options.annotate = True
    10761700
    10771701
    10781702#*******************************************************************************
    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")
     1703buffers_c = "xpra/buffers/buffers.c"
     1704memalign_c = "xpra/buffers/memalign.c"
     1705xxhash_c = "xpra/buffers/xxhash.c"
     1706membuffers_c = [memalign_c, buffers_c, xxhash_c]
     1707
     1708if modules_ENABLED:
     1709    add_packages("xpra.buffers")
     1710    buffers_pkgconfig = pkgconfig(optimize=3)
     1711    import platform
     1712    if platform.machine()=="i386":
     1713        #this may well be sub-optimal:
     1714        add_to_keywords(buffers_pkgconfig, "extra_compile_args", "-mfpmath=387")
     1715    if cython_ENABLED:
     1716        cython_add(Extension("xpra.buffers.membuf",
     1717                    ["xpra/buffers/membuf.pyx"]+membuffers_c, **buffers_pkgconfig))
     1718
     1719
     1720toggle_packages(dbus_ENABLED, "xpra.dbus")
     1721toggle_packages(mdns_ENABLED, "xpra.net.mdns")
     1722toggle_packages(websockets_ENABLED, "xpra.net.websockets")
     1723toggle_packages(server_ENABLED or proxy_ENABLED, "xpra.server", "xpra.server.auth")
     1724toggle_packages(rfb_ENABLED, "xpra.server.rfb")
     1725toggle_packages(proxy_ENABLED, "xpra.server.proxy")
     1726toggle_packages(server_ENABLED, "xpra.server.window")
     1727toggle_packages(server_ENABLED or shadow_ENABLED, "xpra.server.mixins", "xpra.server.source")
     1728toggle_packages(shadow_ENABLED, "xpra.server.shadow")
     1729toggle_packages(server_ENABLED or client_ENABLED, "xpra.clipboard")
     1730toggle_packages(x11_ENABLED and dbus_ENABLED and server_ENABLED, "xpra.x11.dbus")
     1731toggle_packages(notifications_ENABLED, "xpra.notifications")
     1732
     1733#cannot use toggle here as cx_Freeze will complain if we try to exclude this module:
     1734if dbus_ENABLED and server_ENABLED:
     1735    add_packages("xpra.server.dbus")
     1736
     1737if OSX:
     1738    quartz_pkgconfig = pkgconfig("gtk+-3.0", "pygobject-3.0")
     1739    add_to_keywords(quartz_pkgconfig, 'extra_compile_args',
     1740                "-ObjC",
     1741                "-framework", "AppKit",
     1742                "-I/System/Library/Frameworks/Cocoa.framework/Versions/A/Headers/",
     1743                "-I/System/Library/Frameworks/AppKit.framework/Versions/C/Headers/")
     1744    cython_add(Extension("xpra.platform.darwin.gdk3_bindings",
     1745            ["xpra/platform/darwin/gdk3_bindings.pyx", "xpra/platform/darwin/transparency_glue.m"],
     1746            language="objc",
     1747            **quartz_pkgconfig
     1748            ))
     1749
     1750if cython_ENABLED:
     1751    monotonic_time_pkgconfig = pkgconfig()
     1752    if not OSX and not WIN32 and not OPENBSD:
     1753        add_to_keywords(monotonic_time_pkgconfig, 'extra_link_args', "-lrt")
     1754    cython_add(Extension("xpra.monotonic_time",
     1755                ["xpra/monotonic_time.pyx", "xpra/monotonic_ctime.c"],
     1756                **monotonic_time_pkgconfig
     1757                ))
     1758
     1759
     1760toggle_packages(x11_ENABLED, "xpra.x11", "xpra.x11.bindings")
    10841761if x11_ENABLED:
    1085     make_constants("xpra", "x11", "bindings", "constants")
    1086     make_constants("xpra", "x11", "gtk_x11", "constants")
    1087 
    10881762    cython_add(Extension("xpra.x11.bindings.wait_for_x_server",
    10891763                ["xpra/x11/bindings/wait_for_x_server.pyx"],
     
    10981772                **pkgconfig("x11")
    10991773                ))
     1774    cython_add(Extension("xpra.x11.bindings.posix_display_source",
     1775                ["xpra/x11/bindings/posix_display_source.pyx"],
     1776                **pkgconfig("x11")
     1777                ))
     1778
    11001779    cython_add(Extension("xpra.x11.bindings.randr_bindings",
    11011780                ["xpra/x11/bindings/randr_bindings.pyx"],
     
    11041783    cython_add(Extension("xpra.x11.bindings.keyboard_bindings",
    11051784                ["xpra/x11/bindings/keyboard_bindings.pyx"],
    1106                 **pkgconfig("x11", "xtst", "xfixes")
     1785                **pkgconfig("x11", "xtst", "xfixes", "xkbfile")
    11071786                ))
    11081787
    11091788    cython_add(Extension("xpra.x11.bindings.window_bindings",
    11101789                ["xpra/x11/bindings/window_bindings.pyx"],
    1111                 **pkgconfig("xtst", "xfixes", "xcomposite", "xdamage")
     1790                **pkgconfig("x11", "xtst", "xfixes", "xcomposite", "xdamage", "xext")
    11121791                ))
    11131792    cython_add(Extension("xpra.x11.bindings.ximage",
    11141793                ["xpra/x11/bindings/ximage.pyx"],
    1115                 **pkgconfig("xcomposite", "xdamage", "xext")
     1794                **pkgconfig("x11", "xext", "xcomposite")
    11161795                ))
    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)
     1796if xinput_ENABLED:
     1797    cython_add(Extension("xpra.x11.bindings.xi2_bindings",
     1798                ["xpra/x11/bindings/xi2_bindings.pyx"],
     1799                **pkgconfig("x11", "xi")
    11221800                ))
    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)
     1801
     1802toggle_packages(gtk_x11_ENABLED, "xpra.x11.gtk_x11")
     1803toggle_packages(server_ENABLED and gtk_x11_ENABLED, "xpra.x11.models")
     1804if gtk_x11_ENABLED:
     1805    add_packages("xpra.x11.gtk3")
     1806    #GTK3 display source:
     1807    cython_add(Extension("xpra.x11.gtk3.gdk_display_source",
     1808                ["xpra/x11/gtk3/gdk_display_source.pyx"],
     1809                **pkgconfig("gdk-3.0")
    11271810                ))
    1128 
    1129 
    1130 toggle_packages(argb_ENABLED, "xpra.codecs.argb")
    1131 if argb_ENABLED:
     1811    cython_add(Extension("xpra.x11.gtk3.gdk_bindings",
     1812                ["xpra/x11/gtk3/gdk_bindings.pyx", "xpra/x11/gtk3/gdk_x11_macros.c"],
     1813                **pkgconfig("gdk-3.0")
     1814                ))
     1815
     1816if client_ENABLED and gtk3_ENABLED:
     1817    #cairo workaround:
     1818    cython_add(Extension("xpra.client.gtk3.cairo_workaround",
     1819                ["xpra/client/gtk3/cairo_workaround.pyx"],
     1820                **pkgconfig("py3cairo")
     1821                ))
     1822
     1823if client_ENABLED or server_ENABLED:
     1824    add_packages("xpra.codecs.argb")
     1825    argb_pkgconfig = pkgconfig(optimize=3)
    11321826    cython_add(Extension("xpra.codecs.argb.argb",
    1133                 ["xpra/codecs/argb/argb.pyx"]))
     1827                ["xpra/codecs/argb/argb.pyx"], **argb_pkgconfig))
     1828
     1829
     1830#build tests, but don't install them:
     1831toggle_packages(tests_ENABLED, "unit")
    11341832
    11351833
    11361834if bundle_tests_ENABLED:
    11371835    #bundle the tests directly (not in library.zip):
    1138     for k,v in glob_recurse("tests").items():
    1139         if (k!=""):
     1836    for k,v in glob_recurse("unit").items():
     1837        if k!="":
    11401838            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:
     1839        add_data_files("unit"+k, v)
     1840
     1841#python-cryptography needs workarounds for bundling:
     1842if crypto_ENABLED and (OSX or WIN32):
     1843    external_includes.append("_ssl")
     1844    external_includes.append("cffi")
     1845    external_includes.append("_cffi_backend")
     1846    external_includes.append("cryptography")
     1847    external_includes.append("idna")
     1848    external_includes.append("idna.idnadata")
     1849    external_includes.append("pkg_resources._vendor.packaging")
     1850    external_includes.append("pkg_resources._vendor.packaging.requirements")
     1851    external_includes.append("pkg_resources._vendor.pyparsing")
     1852    add_modules("cryptography.hazmat.bindings._openssl")
     1853    add_modules("cryptography.hazmat.bindings._constant_time")
     1854    add_modules("cryptography.hazmat.bindings._padding")
     1855    add_modules("cryptography.hazmat.backends.openssl")
     1856    add_modules("cryptography.fernet")
     1857    if WIN32:
     1858        external_includes.append("appdirs")
     1859
     1860#special case for client: cannot use toggle_packages which would include gtk3, etc:
    11441861if 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")
    1147 toggle_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")
    1150 toggle_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")
     1862    add_modules("xpra.client")
     1863    add_packages("xpra.client.mixins", "xpra.client.auth")
     1864    add_modules("xpra.scripts.gtk_info")
     1865    add_modules("xpra.scripts.show_webcam")
     1866if gtk3_ENABLED:
     1867    add_modules("xpra.scripts.bug_report")
     1868toggle_packages((client_ENABLED and gtk3_ENABLED) or sound_ENABLED or server_ENABLED, "xpra.gtk_common")
     1869toggle_packages(client_ENABLED and gtk3_ENABLED, "xpra.client.gtk3")
     1870toggle_packages((client_ENABLED and gtk3_ENABLED) or (sound_ENABLED and WIN32 and MINGW_PREFIX), "gi")
     1871toggle_packages(client_ENABLED and gtk3_ENABLED, "xpra.client.gtk_base")
     1872toggle_packages(client_ENABLED and opengl_ENABLED and gtk3_ENABLED, "xpra.client.gl.gtk3")
     1873toggle_packages(client_ENABLED and gtk3_ENABLED and example_ENABLED, "xpra.client.gtk_base.example")
     1874if client_ENABLED and WIN32 and MINGW_PREFIX:
     1875    propsys_pkgconfig = pkgconfig()
     1876    if debug_ENABLED:
     1877        add_to_keywords(propsys_pkgconfig, 'extra_compile_args', "-DDEBUG")
     1878    add_to_keywords(propsys_pkgconfig, 'extra_link_args', "-luuid", "-lshlwapi", "-lole32", "-static-libgcc")
     1879    cython_add(Extension("xpra.platform.win32.propsys",
     1880                ["xpra/platform/win32/propsys.pyx", "xpra/platform/win32/setappid.cpp"],
     1881                language="c++",
     1882                **propsys_pkgconfig))
     1883
     1884if client_ENABLED or server_ENABLED:
     1885    add_modules("xpra.codecs")
     1886toggle_packages(keyboard_ENABLED, "xpra.keyboard")
     1887if client_ENABLED or server_ENABLED:
     1888    add_modules(
     1889        "xpra.scripts.config",
     1890        "xpra.scripts.parsing",
     1891        "xpra.scripts.exec_util",
     1892        "xpra.scripts.fdproxy",
     1893        "xpra.scripts.version",
     1894        )
     1895if server_ENABLED or proxy_ENABLED:
     1896    add_modules("xpra.scripts.server")
     1897if WIN32 and client_ENABLED and gtk3_ENABLED:
     1898    add_modules("xpra.scripts.gtk_info")
     1899
     1900toggle_packages(not WIN32, "xpra.platform.pycups_printing")
     1901toggle_packages(client_ENABLED and opengl_ENABLED, "xpra.client.gl")
     1902
     1903toggle_modules(sound_ENABLED, "xpra.sound")
     1904toggle_modules(sound_ENABLED and not (OSX or WIN32), "xpra.sound.pulseaudio")
    11541905
    11551906toggle_packages(clipboard_ENABLED, "xpra.clipboard")
    11561907if clipboard_ENABLED:
    1157     cython_add(Extension("xpra.gtk_common.gdk_atoms",
    1158                 ["xpra/gtk_common/gdk_atoms.pyx"],
    1159                 **pkgconfig(*PYGTK_PACKAGES)
     1908    cython_add(Extension("xpra.gtk_common.gtk3.gdk_atoms",
     1909                         ["xpra/gtk_common/gtk3/gdk_atoms.pyx"],
     1910                         **pkgconfig("gtk+-3.0")
     1911                         ))
     1912toggle_packages(clipboard_ENABLED or gtk3_ENABLED, "xpra.gtk_common.gtk3")
     1913if gtk3_ENABLED:
     1914    cython_add(Extension("xpra.gtk_common.gtk3.gdk_bindings",
     1915                ["xpra/gtk_common/gtk3/gdk_bindings.pyx"],
     1916                **pkgconfig("gtk+-3.0", "pygobject-3.0")
    11601917                ))
    11611918
    1162 if cyxor_ENABLED:
     1919O3_pkgconfig = pkgconfig(optimize=3)
     1920toggle_packages(client_ENABLED or server_ENABLED, "xpra.codecs.xor")
     1921if client_ENABLED or server_ENABLED:
    11631922    cython_add(Extension("xpra.codecs.xor.cyxor",
    11641923                ["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")
     1924                **O3_pkgconfig))
     1925if client_ENABLED or server_ENABLED or shadow_ENABLED:
     1926    cython_add(Extension("xpra.rectangle",
     1927                ["xpra/rectangle.pyx"],
     1928                **O3_pkgconfig))
     1929
     1930if server_ENABLED or shadow_ENABLED:
     1931    cython_add(Extension("xpra.server.cystats",
     1932                ["xpra/server/cystats.pyx"],
     1933                **O3_pkgconfig))
     1934    cython_add(Extension("xpra.server.window.motion",
     1935                ["xpra/server/window/motion.pyx"],
     1936                **O3_pkgconfig))
     1937
     1938if sd_listen_ENABLED:
     1939    sdp = pkgconfig("libsystemd")
     1940    cython_add(Extension("xpra.platform.xposix.sd_listen",
     1941                ["xpra/platform/xposix/sd_listen.pyx"],
     1942                **sdp))
     1943
     1944
    11781945toggle_packages(enc_proxy_ENABLED, "xpra.codecs.enc_proxy")
    11791946
     1947toggle_packages(nvfbc_ENABLED, "xpra.codecs.nvfbc")
     1948if nvfbc_ENABLED:
     1949    nvfbc_pkgconfig = pkgconfig("nvfbc")
     1950    if WIN32:
     1951        add_to_keywords(nvfbc_pkgconfig, 'extra_compile_args', "-Wno-endif-labels")
     1952    platform = sys.platform.rstrip("0123456789")
     1953    cython_add(Extension("xpra.codecs.nvfbc.fbc_capture_%s" % platform,
     1954                         ["xpra/codecs/nvfbc/fbc_capture_%s.pyx" % platform],
     1955                         language="c++",
     1956                         **nvfbc_pkgconfig))
     1957
    11801958toggle_packages(nvenc_ENABLED, "xpra.codecs.nvenc")
     1959toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.cuda_common")
     1960toggle_packages(nvenc_ENABLED or nvfbc_ENABLED, "xpra.codecs.nv_util")
     1961
     1962if nvenc_ENABLED and cuda_kernels_ENABLED:
     1963    #find nvcc:
     1964    path_options = os.environ.get("PATH", "").split(os.path.pathsep)
     1965    CUDA_VERSIONS = ["10.2", "10.1", "10.0", "9.2", "9.1", "9.0", "8.0", "7.5", ]
     1966    if WIN32:
     1967        external_includes += ["pycuda"]
     1968        nvcc_exe = "nvcc.exe"
     1969        CUDA_DIR = os.environ.get("CUDA_DIR", "C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA")
     1970        path_options = [os.path.join(CUDA_DIR, "v%s" % x, "bin") for x in CUDA_VERSIONS] + path_options
     1971        #pycuda may link against curand, find it and ship it:
     1972        for p in path_options:
     1973            if os.path.exists(p):
     1974                add_data_files("", glob.glob("%s\\curand64*.dll" % p))
     1975                add_data_files("", glob.glob("%s\\cudart64*.dll" % p))
     1976                break
     1977    else:
     1978        nvcc_exe = "nvcc"
     1979        for v in [""]+CUDA_VERSIONS:
     1980            suffix = ""
     1981            if v:
     1982                suffix = "-%s" % v
     1983            path_options += ["/usr/local/cuda%s/bin" % suffix, "/opt/cuda%s/bin" % suffix]
     1984    options = [os.path.join(x, nvcc_exe) for x in path_options]
     1985    def which(cmd):
     1986        try:
     1987            code, out, _ = get_status_output(["which", cmd])
     1988            if code==0:
     1989                return out
     1990        except:
     1991            pass
     1992        return None
     1993    #prefer the one we find on the $PATH, if any:
     1994    try:
     1995        v = which(nvcc_exe)
     1996        if v and (v not in options):
     1997            options.insert(0, v)
     1998    except:
     1999        pass
     2000    nvcc_versions = {}
     2001    def get_nvcc_version(command):
     2002        if not os.path.exists(command):
     2003            return None
     2004        code, out, _ = get_status_output([command, "--version"])
     2005        if code!=0:
     2006            return None
     2007        vpos = out.rfind(", V")
     2008        if vpos>0:
     2009            version = out[vpos+3:].strip("\n")
     2010            version_str = " version %s" % version
     2011        else:
     2012            version = "0"
     2013            version_str = " unknown version!"
     2014        print("found CUDA compiler: %s%s" % (filename, version_str))
     2015        return tuple(int(x) for x in version.split("."))
     2016    for filename in options:
     2017        vnum = get_nvcc_version(filename)
     2018        if vnum:
     2019            nvcc_versions[vnum] = filename
     2020    assert nvcc_versions, "cannot find nvcc compiler!"
     2021    #choose the most recent one:
     2022    version, nvcc = list(reversed(sorted(nvcc_versions.items())))[0]
     2023    if len(nvcc_versions)>1:
     2024        print(" using version %s from %s" % (version, nvcc))
     2025    if WIN32:
     2026        cuda_path = os.path.dirname(nvcc)           #strip nvcc.exe
     2027        cuda_path = os.path.dirname(cuda_path)      #strip /bin/
     2028    #first compile the cuda kernels
     2029    #(using the same cuda SDK for both nvenc modules for now..)
     2030    #TODO:
     2031    # * compile directly to output directory instead of using data files?
     2032    # * detect which arches we want to build for? (does it really matter much?)
     2033    kernels = ("ARGB_to_NV12", "ARGB_to_YUV444", "BGRA_to_NV12", "BGRA_to_YUV444")
     2034    for kernel in kernels:
     2035        cuda_src = "xpra/codecs/cuda_common/%s.cu" % kernel
     2036        cuda_bin = "xpra/codecs/cuda_common/%s.fatbin" % kernel
     2037        if os.path.exists(cuda_bin) and (cuda_rebuild_ENABLED is False):
     2038            continue
     2039        reason = should_rebuild(cuda_src, cuda_bin)
     2040        if not reason:
     2041            continue
     2042        print("rebuilding %s: %s" % (kernel, reason))
     2043        cmd = [nvcc,
     2044               '-fatbin',
     2045               #"-cubin",
     2046               #"-arch=compute_30", "-code=compute_30,sm_30,sm_35",
     2047               #"-gencode=arch=compute_50,code=sm_50",
     2048               #"-gencode=arch=compute_52,code=sm_52",
     2049               #"-gencode=arch=compute_52,code=compute_52",
     2050               "-c", cuda_src,
     2051               "-o", cuda_bin]
     2052        #GCC 8.1 has compatibility issues with CUDA 9.2,
     2053        #so revert to C++03:
     2054        if get_gcc_version()>=[8, 1]:
     2055            cmd.append("-std=c++03")
     2056        #GCC 6 uses C++11 by default:
     2057        elif get_gcc_version()>=[6, 0]:
     2058            cmd.append("-std=c++11")
     2059        CL_VERSION = os.environ.get("CL_VERSION")
     2060        if CL_VERSION:
     2061            cmd += ["--use-local-env", "--cl-version", CL_VERSION]
     2062            #-ccbin "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\cl.exe"
     2063            cmd += ["--machine", "32"]
     2064        if WIN32:
     2065            #cmd += ["--compiler-bindir", "C:\\msys64\\mingw64\\bin\\g++.exe"]
     2066            #cmd += ["--input-drive-prefix", "/"]
     2067            #cmd += ["--dependency-drive-prefix", "/"]
     2068            cmd += ["-I%s" % os.path.abspath("win32")]
     2069        comp_code_options = [(30, 30), (35, 35)]
     2070        #see: http://docs.nvidia.com/cuda/maxwell-compatibility-guide/#building-maxwell-compatible-apps-using-cuda-6-0
     2071        if version!=(0,) and version<(7, 5):
     2072            print("CUDA version %s is very unlikely to work")
     2073            print("try upgrading to version 7.5 or later")
     2074        if version>=(7, 5):
     2075            comp_code_options.append((50, 50))
     2076            comp_code_options.append((52, 52))
     2077            comp_code_options.append((53, 53))
     2078        if version>=(8, 0):
     2079            comp_code_options.append((60, 60))
     2080            comp_code_options.append((61, 61))
     2081            comp_code_options.append((62, 62))
     2082        if version>=(9, 0):
     2083            comp_code_options.append((70, 70))
     2084        if version>=(10, 0):
     2085            comp_code_options.append((75, 75))
     2086        for arch, code in comp_code_options:
     2087            cmd.append("-gencode=arch=compute_%s,code=sm_%s" % (arch, code))
     2088        print("CUDA compiling %s (%s)" % (kernel.ljust(16), reason))
     2089        print(" %s" % " ".join("'%s'" % x for x in cmd))
     2090        c, stdout, stderr = get_status_output(cmd)
     2091        if c!=0:
     2092            print("Error: failed to compile CUDA kernel %s" % kernel)
     2093            print(stdout or "")
     2094            print(stderr or "")
     2095            sys.exit(1)
     2096    CUDA_BIN = "%s/cuda" % share_xpra
     2097    add_data_files(CUDA_BIN, ["xpra/codecs/cuda_common/%s.fatbin" % x for x in kernels])
     2098
    11812099if 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))
     2100    nvencmodule = "nvenc"
     2101    nvenc_pkgconfig = pkgconfig(nvencmodule, ignored_flags=["-l", "-L"])
     2102    #don't link against libnvidia-encode, we load it dynamically:
     2103    libraries = nvenc_pkgconfig.get("libraries", [])
     2104    if "nvidia-encode" in libraries:
     2105        libraries.remove("nvidia-encode")
     2106    if not cython_version_compare("0.29"):
     2107        #older versions emit spurious warnings:
     2108        print("Warning: using workaround for outdated version of cython")
     2109        add_to_keywords(nvenc_pkgconfig, 'extra_compile_args', "-Wno-error=sign-compare")
     2110    cython_add(Extension("xpra.codecs.%s.encoder" % nvencmodule,
     2111                         ["xpra/codecs/%s/encoder.pyx" % nvencmodule],
     2112                         **nvenc_pkgconfig))
    11872113
    11882114toggle_packages(enc_x264_ENABLED, "xpra.codecs.enc_x264")
    11892115if enc_x264_ENABLED:
    1190     x264_pkgconfig = pkgconfig("x264", static=x264_static_ENABLED)
     2116    x264_pkgconfig = pkgconfig("x264")
     2117    if get_gcc_version()>=[6, 0]:
     2118        add_to_keywords(x264_pkgconfig, 'extra_compile_args', "-Wno-unused-variable")
    11912119    cython_add(Extension("xpra.codecs.enc_x264.encoder",
    11922120                ["xpra/codecs/enc_x264/encoder.pyx"],
    1193                 **x264_pkgconfig), min_version=(0, 16))
     2121                **x264_pkgconfig))
    11942122
    11952123toggle_packages(enc_x265_ENABLED, "xpra.codecs.enc_x265")
    11962124if enc_x265_ENABLED:
    1197     x265_pkgconfig = pkgconfig("x265", static=x265_static_ENABLED)
     2125    x265_pkgconfig = pkgconfig("x265")
    11982126    cython_add(Extension("xpra.codecs.enc_x265.encoder",
    11992127                ["xpra/codecs/enc_x265/encoder.pyx"],
    1200                 **x265_pkgconfig), min_version=(0, 16))
     2128                **x265_pkgconfig))
     2129
     2130toggle_packages(pillow_ENABLED, "xpra.codecs.pillow")
     2131if pillow_ENABLED:
     2132    external_includes += ["PIL", "PIL.Image", "PIL.WebPImagePlugin"]
    12012133
    12022134toggle_packages(webp_ENABLED, "xpra.codecs.webp")
    12032135if webp_ENABLED:
    1204     webp_pkgconfig = pkgconfig("webp")
    1205     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))
     2136    webp_pkgconfig = pkgconfig("libwebp")
     2137    cython_add(Extension("xpra.codecs.webp.encoder",
     2138                    ["xpra/codecs/webp/encoder.pyx"],
     2139                    **webp_pkgconfig))
     2140    cython_add(Extension("xpra.codecs.webp.decoder",
     2141                ["xpra/codecs/webp/decoder.pyx"],
     2142                **webp_pkgconfig))
     2143
     2144jpeg = jpeg_decoder_ENABLED or jpeg_encoder_ENABLED
     2145toggle_packages(jpeg, "xpra.codecs.jpeg")
     2146if jpeg:
     2147    if jpeg_encoder_ENABLED:
     2148        jpeg_pkgconfig = pkgconfig("libturbojpeg")
     2149        if not pkg_config_version("1.4", "libturbojpeg"):
     2150            #older versions don't have const argument:
     2151            remove_from_keywords(jpeg_pkgconfig, 'extra_compile_args', "-Werror")
     2152        cython_add(Extension("xpra.codecs.jpeg.encoder",
     2153                ["xpra/codecs/jpeg/encoder.pyx"],
     2154                **jpeg_pkgconfig))
     2155    if jpeg_decoder_ENABLED:
     2156        jpeg_pkgconfig = pkgconfig("libturbojpeg")
     2157        cython_add(Extension("xpra.codecs.jpeg.decoder",
     2158                ["xpra/codecs/jpeg/decoder.pyx"],
     2159                **jpeg_pkgconfig))
     2160
     2161#swscale and avcodec2 use libav_common/av_log:
     2162libav_common = dec_avcodec2_ENABLED or csc_swscale_ENABLED
     2163toggle_packages(libav_common, "xpra.codecs.libav_common")
     2164if libav_common:
     2165    avutil_pkgconfig = pkgconfig("libavutil")
     2166    if get_gcc_version()>=[9, 0]:
     2167        add_to_keywords(avutil_pkgconfig, 'extra_compile_args', "-Wno-error=attributes")
     2168    cython_add(Extension("xpra.codecs.libav_common.av_log",
     2169                ["xpra/codecs/libav_common/av_log.pyx"],
     2170                **avutil_pkgconfig))
     2171
    12162172
    12172173toggle_packages(dec_avcodec2_ENABLED, "xpra.codecs.dec_avcodec2")
    12182174if dec_avcodec2_ENABLED:
    1219     avcodec2_pkgconfig = pkgconfig("avcodec", "avutil", static=avcodec2_static_ENABLED)
     2175    avcodec2_pkgconfig = pkgconfig("libavcodec", "libavutil", "libavformat")
     2176    if get_gcc_version()>=[9, 0]:
     2177        add_to_keywords(avcodec2_pkgconfig, 'extra_compile_args', "-Wno-error=attributes")
    12202178    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 
     2179                ["xpra/codecs/dec_avcodec2/decoder.pyx", "xpra/codecs/dec_avcodec2/register_compat.c"],
     2180                **avcodec2_pkgconfig))
     2181
     2182
     2183toggle_packages(csc_libyuv_ENABLED, "xpra.codecs.csc_libyuv")
     2184if csc_libyuv_ENABLED:
     2185    libyuv_pkgconfig = pkgconfig("libyuv")
     2186    cython_add(Extension("xpra.codecs.csc_libyuv.colorspace_converter",
     2187                ["xpra/codecs/csc_libyuv/colorspace_converter.pyx"],
     2188                language="c++",
     2189                **libyuv_pkgconfig))
    12242190
    12252191toggle_packages(csc_swscale_ENABLED, "xpra.codecs.csc_swscale")
    12262192if csc_swscale_ENABLED:
    1227     make_constants("xpra", "codecs", "csc_swscale", "constants")
    1228     swscale_pkgconfig = pkgconfig("swscale", static=swscale_static_ENABLED)
     2193    swscale_pkgconfig = pkgconfig("libswscale", "libavutil")
     2194    if get_gcc_version()>=[9, 0]:
     2195        add_to_keywords(swscale_pkgconfig, 'extra_compile_args', "-Wno-error=attributes")
    12292196    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))
     2197                ["xpra/codecs/csc_swscale/colorspace_converter.pyx"],
     2198                **swscale_pkgconfig))
     2199
    12392200
    12402201toggle_packages(vpx_ENABLED, "xpra.codecs.vpx")
    12412202if vpx_ENABLED:
    1242     vpx_pkgconfig = pkgconfig("vpx", static=vpx_static_ENABLED)
     2203    vpx_pkgconfig = pkgconfig("vpx")
    12432204    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))
     2205                ["xpra/codecs/vpx/encoder.pyx"],
     2206                **vpx_pkgconfig))
    12462207    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))
     2208                ["xpra/codecs/vpx/decoder.pyx"],
     2209                **vpx_pkgconfig))
     2210
     2211toggle_packages(enc_ffmpeg_ENABLED, "xpra.codecs.enc_ffmpeg")
     2212if enc_ffmpeg_ENABLED:
     2213    ffmpeg_pkgconfig = pkgconfig("libavcodec", "libavformat", "libavutil")
     2214    if get_gcc_version()>=[9, 0]:
     2215        add_to_keywords(ffmpeg_pkgconfig, 'extra_compile_args', "-Wno-error=attributes")
     2216    cython_add(Extension("xpra.codecs.enc_ffmpeg.encoder",
     2217                ["xpra/codecs/enc_ffmpeg/encoder.pyx"],
     2218                **ffmpeg_pkgconfig))
     2219
     2220toggle_packages(v4l2_ENABLED, "xpra.codecs.v4l2")
     2221if v4l2_ENABLED:
     2222    v4l2_pkgconfig = pkgconfig()
     2223    #fugly warning: cython makes this difficult,
     2224    #we have to figure out if "device_caps" exists in the headers:
     2225    videodev2_h = "/usr/include/linux/videodev2.h"
     2226    constants_pxi = "xpra/codecs/v4l2/constants.pxi"
     2227    if not os.path.exists(videodev2_h) or should_rebuild(videodev2_h, constants_pxi):
     2228        ENABLE_DEVICE_CAPS = 0
     2229        if os.path.exists(videodev2_h):
     2230            with open(videodev2_h) as f:
     2231                hdata = f.read()
     2232            ENABLE_DEVICE_CAPS = int(hdata.find("device_caps")>=0)
     2233        with open(constants_pxi, "wb") as f:
     2234            f.write(b"DEF ENABLE_DEVICE_CAPS=%i" % ENABLE_DEVICE_CAPS)
     2235    cython_add(Extension("xpra.codecs.v4l2.pusher",
     2236                ["xpra/codecs/v4l2/pusher.pyx"],
     2237                **v4l2_pkgconfig))
    12622238
    12632239
    12642240toggle_packages(bencode_ENABLED, "xpra.net.bencode")
     2241toggle_packages(bencode_ENABLED and cython_bencode_ENABLED, "xpra.net.bencode.cython_bencode")
    12652242if 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")
     2243    bencode_pkgconfig = pkgconfig(optimize=3)
    12722244    cython_add(Extension("xpra.net.bencode.cython_bencode",
    12732245                ["xpra/net/bencode/cython_bencode.pyx"],
    12742246                **bencode_pkgconfig))
    12752247
     2248if netdev_ENABLED:
     2249    netdev_pkgconfig = pkgconfig()
     2250    cython_add(Extension("xpra.platform.xposix.netdev_query",
     2251                ["xpra/platform/xposix/netdev_query.pyx"],
     2252                **netdev_pkgconfig))
     2253
     2254if vsock_ENABLED:
     2255    vsock_pkgconfig = pkgconfig()
     2256    cython_add(Extension("xpra.net.vsock",
     2257                ["xpra/net/vsock.pyx"],
     2258                **vsock_pkgconfig))
     2259
     2260if pam_ENABLED:
     2261    pam_pkgconfig = pkgconfig()
     2262    add_to_keywords(pam_pkgconfig, 'extra_compile_args', "-I/usr/include/pam", "-I/usr/include/security")
     2263    add_to_keywords(pam_pkgconfig, 'extra_link_args', "-lpam", "-lpam_misc")
     2264    cython_add(Extension("xpra.server.pam",
     2265                ["xpra/server/pam.pyx"],
     2266                **pam_pkgconfig))
     2267
    12762268
    12772269if ext_modules:
    1278     setup_options["ext_modules"] = ext_modules
     2270    from Cython.Build import cythonize
     2271    #this causes Cython to fall over itself:
     2272    #gdb_debug=debug_ENABLED
     2273    setup_options["ext_modules"] = cythonize(ext_modules, gdb_debug=False)
    12792274if cmdclass:
    12802275    setup_options["cmdclass"] = cmdclass
     
    12832278
    12842279
    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 
    12932280def main():
    12942281    if OSX or WIN32 or debug_ENABLED:
     2282        print()
    12952283        print("setup options:")
     2284        if verbose_ENABLED:
     2285            print("setup_options=%s" % (setup_options,))
     2286        try:
     2287            from xpra.util import repr_ellipsized as pv
     2288        except ImportError:
     2289            def pv(v):
     2290                return str(v)
    12962291        for k,v in setup_options.items():
    1297             print_option("", k, v)
     2292            print_option("", k, pv(v))
    12982293        print("")
    12992294
Note: See TracChangeset for help on using the changeset viewer.