From 3d8662ebfe778c85319c473b16ecd4d60cb6d137 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 2 Aug 2019 19:22:16 -0700 Subject: [PATCH] Add support for wine+mingw environments --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++ gst-env.py | 40 ++++++++++++++++++++++++++++++++--- gst-uninstalled.py | 1 + meson.build | 10 +++++++++ scripts/common.py | 28 +++++++++++++++++++++++++ 5 files changed, 128 insertions(+), 3 deletions(-) create mode 120000 gst-uninstalled.py diff --git a/README.md b/README.md index ba5c8dec94..7fc75e84ae 100644 --- a/README.md +++ b/README.md @@ -279,3 +279,55 @@ pip3 install meson Note that Meson is written entirely in Python, so you can also run it as-is from the [git repository](https://github.com/mesonbuild/meson/) if you want to use the latest master branch for some reason. + + +### Setup a mingw/wine based development environment on linux + +#### Install wine and mingw + +##### On fedora x64 + +``` sh +sudo dnf install mingw64-gcc mingw64-gcc-c++ mingw64-pkg-config mingw64-winpthreads wine +``` + +FIXME: Figure out what needs to be installed on other distros + +#### Get meson from git + +This simplifies the process and allows us to use the cross files +defined in meson itself. + +``` sh +git clone https://github.com/mesonbuild/meson.git +``` + +#### Build and install + +``` +BUILDDIR=$PWD/winebuild/ +export WINEPREFIX=$BUILDDIR/wine-prefix/ && mkdir -p $WINEPREFIX +# Setting the prefix is mandatory as it is used to setup symlinks during uninstalled development +meson/meson.py $BUILDDIR --cross-file meson/cross/linux-mingw-w64-64bit.txt -Dgst-plugins-bad:vulkan=disabled -Dorc:gtk_doc=disabled --prefix=$BUILDDIR/wininstall/ -Djson-glib:gtk_doc=disabled +meson/meson.py install -C $BUILDDIR/ +``` + +> __NOTE__: You should use `meson install -C $BUILDDIR` each time you make a change +> instead of the usual `ninja -C build` as the environment is not uninstalled. + +#### The development environment + +You can get into the development environment the usual way: + +``` +ninja -C $BUILDDIR/ devenv +``` + +After setting up [binfmt] to use wine for windows binaries, +you can run GStreamer tools under wine by running: + +``` +gst-launch-1.0.exe videotestsrc ! glimagesink +``` + +[binfmt]: http://man7.org/linux/man-pages/man5/binfmt.d.5.html \ No newline at end of file diff --git a/gst-env.py b/gst-env.py index 8668973efb..06f04ae0d5 100755 --- a/gst-env.py +++ b/gst-env.py @@ -19,6 +19,7 @@ from distutils.util import strtobool from scripts.common import get_meson from scripts.common import git from scripts.common import win32_get_short_path_name +from scripts.common import get_wine_shortpath SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)) PREFIX_DIR = os.path.join(SCRIPTDIR, 'prefix') @@ -88,29 +89,53 @@ def is_library_target_and_not_plugin(target, filename): return True +def get_wine_subprocess_env(options, env): + with open(os.path.join(options.builddir, 'meson-info', 'intro-buildoptions.json')) as f: + buildoptions = json.load(f) + + prefix, = [o for o in buildoptions if o['name'] == 'prefix'] + path = os.path.normpath(os.path.join(prefix['value'], 'bin')) + prepend_env_var(env, "PATH", path, options.sysroot) + wine_path = get_wine_shortpath( + options.wine.split(' '), + [path] + env.get('WINEPATH', '').split(';') + ) + if options.winepath: + wine_path += ';' + options.winepath + env['WINEPATH'] = wine_path + env['WINEDEBUG'] = 'fixme-all' + + return env + + def get_subprocess_env(options, gst_version): env = os.environ.copy() env["CURRENT_GST"] = os.path.normpath(SCRIPTDIR) + env["GST_VERSION"] = gst_version env["GST_VALIDATE_SCENARIOS_PATH"] = os.path.normpath( "%s/subprojects/gst-devtools/validate/data/scenarios" % SCRIPTDIR) env["GST_VALIDATE_PLUGIN_PATH"] = os.path.normpath( "%s/subprojects/gst-devtools/validate/plugins" % options.builddir) env["GST_VALIDATE_APPS_DIR"] = os.path.normpath( "%s/subprojects/gst-editing-services/tests/validate" % SCRIPTDIR) + env["GST_ENV"] = 'gst-' + gst_version + env["GST_REGISTRY"] = os.path.normpath(options.builddir + "/registry.dat") prepend_env_var(env, "PATH", os.path.normpath( "%s/subprojects/gst-devtools/validate/tools" % options.builddir), options.sysroot) + + if options.wine: + return get_wine_subprocess_env(options, env) + prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'meson'), options.sysroot) - env["GST_VERSION"] = gst_version - env["GST_ENV"] = 'gst-' + gst_version + env["GST_PLUGIN_SYSTEM_PATH"] = "" env["GST_PLUGIN_SCANNER"] = os.path.normpath( "%s/subprojects/gstreamer/libs/gst/helpers/gst-plugin-scanner" % options.builddir) env["GST_PTP_HELPER"] = os.path.normpath( "%s/subprojects/gstreamer/libs/gst/helpers/gst-ptp-helper" % options.builddir) - env["GST_REGISTRY"] = os.path.normpath(options.builddir + "/registry.dat") if os.name is 'nt': lib_path_envvar = 'PATH' @@ -285,6 +310,12 @@ if __name__ == "__main__": parser.add_argument("--sysroot", default='', help="The sysroot path used during cross-compilation") + parser.add_argument("--wine", + default='', + help="Build a wine env based on specified wine command") + parser.add_argument("--winepath", + default='', + help="Exra path to set to WINEPATH.") options, args = parser.parse_known_args() if not os.path.exists(options.builddir): @@ -302,6 +333,9 @@ if __name__ == "__main__": gst_version = git("rev-parse", "--symbolic-full-name", "--abbrev-ref", "HEAD", repository_path=options.srcdir).strip('\n') + if options.wine: + gst_version += '-' + os.path.basename(options.wine) + if not args: if os.name is 'nt': shell = get_windows_shell() diff --git a/gst-uninstalled.py b/gst-uninstalled.py new file mode 120000 index 0000000000..2025ace645 --- /dev/null +++ b/gst-uninstalled.py @@ -0,0 +1 @@ +gst-env.py \ No newline at end of file diff --git a/meson.build b/meson.build index 4b75b41434..e64c5b0a3e 100644 --- a/meson.build +++ b/meson.build @@ -172,6 +172,16 @@ setenv = find_program('gst-env.py') devenv_cmd = [setenv, '--builddir=@0@'.format(meson.build_root()), '--srcdir=@0@'.format(meson.source_root())] +if meson.has_exe_wrapper() and build_machine.system() == 'linux' and host_machine.system() == 'windows' + # FIXME: Ideally we could get the wrapper directly from meson + devenv_cmd += ['--wine', host_machine.cpu_family() == 'x86_64' ? 'wine64' : 'wine32'] + sysroot = meson.get_cross_property('sys_root') + if sysroot != '' + # Logic from meson + devenv_cmd += ['--winepath', 'Z:' + join_paths(sysroot, 'bin')] + endif +endif + run_target('uninstalled', command : devenv_cmd) run_target('devenv', command : devenv_cmd) diff --git a/scripts/common.py b/scripts/common.py index 5cea742027..4fea527359 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -5,6 +5,7 @@ import shutil import argparse import platform import subprocess +import uuid ROOTDIR = os.path.abspath(os.path.dirname(__file__)) @@ -31,6 +32,33 @@ def win32_get_short_path_name(long_name): else: output_buf_size = needed + +def get_wine_shortpath(winecmd, wine_paths): + seen = set() + wine_paths += [p for p in wine_paths if not (p in seen or seen.add(p))] + + getShortPathScript = '%s.bat' % str(uuid.uuid4()).lower()[:5] + with open(getShortPathScript, mode='w') as f: + f.write("@ECHO OFF\nfor %%x in (%*) do (\n echo|set /p=;%~sx\n)\n") + f.flush() + try: + with open(os.devnull, 'w') as stderr: + wine_path = subprocess.check_output( + winecmd + + ['cmd', '/C', getShortPathScript] + wine_paths, + stderr=stderr).decode('utf-8') + except subprocess.CalledProcessError as e: + print("Could not get short paths: %s" % e) + wine_path = ';'.join(wine_paths) + finally: + os.remove(getShortPathScript) + if len(wine_path) > 2048: + raise AssertionError('WINEPATH size {} > 2048' + ' this will cause random failure.'.format( + len(wine_path))) + return wine_path + + class Colors: HEADER = '\033[95m' OKBLUE = '\033[94m'