trying to patch yabridge

This commit is contained in:
Matt Nish-Lapidus 2025-06-20 15:44:46 -04:00
parent b5337a73b4
commit d048a0ae76
6 changed files with 1091 additions and 0 deletions

View file

@ -0,0 +1,41 @@
diff --git a/meson.build b/meson.build
index 9e69128d..8c53ac88 100644
--- a/meson.build
+++ b/meson.build
@@ -226,7 +226,7 @@ if is_64bit_system
xcb_64bit_dep = dependency('xcb')
endif
if with_32bit_libraries or with_bitbridge
- xcb_32bit_dep = winegcc.find_library('xcb')
+ xcb_32bit_dep = winegcc.find_library('xcb', dirs: ['@libxcb32@/lib'])
endif
# These are all headers-only libraries, and thus won't require separate 32-bit
diff --git a/src/common/notifications.cpp b/src/common/notifications.cpp
index 654b6c83..78ba2fe7 100644
--- a/src/common/notifications.cpp
+++ b/src/common/notifications.cpp
@@ -29,8 +29,8 @@
#include "process.h"
#include "utils.h"
-constexpr char libdbus_library_name[] = "libdbus-1.so.3";
-constexpr char libdbus_library_fallback_name[] = "libdbus-1.so";
+constexpr char libdbus_library_name[] = "@libdbus@/lib/libdbus-1.so.3";
+constexpr char libdbus_library_fallback_name[] = "@libdbus@/lib/libdbus-1.so";
std::atomic<void*> libdbus_handle = nullptr;
std::mutex libdbus_mutex;
diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp
index 441345c6..f3e51cff 100644
--- a/src/plugin/utils.cpp
+++ b/src/plugin/utils.cpp
@@ -103,7 +103,7 @@ std::string PluginInfo::wine_version() const {
// The '*.exe' scripts generated by winegcc allow you to override the binary
// used to run Wine, so will will handle this in the same way for our Wine
// version detection. We'll be using `execvpe`
- std::string wine_path = "wine";
+ std::string wine_path = "@wine@/bin/wine";
// NOLINTNEXTLINE(concurrency-mt-unsafe)
if (const char* wineloader_path = getenv("WINELOADER");
wineloader_path && access(wineloader_path, X_OK) == 0) {

View file

@ -0,0 +1,71 @@
diff --git a/src/chainloader/utils.cpp b/src/chainloader/utils.cpp
index fa90b8f7..bd44d0ea 100644
--- a/src/chainloader/utils.cpp
+++ b/src/chainloader/utils.cpp
@@ -29,8 +29,10 @@
namespace fs = ghc::filesystem;
void* find_plugin_library(const std::string& name) {
+ Logger logger = Logger::create_exception_logger();
+
// Just using a goto for this would probably be cleaner, but yeah...
- const auto impl = [&name]() -> void* {
+ const auto impl = [&name, &logger]() -> void* {
// If `name` exists right next to the Wine plugin host binary, then
// we'll try loading that. Otherwise we'll fall back to regular
// `dlopen()` for distro packaged versions of yabridge
@@ -52,27 +54,28 @@ void* find_plugin_library(const std::string& name) {
}
}
- if (void* handle = dlopen(name.c_str(), RTLD_LAZY | RTLD_LOCAL)) {
- return handle;
+ auto nix_profiles = getenv("NIX_PROFILES");
+ if (!nix_profiles || nix_profiles[0] == '\0') {
+ logger.log("");
+ logger.log("ERROR: 'NIX_PROFILES' environment variable is not set");
+ logger.log("");
+ return nullptr;
}
- // One last Hail Mary, in case ldconfig was not set up correctly. This
- // might be relevant for some of the `/usr/local/*` locations (although
- // you really, really shouldn't install yabridge there, please, thank
- // you). Yabridgectl searches through these same directories.
- for (const auto& lib_dir : {
- "/usr/lib",
- "/usr/lib/x86_64-linux-gnu",
- "/usr/lib64",
- "/usr/local/lib",
- "/usr/local/lib/x86_64-linux-gnu",
- "/usr/local/lib64",
- }) {
- const fs::path candidate = fs::path(lib_dir) / name;
- if (void* handle =
- dlopen(candidate.c_str(), RTLD_LAZY | RTLD_LOCAL)) {
+ // NIX_PROFILES is iterated in reverse from the most specific (the
+ // user profile) to the least specific (the system profile).
+ const std::string_view nix_profiles_view = nix_profiles;
+ auto segment_end = nix_profiles_view.size();
+ while (segment_end != std::string::npos) {
+ const auto next_segment_end = nix_profiles_view.rfind(' ', segment_end - 1);
+ const auto segment_begin = next_segment_end + 1;
+ const auto profile = nix_profiles_view.substr(segment_begin, segment_end - segment_begin);
+ const auto candidate = fs::path(profile) / "lib" / name;
+ if (auto handle = dlopen(candidate.c_str(), RTLD_LAZY | RTLD_LOCAL)) {
return handle;
}
+
+ segment_end = next_segment_end;
}
return nullptr;
@@ -82,8 +85,6 @@ void* find_plugin_library(const std::string& name) {
if (!handle) {
const fs::path this_plugin_path = get_this_file_location();
- Logger logger = Logger::create_exception_logger();
-
logger.log("");
logger.log("Could not find '" + name + "'");
logger.log("");

385
overlays/meson-p.build Normal file
View file

@ -0,0 +1,385 @@
project(
'yabridge',
'cpp',
version : '5.1.1',
meson_version : '>=0.56',
default_options : [
'warning_level=3',
'cpp_std=c++2a',
# Even though Meson will complain that this option does not exist, without
# this Meson will not apply the above option to native targets
'build.cpp_std=c++2a',
],
)
#
# Build options
#
# In theory yabridge should compile fine on a 32-bit system, but you will always
# need to pass `-Dbitbridge=true`. We just make sure that we won't build
# any 64-bit binaries in that situation.
is_64bit_system = build_machine.cpu_family() not in ['x86', 'arm']
with_bitbridge = get_option('bitbridge')
with_clap = get_option('clap')
with_winedbg = get_option('winedbg')
with_vst3 = get_option('vst3')
#
# Compiler flags
#
# Depending on the `bitbridge` flag we'll enable building secondary 32-bit
# host applications that can act as a bit bridge for using 32-bit Windows
# plugins in 64-bit Linux VST hosts. The plugin will determine which host
# application to use based on the `.dll` file it's trying to load. This setup is
# necessary until Meson provides a way to have multiple cross-builds for a
# single build directory: https://github.com/mesonbuild/meson/issues/5125
# These variables are used to generate a `config.h` file. The library names will
# be prefixed with `lib` and suffixed with `.so`, and the host names will be
# suffixed with `.exe`.
clap_plugin_name = 'yabridge-clap'
vst2_plugin_name = 'yabridge-vst2'
vst3_plugin_name = 'yabridge-vst3'
host_name_64bit = 'yabridge-host'
host_name_32bit = 'yabridge-host-32'
compiler_options = [
'-fvisibility=hidden',
'-fvisibility-inlines-hidden',
# We use an intrinsic to force flush-to-zero. SSE2 is always enabled in x86_64
# CPUs, but when we're compiling the 32-bit bitbridge we need to manually add
# this flag.
'-msse2',
# FIXME: Bitsery relies on the definitions from `<cstdint>`, which is no
# longer included transitively with GCC 13. This should be removed once
# bitsery is updated to support GCC 13.
'-include',
'cstdint',
]
chainloader_compiler_options = [
# We use our process library for sending notifications from the chainloaders,
# but we don't need the Asio pipe support there
'-DWITHOUT_ASIO',
]
# HACK: Some stuff from `windows.h` that we don't need results in conflicting
# definitions, so we'll try to exclude those bits
wine_compiler_options = [
'-DNOMINMAX',
# Since Wine 5.12 any use of attributes (like visibility specifiers, or
# calling conventions) in templated member or variable types causes a warning
'-Wno-attributes',
'-Wno-ignored-attributes',
# Winsock conflicts with the Posix sockets API. Before Wine 6.8 there was a
# `WINE_NOWINSOCK` that would exclude just `winsock.h` from `windows.h`, but
# they got rid of that so we now need to explicitly define the ifdef guards
'-D__WINE_WINSOCKAPI_STDLIB_H',
'-D_WINSOCKAPI_',
# This is only relevant for Wine 6.2, but commit
# `0c19e2e487d36a89531daf4897c0b6390d82a843`, broke compilation of
# `shobjidl.h` under C++.
#
# https://bugs.winehq.org/show_bug.cgi?id=50670
'-D__IFileOperation_INTERFACE_DEFINED__',
# This Wine 6.20 commit `dfdf56fbe47f8ff50ebe533e6d73f2de6546f008` added a
# bunch of new SAL includes to `windows.h`, which include things like `__in`
# and `__out`. This breaks libstdc++ compilation since they often use those
# names for function parameters.
#
# https://bugs.winehq.org/show_bug.cgi?id=51919
'-D__WINE_SAL_H__',
]
# NOTE: GCC doesn't 8-byte align doubles in structs on x86 for ABI-compatibilty
# reasons, but MSVC++ does. We need to force this same alignment to be
# ABI-compatible with 32-bit binaries created with MSVC++ on Windows.
wine_32bit_compiler_options = wine_compiler_options + ['-m32', '-malign-double']
wine_64bit_compiler_options = wine_compiler_options + ['-m64']
# Enable addition assertions on the STL containers during debug builds. Meson
# has a `cpp_debugstl` option, but it's nicer having this automatically tied to
# debug builds.
if get_option('buildtype') == 'debug'
compiler_options += ['-D_GLIBCXX_DEBUG']
endif
if with_bitbridge
compiler_options += '-DWITH_BITBRIDGE'
endif
if with_clap
compiler_options += '-DWITH_CLAP'
endif
# This provides an easy way to start the Wine plugin host using winedbg since it
# can be quite a pain to set up
if with_winedbg
compiler_options += '-DWITH_WINEDBG'
endif
if with_vst3
compiler_options += '-DWITH_VST3'
endif
#
# Wine checks
#
# Meson does not let us set a default cross compiler, which makes sense, but it
# also means that it's easy to forget. This will cause the setup process to
# abort if no cross compiler has been set up.
winelib_check = '''#ifndef __WINE__
#error 1
#endif'''
if not meson.get_compiler('cpp').compiles(winelib_check)
error('You need to set up a cross compiler, check the README for compilation instructions.')
endif
# Wine versions after Wine 5.6 and before 6.0 require a `__cdecl` calling
# convention to be specified on the `main()` functions or else `argc` and `argv`
# will point to the wrong memory. Similarly, with other versions of Wine this
# should _not_ be specified for the same reason. We'll try to figure out the
# current Wine version and add this calling convention based on that. Also,
# printing the configure-time Wine version might be useful in diagnosing build
# issues so we'll do just that.
#
# https://bugs.winehq.org/show_bug.cgi?id=49138
wine_version = run_command(
'sh', '-c', '''wine --version | grep --only-matching -E '[0-9]+\.[0-9]+(-?rc[0-9]+)?' | head -n1''',
check : false
)
if wine_version.returncode() == 0
wine_version = wine_version.stdout()
message('Targetting Wine @0@'.format(wine_version))
# Wine versions below 5.7 will segfault in `CoCreateGuid` which gets called
# during static initialization. I'm not exactly sure why this is happening,
# but to prevent this from causing more headaches and confusion in the future
# we should just immediately error out when building yabridge's VST3 support
# with these older Wine versions.
if wine_version.version_compare('<5.7') and with_vst3
error('Because of a bug in Wine < 5.7\n' +
'you cannot build yabridge with VST3 support using these older Wine versions.\n' +
'Use the \'-Dvst3=false\' build option to disable VST3 support.\n\n' +
'https://github.com/robbert-vdh/yabridge/issues/63#issuecomment-757369645')
endif
# This version of yabridge will not work when built against Wine 7.21, 7.22,
# or 8.0-rc1 because of https://bugs.winehq.org/show_bug.cgi?id=53912. We'll
# outright prevent building yabridge with these versions to avoid broken
# yabridge builds. If anyone's reading this because you ran into the error
# below, either build with Wine 8.0-rc2+, or stick with yabridge 5.0.2 if
# you're stuck with Wine 7.22.
# NOTE: Meson considers 8.0 to be below 8.0rc2, so this third check is also
# needed
if wine_version.version_compare('>=7.21') and \
wine_version.version_compare('<8.0rc2') and \
wine_version.version_compare('!=8.0')
error('Building this version of yabridge against Wine ' + wine_version +
'would result in nonfunctional binaries. Either build yabridge 5.0.2 ' +
'with Wine 7.22, or switch to Wine 8.0-rc2+. Yabridge built with 8.0-rc2+ ' +
'will also work with older Wine versions, but yabridge built against older ' +
'Wine versions will not work with Wine 7.21+.\n\n' +
'https://bugs.winehq.org/show_bug.cgi?id=53912')
endif
if wine_version.version_compare('>=5.7') and \
wine_version.version_compare('<6.0')
message('- Using the cdecl calling convention')
compiler_options += '-DWINE_USE_CDECL'
endif
if wine_version.version_compare('<6.23') and with_winedbg
message('- Using legacy winedbg argument quoting')
compiler_options += '-DWINEDBG_LEGACY_ARGUMENT_QUOTING'
endif
else
warning('Unable to determine the current Wine version')
endif
#
# Dependencies
#
include_dir = include_directories('src/include', is_system : true)
# These dependencies require separate linking flags for the 32-bit and 64-bit
# versions
# I honestly have no idea what the correct way is to have `dependency()` or
# `compiler.find_dependency()` search for 32-bit versions of libraries when
# cross-compiling. Meson also doesn't seem to respect the default linker
# search path set by the system in `find_library()`. If anyone does know how
# to properly do this, please let me know!
winegcc = meson.get_compiler('cpp', native : false)
if is_64bit_system
xcb_64bit_dep = dependency('xcb')
endif
if with_bitbridge
xcb_32bit_dep = winegcc.find_library('xcb', dirs: ['@libxcb32@/lib'])
endif
# These are all headers-only libraries, and thus won't require separate 32-bit
# and 64-bit versions
asio_dep = dependency('asio', version : '>=1.28.0')
if meson.version().version_compare('>=0.60')
# Bitsery's CMake build definition is capitalized for some reason
bitsery_dep = dependency('bitsery', 'Bitsery', version : '>=5.2.0')
else
# Mmeson <=0.6.0 didn't support multiple names for a dependency, and since at
# the moment this is only relevant for packing on Arch btw, it's probably
# better to remove this conditional later than it is to bump the minimum Meson
# version now.
bitsery_dep = dependency('bitsery', version : '>=5.2.0')
endif
# The D-Bus headers are also only accessed through the include path. We don't
# link to libdbus-1 to make soname changes don't completely break yabridge.
dbus_dep = dependency('dbus-1').partial_dependency(compile_args : true, includes : true)
function2_dep = dependency('function2', version : '>=4.0.0')
ghc_filesystem_dep = dependency('ghc_filesystem', modules : 'ghcFilesystem::ghc_filesystem', version : '>=1.5.0')
threads_dep = dependency('threads')
# Tomlplusplus recently added a shraed library version. We don't want to link to
# that. `compile_library` is deprecated but it (incorrectly) defaults to `true`
# so we can't omit it.
tomlplusplus_dep = dependency('tomlplusplus', version : '>=3.4.0', default_options : ['compile_library=false']).partial_dependency(compile_args : true, includes : true)
dl_dep = declare_dependency(link_args : '-ldl')
rt_dep = declare_dependency(link_args : '-lrt')
wine_ole32_dep = declare_dependency(link_args : '-lole32')
# The SDK includes a comment pragma that would link to this on MSVC
wine_shell32_dep = declare_dependency(link_args : '-lshell32')
# The built in threads dependency does not know how to handle winegcc
wine_threads_dep = declare_dependency(link_args : '-lpthread')
wine_uuid_dep = declare_dependency(link_args : '-luuid')
if with_clap
clap_dep = dependency('clap', version : ['>=1.1.7', '<1.2'])
endif
# We need to build the VST3 SDK dependencies in tree because Meson won't let us
# build both native, 32-bit cross compiled and 64-bit cross compiled
# dependencies from a (CMake) subproject
if with_vst3
subdir('src/common/vst3')
endif
#
# Binaries
#
# The application consists of a plugin (`libyabridge-{clap,vst2,vst3}.so`) that calls
# a Winelib application (`yabridge-host{,-32}.exe`) that can host Windows VST2
# and VST3 plugins. These plugins can in turn be loaded from small stub
# libraries dubbed chainloaders to avoid having to copy large plugin libraries
# around. More information about the way these two components work together can
# be found in `docs/architecture.md`.
#
# Generate header files for configuration variables such as the current git tag
# and the name of the host binary
subdir('src/common/config')
# These only contain the definitions for sources and dependencies. It would be
# nice to define the libraries and executables inside of these meson.build
# files, but that will also scatter the build artifacts around in the `build/`
# directory and it's much more convenient having all of the important files
# directory under `build/`.
# https://github.com/mesonbuild/meson/pull/4037
subdir('src/chainloader')
subdir('src/plugin')
subdir('src/wine-host')
shared_library(
vst2_plugin_name,
vst2_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : vst2_plugin_deps,
# NOTE: LTO does not support Winelibs, and it seems to break
# `libyabridge-vst2.so` in Bitwig for some reason. It should be left
# turned off for the time being except for on the chainloader
# libraries.
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-vst2',
vst2_chainloader_sources,
native : true,
dependencies : chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# LTO is useful here to get rid of unused code
override_options : ['b_lto=true'],
)
if with_clap
# This is the CLAP equivalent of `libyabridge-vst2.so`. The Wine host
# applications can handle VST2, VST3, and CLAP plugins.
shared_library(
clap_plugin_name,
clap_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : clap_plugin_deps,
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-clap',
clap_chainloader_sources,
native : true,
dependencies : clap_chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# See above
override_options : ['b_lto=true'],
)
endif
if with_vst3
# This is the VST3 equivalent of `libyabridge-vst2.so`. The Wine host
# applications can handle both VST2, VST3 and CLAP plugins.
shared_library(
vst3_plugin_name,
vst3_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : vst3_plugin_deps,
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-vst3',
vst3_chainloader_sources,
native : true,
dependencies : chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# See above
override_options : ['b_lto=true'],
)
endif
if is_64bit_system
executable(
host_name_64bit,
host_sources,
native : false,
include_directories : include_dir,
dependencies : host_64bit_deps,
cpp_args : compiler_options + wine_64bit_compiler_options,
link_args : ['-m64'],
)
endif
if with_bitbridge
executable(
host_name_32bit,
host_sources,
native : false,
include_directories : include_dir,
dependencies : host_32bit_deps,
cpp_args : compiler_options + wine_32bit_compiler_options,
link_args : ['-m32'],
)
endif

385
overlays/meson.build Normal file
View file

@ -0,0 +1,385 @@
project(
'yabridge',
'cpp',
version : '5.1.1',
meson_version : '>=0.56',
default_options : [
'warning_level=3',
'cpp_std=c++2a',
# Even though Meson will complain that this option does not exist, without
# this Meson will not apply the above option to native targets
'build.cpp_std=c++2a',
],
)
#
# Build options
#
# In theory yabridge should compile fine on a 32-bit system, but you will always
# need to pass `-Dbitbridge=true`. We just make sure that we won't build
# any 64-bit binaries in that situation.
is_64bit_system = build_machine.cpu_family() not in ['x86', 'arm']
with_bitbridge = get_option('bitbridge')
with_clap = get_option('clap')
with_winedbg = get_option('winedbg')
with_vst3 = get_option('vst3')
#
# Compiler flags
#
# Depending on the `bitbridge` flag we'll enable building secondary 32-bit
# host applications that can act as a bit bridge for using 32-bit Windows
# plugins in 64-bit Linux VST hosts. The plugin will determine which host
# application to use based on the `.dll` file it's trying to load. This setup is
# necessary until Meson provides a way to have multiple cross-builds for a
# single build directory: https://github.com/mesonbuild/meson/issues/5125
# These variables are used to generate a `config.h` file. The library names will
# be prefixed with `lib` and suffixed with `.so`, and the host names will be
# suffixed with `.exe`.
clap_plugin_name = 'yabridge-clap'
vst2_plugin_name = 'yabridge-vst2'
vst3_plugin_name = 'yabridge-vst3'
host_name_64bit = 'yabridge-host'
host_name_32bit = 'yabridge-host-32'
compiler_options = [
'-fvisibility=hidden',
'-fvisibility-inlines-hidden',
# We use an intrinsic to force flush-to-zero. SSE2 is always enabled in x86_64
# CPUs, but when we're compiling the 32-bit bitbridge we need to manually add
# this flag.
'-msse2',
# FIXME: Bitsery relies on the definitions from `<cstdint>`, which is no
# longer included transitively with GCC 13. This should be removed once
# bitsery is updated to support GCC 13.
'-include',
'cstdint',
]
chainloader_compiler_options = [
# We use our process library for sending notifications from the chainloaders,
# but we don't need the Asio pipe support there
'-DWITHOUT_ASIO',
]
# HACK: Some stuff from `windows.h` that we don't need results in conflicting
# definitions, so we'll try to exclude those bits
wine_compiler_options = [
'-DNOMINMAX',
# Since Wine 5.12 any use of attributes (like visibility specifiers, or
# calling conventions) in templated member or variable types causes a warning
'-Wno-attributes',
'-Wno-ignored-attributes',
# Winsock conflicts with the Posix sockets API. Before Wine 6.8 there was a
# `WINE_NOWINSOCK` that would exclude just `winsock.h` from `windows.h`, but
# they got rid of that so we now need to explicitly define the ifdef guards
'-D__WINE_WINSOCKAPI_STDLIB_H',
'-D_WINSOCKAPI_',
# This is only relevant for Wine 6.2, but commit
# `0c19e2e487d36a89531daf4897c0b6390d82a843`, broke compilation of
# `shobjidl.h` under C++.
#
# https://bugs.winehq.org/show_bug.cgi?id=50670
'-D__IFileOperation_INTERFACE_DEFINED__',
# This Wine 6.20 commit `dfdf56fbe47f8ff50ebe533e6d73f2de6546f008` added a
# bunch of new SAL includes to `windows.h`, which include things like `__in`
# and `__out`. This breaks libstdc++ compilation since they often use those
# names for function parameters.
#
# https://bugs.winehq.org/show_bug.cgi?id=51919
'-D__WINE_SAL_H__',
]
# NOTE: GCC doesn't 8-byte align doubles in structs on x86 for ABI-compatibilty
# reasons, but MSVC++ does. We need to force this same alignment to be
# ABI-compatible with 32-bit binaries created with MSVC++ on Windows.
wine_32bit_compiler_options = wine_compiler_options + ['-m32', '-malign-double']
wine_64bit_compiler_options = wine_compiler_options + ['-m64']
# Enable addition assertions on the STL containers during debug builds. Meson
# has a `cpp_debugstl` option, but it's nicer having this automatically tied to
# debug builds.
if get_option('buildtype') == 'debug'
compiler_options += ['-D_GLIBCXX_DEBUG']
endif
if with_bitbridge
compiler_options += '-DWITH_BITBRIDGE'
endif
if with_clap
compiler_options += '-DWITH_CLAP'
endif
# This provides an easy way to start the Wine plugin host using winedbg since it
# can be quite a pain to set up
if with_winedbg
compiler_options += '-DWITH_WINEDBG'
endif
if with_vst3
compiler_options += '-DWITH_VST3'
endif
#
# Wine checks
#
# Meson does not let us set a default cross compiler, which makes sense, but it
# also means that it's easy to forget. This will cause the setup process to
# abort if no cross compiler has been set up.
winelib_check = '''#ifndef __WINE__
#error 1
#endif'''
if not meson.get_compiler('cpp').compiles(winelib_check)
error('You need to set up a cross compiler, check the README for compilation instructions.')
endif
# Wine versions after Wine 5.6 and before 6.0 require a `__cdecl` calling
# convention to be specified on the `main()` functions or else `argc` and `argv`
# will point to the wrong memory. Similarly, with other versions of Wine this
# should _not_ be specified for the same reason. We'll try to figure out the
# current Wine version and add this calling convention based on that. Also,
# printing the configure-time Wine version might be useful in diagnosing build
# issues so we'll do just that.
#
# https://bugs.winehq.org/show_bug.cgi?id=49138
wine_version = run_command(
'sh', '-c', '''wine --version | grep --only-matching -E '[0-9]+\.[0-9]+(-?rc[0-9]+)?' | head -n1''',
check : false
)
if wine_version.returncode() == 0
wine_version = wine_version.stdout()
message('Targetting Wine @0@'.format(wine_version))
# Wine versions below 5.7 will segfault in `CoCreateGuid` which gets called
# during static initialization. I'm not exactly sure why this is happening,
# but to prevent this from causing more headaches and confusion in the future
# we should just immediately error out when building yabridge's VST3 support
# with these older Wine versions.
if wine_version.version_compare('<5.7') and with_vst3
error('Because of a bug in Wine < 5.7\n' +
'you cannot build yabridge with VST3 support using these older Wine versions.\n' +
'Use the \'-Dvst3=false\' build option to disable VST3 support.\n\n' +
'https://github.com/robbert-vdh/yabridge/issues/63#issuecomment-757369645')
endif
# This version of yabridge will not work when built against Wine 7.21, 7.22,
# or 8.0-rc1 because of https://bugs.winehq.org/show_bug.cgi?id=53912. We'll
# outright prevent building yabridge with these versions to avoid broken
# yabridge builds. If anyone's reading this because you ran into the error
# below, either build with Wine 8.0-rc2+, or stick with yabridge 5.0.2 if
# you're stuck with Wine 7.22.
# NOTE: Meson considers 8.0 to be below 8.0rc2, so this third check is also
# needed
if wine_version.version_compare('>=7.21') and \
wine_version.version_compare('<8.0rc2') and \
wine_version.version_compare('!=8.0')
error('Building this version of yabridge against Wine ' + wine_version +
'would result in nonfunctional binaries. Either build yabridge 5.0.2 ' +
'with Wine 7.22, or switch to Wine 8.0-rc2+. Yabridge built with 8.0-rc2+ ' +
'will also work with older Wine versions, but yabridge built against older ' +
'Wine versions will not work with Wine 7.21+.\n\n' +
'https://bugs.winehq.org/show_bug.cgi?id=53912')
endif
if wine_version.version_compare('>=5.7') and \
wine_version.version_compare('<6.0')
message('- Using the cdecl calling convention')
compiler_options += '-DWINE_USE_CDECL'
endif
if wine_version.version_compare('<6.23') and with_winedbg
message('- Using legacy winedbg argument quoting')
compiler_options += '-DWINEDBG_LEGACY_ARGUMENT_QUOTING'
endif
else
warning('Unable to determine the current Wine version')
endif
#
# Dependencies
#
include_dir = include_directories('src/include', is_system : true)
# These dependencies require separate linking flags for the 32-bit and 64-bit
# versions
# I honestly have no idea what the correct way is to have `dependency()` or
# `compiler.find_dependency()` search for 32-bit versions of libraries when
# cross-compiling. Meson also doesn't seem to respect the default linker
# search path set by the system in `find_library()`. If anyone does know how
# to properly do this, please let me know!
winegcc = meson.get_compiler('cpp', native : false)
if is_64bit_system
xcb_64bit_dep = dependency('xcb')
endif
if with_bitbridge
xcb_32bit_dep = winegcc.find_library('xcb')
endif
# These are all headers-only libraries, and thus won't require separate 32-bit
# and 64-bit versions
asio_dep = dependency('asio', version : '>=1.28.0')
if meson.version().version_compare('>=0.60')
# Bitsery's CMake build definition is capitalized for some reason
bitsery_dep = dependency('bitsery', 'Bitsery', version : '>=5.2.0')
else
# Mmeson <=0.6.0 didn't support multiple names for a dependency, and since at
# the moment this is only relevant for packing on Arch btw, it's probably
# better to remove this conditional later than it is to bump the minimum Meson
# version now.
bitsery_dep = dependency('bitsery', version : '>=5.2.0')
endif
# The D-Bus headers are also only accessed through the include path. We don't
# link to libdbus-1 to make soname changes don't completely break yabridge.
dbus_dep = dependency('dbus-1').partial_dependency(compile_args : true, includes : true)
function2_dep = dependency('function2', version : '>=4.0.0')
ghc_filesystem_dep = dependency('ghc_filesystem', modules : 'ghcFilesystem::ghc_filesystem', version : '>=1.5.0')
threads_dep = dependency('threads')
# Tomlplusplus recently added a shraed library version. We don't want to link to
# that. `compile_library` is deprecated but it (incorrectly) defaults to `true`
# so we can't omit it.
tomlplusplus_dep = dependency('tomlplusplus', version : '>=3.4.0', default_options : ['compile_library=false']).partial_dependency(compile_args : true, includes : true)
dl_dep = declare_dependency(link_args : '-ldl')
rt_dep = declare_dependency(link_args : '-lrt')
wine_ole32_dep = declare_dependency(link_args : '-lole32')
# The SDK includes a comment pragma that would link to this on MSVC
wine_shell32_dep = declare_dependency(link_args : '-lshell32')
# The built in threads dependency does not know how to handle winegcc
wine_threads_dep = declare_dependency(link_args : '-lpthread')
wine_uuid_dep = declare_dependency(link_args : '-luuid')
if with_clap
clap_dep = dependency('clap', version : ['>=1.1.7', '<1.2'])
endif
# We need to build the VST3 SDK dependencies in tree because Meson won't let us
# build both native, 32-bit cross compiled and 64-bit cross compiled
# dependencies from a (CMake) subproject
if with_vst3
subdir('src/common/vst3')
endif
#
# Binaries
#
# The application consists of a plugin (`libyabridge-{clap,vst2,vst3}.so`) that calls
# a Winelib application (`yabridge-host{,-32}.exe`) that can host Windows VST2
# and VST3 plugins. These plugins can in turn be loaded from small stub
# libraries dubbed chainloaders to avoid having to copy large plugin libraries
# around. More information about the way these two components work together can
# be found in `docs/architecture.md`.
#
# Generate header files for configuration variables such as the current git tag
# and the name of the host binary
subdir('src/common/config')
# These only contain the definitions for sources and dependencies. It would be
# nice to define the libraries and executables inside of these meson.build
# files, but that will also scatter the build artifacts around in the `build/`
# directory and it's much more convenient having all of the important files
# directory under `build/`.
# https://github.com/mesonbuild/meson/pull/4037
subdir('src/chainloader')
subdir('src/plugin')
subdir('src/wine-host')
shared_library(
vst2_plugin_name,
vst2_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : vst2_plugin_deps,
# NOTE: LTO does not support Winelibs, and it seems to break
# `libyabridge-vst2.so` in Bitwig for some reason. It should be left
# turned off for the time being except for on the chainloader
# libraries.
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-vst2',
vst2_chainloader_sources,
native : true,
dependencies : chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# LTO is useful here to get rid of unused code
override_options : ['b_lto=true'],
)
if with_clap
# This is the CLAP equivalent of `libyabridge-vst2.so`. The Wine host
# applications can handle VST2, VST3, and CLAP plugins.
shared_library(
clap_plugin_name,
clap_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : clap_plugin_deps,
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-clap',
clap_chainloader_sources,
native : true,
dependencies : clap_chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# See above
override_options : ['b_lto=true'],
)
endif
if with_vst3
# This is the VST3 equivalent of `libyabridge-vst2.so`. The Wine host
# applications can handle both VST2, VST3 and CLAP plugins.
shared_library(
vst3_plugin_name,
vst3_plugin_sources,
native : true,
include_directories : include_dir,
dependencies : vst3_plugin_deps,
cpp_args : compiler_options,
)
shared_library(
'yabridge-chainloader-vst3',
vst3_chainloader_sources,
native : true,
dependencies : chainloader_deps,
cpp_args : compiler_options + chainloader_compiler_options,
# See above
override_options : ['b_lto=true'],
)
endif
if is_64bit_system
executable(
host_name_64bit,
host_sources,
native : false,
include_directories : include_dir,
dependencies : host_64bit_deps,
cpp_args : compiler_options + wine_64bit_compiler_options,
link_args : ['-m64'],
)
endif
if with_bitbridge
executable(
host_name_32bit,
host_sources,
native : false,
include_directories : include_dir,
dependencies : host_32bit_deps,
cpp_args : compiler_options + wine_32bit_compiler_options,
link_args : ['-m32'],
)
endif

173
overlays/wine-6006.patch Normal file
View file

@ -0,0 +1,173 @@
From 23a6646d697ddfc51e3deab018853a22376dacdf Mon Sep 17 00:00:00 2001
From: Grazvydas Ignotas <notasas@gmail.com>
Date: Sun, 7 Jul 2024 00:11:26 +0300
Subject: [PATCH 1/2] dwmapi: Drop unnecessary static, improve variable names.
---
dlls/dwmapi/dwmapi_main.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c
index adc02552ba7..8d4ccbb1fc4 100644
--- a/dlls/dwmapi/dwmapi_main.c
+++ b/dlls/dwmapi/dwmapi_main.c
@@ -184,9 +184,9 @@ HRESULT WINAPI DwmEnableBlurBehindWindow(HWND hWnd, const DWM_BLURBEHIND *pBlurB
*/
BOOL WINAPI DwmDefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult)
{
- static int i;
+ static BOOL once;
- if (!i++) FIXME("stub\n");
+ if (!once++) FIXME("stub\n");
return FALSE;
}
@@ -273,7 +273,8 @@ static int get_display_frequency(void)
HRESULT WINAPI DwmGetCompositionTimingInfo(HWND hwnd, DWM_TIMING_INFO *info)
{
LARGE_INTEGER performance_frequency, qpc;
- static int i, display_frequency;
+ int display_frequency;
+ static BOOL once;
if (!info)
return E_INVALIDARG;
@@ -281,7 +282,7 @@ HRESULT WINAPI DwmGetCompositionTimingInfo(HWND hwnd, DWM_TIMING_INFO *info)
if (info->cbSize != sizeof(DWM_TIMING_INFO))
return MILERR_MISMATCHED_SIZE;
- if(!i++) FIXME("(%p %p)\n", hwnd, info);
+ if (!once++) FIXME("(%p %p)\n", hwnd, info);
memset(info, 0, info->cbSize);
info->cbSize = sizeof(DWM_TIMING_INFO);
--
GitLab
From 9bd6b35aa8d9b92593db1722ce533e0e4d8985ad Mon Sep 17 00:00:00 2001
From: Grazvydas Ignotas <notasas@gmail.com>
Date: Sun, 7 Jul 2024 00:18:40 +0300
Subject: [PATCH 2/2] dwmapi: Simulate DwmFlush blocking behavior.
The documentation states it's a blocking call. There are reports of it
being used for WaitForVBlank-like purposes [1]. Without blocking Softube
VST plugin logic breaks and they never update their UIs.
[1] https://news.ycombinator.com/item?id=34501612
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56935
---
dlls/dwmapi/dwmapi_main.c | 23 +++++++++++++++++++--
dlls/dwmapi/tests/dwmapi.c | 41 ++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c
index 8d4ccbb1fc4..419216534aa 100644
--- a/dlls/dwmapi/dwmapi_main.c
+++ b/dlls/dwmapi/dwmapi_main.c
@@ -32,6 +32,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(dwmapi);
+static int get_display_frequency(void);
/**********************************************************************
* DwmIsCompositionEnabled (DWMAPI.@)
@@ -88,9 +89,26 @@ HRESULT WINAPI DwmGetColorizationColor(DWORD *colorization, BOOL *opaque_blend)
*/
HRESULT WINAPI DwmFlush(void)
{
+ static volatile LONG last_time;
static BOOL once;
+ DWORD now, interval, last = last_time, target;
+ int freq;
- if (!once++) FIXME("() stub\n");
+ if (!once++) FIXME("() semi-stub\n");
+
+ // simulate the WaitForVBlank-like blocking behavior
+ freq = get_display_frequency();
+ interval = 1000 / freq;
+ now = GetTickCount();
+ if (now - last < interval)
+ target = last + interval;
+ else
+ {
+ // act as if we were called midway between 2 vsyncs
+ target = now + interval / 2;
+ }
+ Sleep(target - now);
+ InterlockedCompareExchange(&last_time, target, last);
return S_OK;
}
@@ -262,7 +280,8 @@ static int get_display_frequency(void)
}
else
{
- WARN("Failed to query display frequency, returning a fallback value.\n");
+ static BOOL once;
+ if (!once++) WARN("Failed to query display frequency, returning a fallback value.\n");
return 60;
}
}
diff --git a/dlls/dwmapi/tests/dwmapi.c b/dlls/dwmapi/tests/dwmapi.c
index a89a1fd705b..20628578f41 100644
--- a/dlls/dwmapi/tests/dwmapi.c
+++ b/dlls/dwmapi/tests/dwmapi.c
@@ -140,9 +140,50 @@ cleanup:
DestroyWindow(hwnd);
}
+static void test_DwmFlush(void)
+{
+ LARGE_INTEGER frequency, ts[2];
+ int i, result, ms;
+ DEVMODEA mode;
+ BOOL enabled;
+ HRESULT hr;
+
+ enabled = FALSE;
+ hr = DwmIsCompositionEnabled(&enabled);
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ if (!enabled)
+ {
+ skip("DWM is disabled.\n");
+ return;
+ }
+
+ memset(&mode, 0, sizeof(mode));
+ mode.dmSize = sizeof(mode);
+ result = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &mode);
+ ok(result, "Failed to get display mode %#lx.\n", GetLastError());
+ ok(mode.dmDisplayFrequency != 0, "dmDisplayFrequency is 0.\n");
+
+ result = QueryPerformanceFrequency(&frequency);
+ ok(result, "Failed to get performance counter frequency.\n");
+
+ result = QueryPerformanceCounter(&ts[0]);
+ ok(result, "Failed to read performance counter.\n");
+ for (i = 0; i < 2; i++)
+ {
+ hr = DwmFlush();
+ ok(hr == S_OK, "Got hr %#lx.\n", hr);
+ }
+ result = QueryPerformanceCounter(&ts[1]);
+ ok(result, "Failed to read performance counter.\n");
+ ms = (ts[1].QuadPart - ts[0].QuadPart) * 1000 / frequency.QuadPart;
+ ok(ms >= 1000 / mode.dmDisplayFrequency,
+ "DwmFlush() took %dms with dmDisplayFrequency %ld.\n", ms, mode.dmDisplayFrequency);
+}
+
START_TEST(dwmapi)
{
test_DwmIsCompositionEnabled();
test_DwmGetCompositionTimingInfo();
test_DWMWA_EXTENDED_FRAME_BOUNDS();
+ test_DwmFlush();
}
--
GitLab

36
overlays/yabridge.nix Normal file
View file

@ -0,0 +1,36 @@
final: prev: {
yabridge = prev.yabridge.overrideAttrs (old: {
src = prev.fetchFromGitHub {
owner = "robbert-vdh";
repo = "yabridge";
rev = "HEAD";
hash = "sha256-pxQ+B4WF9iWNeLholSSqSMLJ3lz/Ub/PfgkAuacUAqc=";
};
patches = [
# Hard code bitbridge & runtime dependencies
(prev.replaceVars ./hardcode-dependencies.patch {
libdbus = prev.pkgs.dbus.lib;
libxcb32 = prev.pkgsi686Linux.xorg.libxcb;
# inherit prev.wine;
})
# Patch the chainloader to search for libyabridge through NIX_PROFILES
./libyabridge-from-nix-profiles.patch
];
});
yabridgectl = prev.yabridge.overrideAttrs (old: {
cargoHash = "";
});
wineWowPackages.stagingFull = prev.pkgs-stable.wineWowPackages.stagingFull.overrideAttrs
(old: {
patches = [ ./wine-6006.patch ];
waylandSupport = true;
fontconfigSupport = true;
vulkanSupport = true;
});
}