Compare commits
	
		
			84 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					b5bd294e5c | ||
| 
						 | 
					ac60bd47f0 | ||
| 
						 | 
					b7248f0333 | ||
| 
						 | 
					8a5b5378e6 | ||
| 
						 | 
					4a49f75799 | ||
| 
						 | 
					9d2666f293 | ||
| 
						 | 
					e63fcc5982 | ||
| 
						 | 
					4c37c17f2e | ||
| 
						 | 
					722820a375 | ||
| 
						 | 
					688023eb9e | ||
| 
						 | 
					5771aeaddd | ||
| 
						 | 
					a42da90042 | ||
| 
						 | 
					d7d32ed6fc | ||
| 
						 | 
					4715acf27e | ||
| 
						 | 
					8780db5ee8 | ||
| 
						 | 
					b8bfc98618 | ||
| 
						 | 
					6e6f72a521 | ||
| 
						 | 
					a654c5d643 | ||
| 
						 | 
					c5d6aa169f | ||
| 
						 | 
					c1c67286d3 | ||
| 
						 | 
					2fb34697c7 | ||
| 
						 | 
					94b5b9f370 | ||
| 
						 | 
					a9467513e1 | ||
| 
						 | 
					17d944f6ce | ||
| 
						 | 
					0f82f18652 | ||
| 
						 | 
					3db3e577f1 | ||
| 
						 | 
					37ee821947 | ||
| 
						 | 
					916ab9a7e6 | ||
| 
						 | 
					1802cf9fd1 | ||
| 
						 | 
					1bf7d30623 | ||
| 
						 | 
					b2d89253a6 | ||
| 
						 | 
					50c1e3738a | ||
| 
						 | 
					7a939746ae | ||
| 
						 | 
					feac1a3f56 | ||
| 
						 | 
					f3c37e484e | ||
| 
						 | 
					49130c2018 | ||
| 
						 | 
					94af199c49 | ||
| 
						 | 
					2d25f6f57f | ||
| 
						 | 
					cf179ec294 | ||
| 
						 | 
					4d6f220a2f | ||
| 
						 | 
					0ffbe5b5ea | ||
| 
						 | 
					5b83c834ac | ||
| 
						 | 
					da7f32bddb | ||
| 
						 | 
					9a5eac4ea9 | ||
| 
						 | 
					6571b5d118 | ||
| 
						 | 
					12dff8e382 | ||
| 
						 | 
					c4da87a0cb | ||
| 
						 | 
					446f8f29d3 | ||
| 
						 | 
					48cc76f114 | ||
| 
						 | 
					a0892b852e | ||
| 
						 | 
					485c7805eb | ||
| 
						 | 
					23802f4489 | ||
| 
						 | 
					3fedd978a2 | ||
| 
						 | 
					a9f1bed922 | ||
| 
						 | 
					eb23788fec | ||
| 
						 | 
					f6d73555a6 | ||
| 
						 | 
					a56a709406 | ||
| 
						 | 
					5f253e66f6 | ||
| 
						 | 
					4669f7e2b9 | ||
| 
						 | 
					4c90f88704 | ||
| 
						 | 
					a7213b78d6 | ||
| 
						 | 
					719333e16e | ||
| 
						 | 
					100e471b49 | ||
| 
						 | 
					3f2016e552 | ||
| 
						 | 
					dd89ea4505 | ||
| 
						 | 
					101e12cf9a | ||
| 
						 | 
					f382808450 | ||
| 
						 | 
					0cbe3c2a93 | ||
| 
						 | 
					4f0ae28359 | ||
| 
						 | 
					6a4250f485 | ||
| 
						 | 
					3322b29e6a | ||
| 
						 | 
					33ac472601 | ||
| 
						 | 
					561d6fd478 | ||
| 
						 | 
					42a01822bf | ||
| 
						 | 
					38f1237d49 | ||
| 
						 | 
					8df77122e5 | ||
| 
						 | 
					fef6b9df80 | ||
| 
						 | 
					d52eac66db | ||
| 
						 | 
					70879f0abc | ||
| 
						 | 
					bcb393628e | ||
| 
						 | 
					18d3a5c12b | ||
| 
						 | 
					6ee3d0102b | ||
| 
						 | 
					fc9626e2f4 | ||
| 
						 | 
					3bedd94fc8 | 
							
								
								
									
										25
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								NEWS
									
									
									
									
									
								
							@@ -1,3 +1,28 @@
 | 
				
			|||||||
 | 
					ver 0.23.16 (2024/12/03)
 | 
				
			||||||
 | 
					* database
 | 
				
			||||||
 | 
					  - fix integer overflows with 64-bit inode numbers
 | 
				
			||||||
 | 
					* filter
 | 
				
			||||||
 | 
					  - ffmpeg: fix for filters producing no output
 | 
				
			||||||
 | 
					* support libfmt 11
 | 
				
			||||||
 | 
					* support ICU 76
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ver 0.23.15 (2023/12/20)
 | 
				
			||||||
 | 
					* decoder
 | 
				
			||||||
 | 
					  - ffmpeg: fix build failure with FFmpeg 6.1
 | 
				
			||||||
 | 
					* output
 | 
				
			||||||
 | 
					  - alsa: limit buffer time to 2 seconds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ver 0.23.14 (2023/10/08)
 | 
				
			||||||
 | 
					* decoder
 | 
				
			||||||
 | 
					  - flac: fix scanning files with non-ASCII names on Windows
 | 
				
			||||||
 | 
					  - mad: fix calculation of LAME peak values
 | 
				
			||||||
 | 
					* mixer
 | 
				
			||||||
 | 
					  - wasapi: fix problem setting volume
 | 
				
			||||||
 | 
					* more libfmt 10 fixes
 | 
				
			||||||
 | 
					* fix auto-detected systemd unit directory
 | 
				
			||||||
 | 
					* Android
 | 
				
			||||||
 | 
					  - require Android 7 or newer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ver 0.23.13 (2023/05/22)
 | 
					ver 0.23.13 (2023/05/22)
 | 
				
			||||||
* input
 | 
					* input
 | 
				
			||||||
  - curl: fix busy loop after connection failed
 | 
					  - curl: fix busy loop after connection failed
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,10 @@
 | 
				
			|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
					<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 | 
				
			||||||
          package="org.musicpd"
 | 
					          package="org.musicpd"
 | 
				
			||||||
          android:installLocation="auto"
 | 
					          android:installLocation="auto"
 | 
				
			||||||
          android:versionCode="71"
 | 
					          android:versionCode="74"
 | 
				
			||||||
          android:versionName="0.23.12">
 | 
					          android:versionName="0.23.16">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30"/>
 | 
					  <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="30"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <uses-feature android:name="android.software.leanback"
 | 
					  <uses-feature android:name="android.software.leanback"
 | 
				
			||||||
                android:required="false" />
 | 
					                android:required="false" />
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										128
									
								
								android/build.py
									
									
									
									
									
								
							
							
						
						
									
										128
									
								
								android/build.py
									
									
									
									
									
								
							@@ -20,131 +20,13 @@ if not os.path.isdir(ndk_path):
 | 
				
			|||||||
    print("NDK not found in", ndk_path, file=sys.stderr)
 | 
					    print("NDK not found in", ndk_path, file=sys.stderr)
 | 
				
			||||||
    sys.exit(1)
 | 
					    sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android_abis = {
 | 
					 | 
				
			||||||
    'armeabi-v7a': {
 | 
					 | 
				
			||||||
        'arch': 'arm-linux-androideabi',
 | 
					 | 
				
			||||||
        'ndk_arch': 'arm',
 | 
					 | 
				
			||||||
        'llvm_triple': 'armv7-linux-androideabi',
 | 
					 | 
				
			||||||
        'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    'arm64-v8a': {
 | 
					 | 
				
			||||||
        'arch': 'aarch64-linux-android',
 | 
					 | 
				
			||||||
        'ndk_arch': 'arm64',
 | 
					 | 
				
			||||||
        'llvm_triple': 'aarch64-linux-android',
 | 
					 | 
				
			||||||
        'cflags': '-fpic',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    'x86': {
 | 
					 | 
				
			||||||
        'arch': 'i686-linux-android',
 | 
					 | 
				
			||||||
        'ndk_arch': 'x86',
 | 
					 | 
				
			||||||
        'llvm_triple': 'i686-linux-android',
 | 
					 | 
				
			||||||
        'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    'x86_64': {
 | 
					 | 
				
			||||||
        'arch': 'x86_64-linux-android',
 | 
					 | 
				
			||||||
        'ndk_arch': 'x86_64',
 | 
					 | 
				
			||||||
        'llvm_triple': 'x86_64-linux-android',
 | 
					 | 
				
			||||||
        'cflags': '-fPIC -m64',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# select the NDK target
 | 
					 | 
				
			||||||
abi_info = android_abis[android_abi]
 | 
					 | 
				
			||||||
arch = abi_info['arch']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# the path to the MPD sources
 | 
					# the path to the MPD sources
 | 
				
			||||||
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
 | 
					mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
 | 
				
			||||||
sys.path[0] = os.path.join(mpd_path, 'python')
 | 
					sys.path[0] = os.path.join(mpd_path, 'python')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# output directories
 | 
					# output directories
 | 
				
			||||||
from build.dirs import lib_path, tarball_path, src_path
 | 
					from build.dirs import lib_path, tarball_path, src_path
 | 
				
			||||||
from build.meson import configure as run_meson
 | 
					from build.toolchain import AndroidNdkToolchain
 | 
				
			||||||
 | 
					 | 
				
			||||||
arch_path = os.path.join(lib_path, arch)
 | 
					 | 
				
			||||||
build_path = os.path.join(arch_path, 'build')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# build host configuration
 | 
					 | 
				
			||||||
build_arch = 'linux-x86_64'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# set up the NDK toolchain
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AndroidNdkToolchain:
 | 
					 | 
				
			||||||
    def __init__(self, tarball_path, src_path, build_path,
 | 
					 | 
				
			||||||
                 use_cxx):
 | 
					 | 
				
			||||||
        self.tarball_path = tarball_path
 | 
					 | 
				
			||||||
        self.src_path = src_path
 | 
					 | 
				
			||||||
        self.build_path = build_path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ndk_arch = abi_info['ndk_arch']
 | 
					 | 
				
			||||||
        android_api_level = '21'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        install_prefix = os.path.join(arch_path, 'root')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.arch = arch
 | 
					 | 
				
			||||||
        self.actual_arch = arch
 | 
					 | 
				
			||||||
        self.install_prefix = install_prefix
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
 | 
					 | 
				
			||||||
        llvm_triple = abi_info['llvm_triple'] + android_api_level
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        common_flags = '-Os -g'
 | 
					 | 
				
			||||||
        common_flags += ' ' + abi_info['cflags']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        llvm_bin = os.path.join(llvm_path, 'bin')
 | 
					 | 
				
			||||||
        self.cc = os.path.join(llvm_bin, 'clang')
 | 
					 | 
				
			||||||
        self.cxx = os.path.join(llvm_bin, 'clang++')
 | 
					 | 
				
			||||||
        common_flags += ' -target ' + llvm_triple
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.ar = os.path.join(llvm_bin, 'llvm-ar')
 | 
					 | 
				
			||||||
        self.arflags = 'rcs'
 | 
					 | 
				
			||||||
        self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
 | 
					 | 
				
			||||||
        self.nm = os.path.join(llvm_bin, 'llvm-nm')
 | 
					 | 
				
			||||||
        self.strip = os.path.join(llvm_bin, 'llvm-strip')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.cflags = common_flags
 | 
					 | 
				
			||||||
        self.cxxflags = common_flags
 | 
					 | 
				
			||||||
        self.cppflags = ' -isystem ' + os.path.join(install_prefix, 'include')
 | 
					 | 
				
			||||||
        self.ldflags = ' -L' + os.path.join(install_prefix, 'lib') + \
 | 
					 | 
				
			||||||
            ' -Wl,--exclude-libs=ALL' + \
 | 
					 | 
				
			||||||
            ' ' + common_flags
 | 
					 | 
				
			||||||
        self.ldflags = common_flags
 | 
					 | 
				
			||||||
        self.libs = ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.is_arm = ndk_arch == 'arm'
 | 
					 | 
				
			||||||
        self.is_armv7 = self.is_arm and 'armv7' in self.cflags
 | 
					 | 
				
			||||||
        self.is_aarch64 = ndk_arch == 'arm64'
 | 
					 | 
				
			||||||
        self.is_windows = False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        libstdcxx_flags = ''
 | 
					 | 
				
			||||||
        libstdcxx_cxxflags = ''
 | 
					 | 
				
			||||||
        libstdcxx_ldflags = ''
 | 
					 | 
				
			||||||
        libstdcxx_libs = '-static-libstdc++'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.is_armv7:
 | 
					 | 
				
			||||||
            # On 32 bit ARM, clang generates no ".eh_frame" section;
 | 
					 | 
				
			||||||
            # instead, the LLVM unwinder library is used for unwinding
 | 
					 | 
				
			||||||
            # the stack after a C++ exception was thrown
 | 
					 | 
				
			||||||
            libstdcxx_libs += ' -lunwind'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if use_cxx:
 | 
					 | 
				
			||||||
            self.cxxflags += ' ' + libstdcxx_cxxflags
 | 
					 | 
				
			||||||
            self.ldflags += ' ' + libstdcxx_ldflags
 | 
					 | 
				
			||||||
            self.libs += ' ' + libstdcxx_libs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.env = dict(os.environ)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # redirect pkg-config to use our root directory instead of the
 | 
					 | 
				
			||||||
        # default one on the build host
 | 
					 | 
				
			||||||
        import shutil
 | 
					 | 
				
			||||||
        bin_dir = os.path.join(install_prefix, 'bin')
 | 
					 | 
				
			||||||
        os.makedirs(bin_dir, exist_ok=True)
 | 
					 | 
				
			||||||
        self.pkg_config = shutil.copy(os.path.join(mpd_path, 'build', 'pkg-config.sh'),
 | 
					 | 
				
			||||||
                                      os.path.join(bin_dir, 'pkg-config'))
 | 
					 | 
				
			||||||
        self.env['PKG_CONFIG'] = self.pkg_config
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# a list of third-party libraries to be used by MPD on Android
 | 
					# a list of third-party libraries to be used by MPD on Android
 | 
				
			||||||
from build.libs import *
 | 
					from build.libs import *
 | 
				
			||||||
@@ -166,13 +48,17 @@ thirdparty_libs = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# build the third-party libraries
 | 
					# build the third-party libraries
 | 
				
			||||||
for x in thirdparty_libs:
 | 
					for x in thirdparty_libs:
 | 
				
			||||||
    toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
 | 
					    toolchain = AndroidNdkToolchain(mpd_path, lib_path,
 | 
				
			||||||
 | 
					                                    tarball_path, src_path,
 | 
				
			||||||
 | 
					                                    ndk_path, android_abi,
 | 
				
			||||||
                                    use_cxx=x.use_cxx)
 | 
					                                    use_cxx=x.use_cxx)
 | 
				
			||||||
    if not x.is_installed(toolchain):
 | 
					    if not x.is_installed(toolchain):
 | 
				
			||||||
        x.build(toolchain)
 | 
					        x.build(toolchain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# configure and build MPD
 | 
					# configure and build MPD
 | 
				
			||||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
 | 
					toolchain = AndroidNdkToolchain(mpd_path, lib_path,
 | 
				
			||||||
 | 
					                                tarball_path, src_path,
 | 
				
			||||||
 | 
					                                ndk_path, android_abi,
 | 
				
			||||||
                                use_cxx=True)
 | 
					                                use_cxx=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
configure_args += [
 | 
					configure_args += [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ Some example code:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.. code-block:: c
 | 
					.. code-block:: c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int
 | 
				
			||||||
    Foo(const char *abc, int xyz)
 | 
					    Foo(const char *abc, int xyz)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (abc == nullptr) {
 | 
					        if (abc == nullptr) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -314,6 +314,7 @@ input {
 | 
				
			|||||||
##	device		"Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
 | 
					##	device		"Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
 | 
				
			||||||
#		or
 | 
					#		or
 | 
				
			||||||
##	device		"0"		# optional
 | 
					##	device		"0"		# optional
 | 
				
			||||||
 | 
					##	mixer_type	"hardware"	# optional
 | 
				
			||||||
## Exclusive mode blocks all other audio source, and get best audio quality without resampling.
 | 
					## Exclusive mode blocks all other audio source, and get best audio quality without resampling.
 | 
				
			||||||
##	exclusive	"no"		# optional
 | 
					##	exclusive	"no"		# optional
 | 
				
			||||||
## Enumerate all devices in log.
 | 
					## Enumerate all devices in log.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1115,7 +1115,7 @@ Connect to a `PipeWire <https://pipewire.org/>`_ server.  Requires
 | 
				
			|||||||
   * - **target NAME**
 | 
					   * - **target NAME**
 | 
				
			||||||
     - Link to the given target.  If not specified, let the PipeWire
 | 
					     - Link to the given target.  If not specified, let the PipeWire
 | 
				
			||||||
       manager select a target.  To get a list of available targets,
 | 
					       manager select a target.  To get a list of available targets,
 | 
				
			||||||
       type ``pw-cli dump short Node``
 | 
					       type ``pw-cli ls Node``
 | 
				
			||||||
   * - **remote NAME**
 | 
					   * - **remote NAME**
 | 
				
			||||||
     - The name of the remote to connect to.  The default is
 | 
					     - The name of the remote to connect to.  The default is
 | 
				
			||||||
       ``pipewire-0``.
 | 
					       ``pipewire-0``.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -691,7 +691,8 @@ Song ids on the other hand are stable: an id is assigned to a song
 | 
				
			|||||||
when it is added, and will stay the same, no matter how much it is
 | 
					when it is added, and will stay the same, no matter how much it is
 | 
				
			||||||
moved around.  Adding the same song twice will assign different ids to
 | 
					moved around.  Adding the same song twice will assign different ids to
 | 
				
			||||||
them, and a deleted-and-readded song will have a new id.  This way, a
 | 
					them, and a deleted-and-readded song will have a new id.  This way, a
 | 
				
			||||||
client can always be sure the correct song is being used.
 | 
					client can always be sure the correct song is being used.  Song ids are not
 | 
				
			||||||
 | 
					preserved across :program:`MPD` restarts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Many commands come in two flavors, one for each address type.
 | 
					Many commands come in two flavors, one for each address type.
 | 
				
			||||||
Whenever possible, ids should be used.
 | 
					Whenever possible, ids should be used.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -661,9 +661,11 @@ MPD enables MixRamp if:
 | 
				
			|||||||
- Cross-fade is enabled
 | 
					- Cross-fade is enabled
 | 
				
			||||||
- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
 | 
					- :ref:`mixrampdelay <command_mixrampdelay>` is set to a positive
 | 
				
			||||||
  value, e.g.::
 | 
					  value, e.g.::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mpc mixrampdelay 1
 | 
					    mpc mixrampdelay 1
 | 
				
			||||||
- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
 | 
					- :ref:`mixrampdb <command_mixrampdb>` is set to a reasonable value,
 | 
				
			||||||
  e.g.::
 | 
					  e.g.::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    mpc mixrampdb -17
 | 
					    mpc mixrampdb -17
 | 
				
			||||||
- both songs have MixRamp tags
 | 
					- both songs have MixRamp tags
 | 
				
			||||||
- both songs have the same audio format (or :ref:`audio_output_format`
 | 
					- both songs have the same audio format (or :ref:`audio_output_format`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
project(
 | 
					project(
 | 
				
			||||||
  'mpd',
 | 
					  'mpd',
 | 
				
			||||||
  ['c', 'cpp'],
 | 
					  ['c', 'cpp'],
 | 
				
			||||||
  version: '0.23.13',
 | 
					  version: '0.23.16',
 | 
				
			||||||
  meson_version: '>= 0.56.0',
 | 
					  meson_version: '>= 0.56.0',
 | 
				
			||||||
  default_options: [
 | 
					  default_options: [
 | 
				
			||||||
    'c_std=c11',
 | 
					    'c_std=c11',
 | 
				
			||||||
@@ -76,6 +76,9 @@ test_common_flags = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  # suppress bogus GCC12 warnings in libfmt headers
 | 
					  # suppress bogus GCC12 warnings in libfmt headers
 | 
				
			||||||
  '-Wno-stringop-overflow',
 | 
					  '-Wno-stringop-overflow',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # libfmt causes this warning due to -ffast-math
 | 
				
			||||||
 | 
					  '-Wno-nan-infinity-disabled',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test_global_cxxflags = test_global_common_flags + [
 | 
					test_global_cxxflags = test_global_common_flags + [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,26 +1,32 @@
 | 
				
			|||||||
import os.path, subprocess, sys
 | 
					import os.path, subprocess, sys
 | 
				
			||||||
 | 
					from typing import Collection, Iterable, Optional, Sequence, Union
 | 
				
			||||||
 | 
					from collections.abc import Mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.makeproject import MakeProject
 | 
					from build.makeproject import MakeProject
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AutotoolsProject(MakeProject):
 | 
					class AutotoolsProject(MakeProject):
 | 
				
			||||||
    def __init__(self, url, md5, installed, configure_args=[],
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 autogen=False,
 | 
					                 configure_args: Iterable[str]=[],
 | 
				
			||||||
                 autoreconf=False,
 | 
					                 autogen: bool=False,
 | 
				
			||||||
                 cppflags='',
 | 
					                 autoreconf: bool=False,
 | 
				
			||||||
                 ldflags='',
 | 
					                 per_arch_cflags: Optional[Mapping[str, str]]=None,
 | 
				
			||||||
                 libs='',
 | 
					                 cppflags: str='',
 | 
				
			||||||
                 subdirs=None,
 | 
					                 ldflags: str='',
 | 
				
			||||||
 | 
					                 libs: str='',
 | 
				
			||||||
 | 
					                 subdirs: Optional[Collection[str]]=None,
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        MakeProject.__init__(self, url, md5, installed, **kwargs)
 | 
					        MakeProject.__init__(self, url, md5, installed, **kwargs)
 | 
				
			||||||
        self.configure_args = configure_args
 | 
					        self.configure_args = configure_args
 | 
				
			||||||
        self.autogen = autogen
 | 
					        self.autogen = autogen
 | 
				
			||||||
        self.autoreconf = autoreconf
 | 
					        self.autoreconf = autoreconf
 | 
				
			||||||
 | 
					        self.per_arch_cflags = per_arch_cflags
 | 
				
			||||||
        self.cppflags = cppflags
 | 
					        self.cppflags = cppflags
 | 
				
			||||||
        self.ldflags = ldflags
 | 
					        self.ldflags = ldflags
 | 
				
			||||||
        self.libs = libs
 | 
					        self.libs = libs
 | 
				
			||||||
        self.subdirs = subdirs
 | 
					        self.subdirs = subdirs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def configure(self, toolchain):
 | 
					    def configure(self, toolchain: AnyToolchain) -> str:
 | 
				
			||||||
        src = self.unpack(toolchain)
 | 
					        src = self.unpack(toolchain)
 | 
				
			||||||
        if self.autogen:
 | 
					        if self.autogen:
 | 
				
			||||||
            if sys.platform == 'darwin':
 | 
					            if sys.platform == 'darwin':
 | 
				
			||||||
@@ -35,12 +41,16 @@ class AutotoolsProject(MakeProject):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        build = self.make_build_path(toolchain)
 | 
					        build = self.make_build_path(toolchain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arch_cflags = ''
 | 
				
			||||||
 | 
					        if self.per_arch_cflags is not None and toolchain.host_triplet is not None:
 | 
				
			||||||
 | 
					            arch_cflags = self.per_arch_cflags.get(toolchain.host_triplet, '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        configure = [
 | 
					        configure = [
 | 
				
			||||||
            os.path.join(src, 'configure'),
 | 
					            os.path.join(src, 'configure'),
 | 
				
			||||||
            'CC=' + toolchain.cc,
 | 
					            'CC=' + toolchain.cc,
 | 
				
			||||||
            'CXX=' + toolchain.cxx,
 | 
					            'CXX=' + toolchain.cxx,
 | 
				
			||||||
            'CFLAGS=' + toolchain.cflags,
 | 
					            'CFLAGS=' + toolchain.cflags + ' ' + arch_cflags,
 | 
				
			||||||
            'CXXFLAGS=' + toolchain.cxxflags,
 | 
					            'CXXFLAGS=' + toolchain.cxxflags + ' ' + arch_cflags,
 | 
				
			||||||
            'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
 | 
					            'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
 | 
				
			||||||
            'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
 | 
					            'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
 | 
				
			||||||
            'LIBS=' + toolchain.libs + ' ' + self.libs,
 | 
					            'LIBS=' + toolchain.libs + ' ' + self.libs,
 | 
				
			||||||
@@ -48,10 +58,14 @@ class AutotoolsProject(MakeProject):
 | 
				
			|||||||
            'ARFLAGS=' + toolchain.arflags,
 | 
					            'ARFLAGS=' + toolchain.arflags,
 | 
				
			||||||
            'RANLIB=' + toolchain.ranlib,
 | 
					            'RANLIB=' + toolchain.ranlib,
 | 
				
			||||||
            'STRIP=' + toolchain.strip,
 | 
					            'STRIP=' + toolchain.strip,
 | 
				
			||||||
            '--host=' + toolchain.arch,
 | 
					 | 
				
			||||||
            '--prefix=' + toolchain.install_prefix,
 | 
					            '--prefix=' + toolchain.install_prefix,
 | 
				
			||||||
            '--disable-silent-rules',
 | 
					            '--disable-silent-rules',
 | 
				
			||||||
        ] + self.configure_args
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if toolchain.host_triplet is not None:
 | 
				
			||||||
 | 
					            configure.append('--host=' + toolchain.host_triplet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        configure.extend(self.configure_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            print(configure)
 | 
					            print(configure)
 | 
				
			||||||
@@ -68,7 +82,7 @@ class AutotoolsProject(MakeProject):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return build
 | 
					        return build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _build(self, toolchain):
 | 
					    def _build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        build = self.configure(toolchain)
 | 
					        build = self.configure(toolchain)
 | 
				
			||||||
        if self.subdirs is not None:
 | 
					        if self.subdirs is not None:
 | 
				
			||||||
            for subdir in self.subdirs:
 | 
					            for subdir in self.subdirs:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,21 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from typing import cast, Optional, Sequence, TextIO, Union
 | 
				
			||||||
 | 
					from collections.abc import Mapping
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.project import Project
 | 
					from build.project import Project
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def __write_cmake_compiler(f, language, compiler):
 | 
					def __write_cmake_compiler(f: TextIO, language: str, compiler: str) -> None:
 | 
				
			||||||
    s = compiler.split(' ', 1)
 | 
					    s = compiler.split(' ', 1)
 | 
				
			||||||
    if len(s) == 2:
 | 
					    if len(s) == 2:
 | 
				
			||||||
        print(f'set(CMAKE_{language}_COMPILER_LAUNCHER {s[0]})', file=f)
 | 
					        print(f'set(CMAKE_{language}_COMPILER_LAUNCHER {s[0]})', file=f)
 | 
				
			||||||
        compiler = s[1]
 | 
					        compiler = s[1]
 | 
				
			||||||
    print(f'set(CMAKE_{language}_COMPILER {compiler})', file=f)
 | 
					    print(f'set(CMAKE_{language}_COMPILER {compiler})', file=f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def __write_cmake_toolchain_file(f, toolchain):
 | 
					def __write_cmake_toolchain_file(f: TextIO, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
    if '-darwin' in toolchain.actual_arch:
 | 
					    if toolchain.is_darwin:
 | 
				
			||||||
        cmake_system_name = 'Darwin'
 | 
					        cmake_system_name = 'Darwin'
 | 
				
			||||||
    elif toolchain.is_windows:
 | 
					    elif toolchain.is_windows:
 | 
				
			||||||
        cmake_system_name = 'Windows'
 | 
					        cmake_system_name = 'Windows'
 | 
				
			||||||
@@ -21,10 +24,10 @@ def __write_cmake_toolchain_file(f, toolchain):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    f.write(f"""
 | 
					    f.write(f"""
 | 
				
			||||||
set(CMAKE_SYSTEM_NAME {cmake_system_name})
 | 
					set(CMAKE_SYSTEM_NAME {cmake_system_name})
 | 
				
			||||||
set(CMAKE_SYSTEM_PROCESSOR {toolchain.actual_arch.split('-', 1)[0]})
 | 
					set(CMAKE_SYSTEM_PROCESSOR {toolchain.host_triplet.split('-', 1)[0]})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_C_COMPILER_TARGET {toolchain.actual_arch})
 | 
					set(CMAKE_C_COMPILER_TARGET {toolchain.host_triplet})
 | 
				
			||||||
set(CMAKE_CXX_COMPILER_TARGET {toolchain.actual_arch})
 | 
					set(CMAKE_CXX_COMPILER_TARGET {toolchain.host_triplet})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set(CMAKE_C_FLAGS_INIT "{toolchain.cflags} {toolchain.cppflags}")
 | 
					set(CMAKE_C_FLAGS_INIT "{toolchain.cflags} {toolchain.cppflags}")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
 | 
					set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
 | 
				
			||||||
@@ -50,38 +53,49 @@ set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
 | 
				
			|||||||
set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix};{sysroot}")
 | 
					set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix};{sysroot}")
 | 
				
			||||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 | 
				
			||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 | 
				
			||||||
 | 
					""")
 | 
				
			||||||
 | 
					    elif cmake_system_name == 'Windows':
 | 
				
			||||||
 | 
					            # search libraries and headers only in the sysroot, not on
 | 
				
			||||||
 | 
					            # the build host
 | 
				
			||||||
 | 
					            f.write(f"""
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix}")
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 | 
				
			||||||
 | 
					set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 | 
				
			||||||
""")
 | 
					""")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def configure(toolchain, src, build, args=(), env=None):
 | 
					def configure(toolchain: AnyToolchain, src: str, build: str, args: list[str]=[], env: Optional[Mapping[str, str]]=None) -> None:
 | 
				
			||||||
    cross_args = []
 | 
					    cross_args: list[str] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if toolchain.is_windows:
 | 
					    if toolchain.is_windows:
 | 
				
			||||||
        cross_args.append('-DCMAKE_RC_COMPILER=' + toolchain.windres)
 | 
					        cross_args.append('-DCMAKE_RC_COMPILER=' + cast(str, toolchain.windres))
 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Several targets need a sysroot to prevent pkg-config from
 | 
					 | 
				
			||||||
    # looking for libraries on the build host (TODO: fix this
 | 
					 | 
				
			||||||
    # properly); but we must not do that on Android because the NDK
 | 
					 | 
				
			||||||
    # has a sysroot already
 | 
					 | 
				
			||||||
    if '-android' not in toolchain.actual_arch and '-darwin' not in toolchain.actual_arch:
 | 
					 | 
				
			||||||
        cross_args.append('-DCMAKE_SYSROOT=' + toolchain.install_prefix)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    os.makedirs(build, exist_ok=True)
 | 
					 | 
				
			||||||
    cmake_toolchain_file = os.path.join(build, 'cmake_toolchain_file')
 | 
					 | 
				
			||||||
    with open(cmake_toolchain_file, 'w') as f:
 | 
					 | 
				
			||||||
        __write_cmake_toolchain_file(f, toolchain)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    configure = [
 | 
					    configure = [
 | 
				
			||||||
        'cmake',
 | 
					        'cmake',
 | 
				
			||||||
        src,
 | 
					        src,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '-DCMAKE_TOOLCHAIN_FILE=' + cmake_toolchain_file,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        '-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
 | 
					        '-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
 | 
				
			||||||
        '-DCMAKE_BUILD_TYPE=release',
 | 
					        '-DCMAKE_BUILD_TYPE=release',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '-GNinja',
 | 
					        '-GNinja',
 | 
				
			||||||
    ] + cross_args + args
 | 
					    ] + cross_args + args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if toolchain.host_triplet is not None:
 | 
				
			||||||
 | 
					        # cross-compiling: write a toolchain file
 | 
				
			||||||
 | 
					        os.makedirs(build, exist_ok=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Several targets need a sysroot to prevent pkg-config from
 | 
				
			||||||
 | 
					        # looking for libraries on the build host (TODO: fix this
 | 
				
			||||||
 | 
					        # properly); but we must not do that on Android because the NDK
 | 
				
			||||||
 | 
					        # has a sysroot already
 | 
				
			||||||
 | 
					        if not toolchain.is_android and not toolchain.is_darwin:
 | 
				
			||||||
 | 
					            cross_args.append('-DCMAKE_SYSROOT=' + toolchain.install_prefix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cmake_toolchain_file = os.path.join(build, 'cmake_toolchain_file')
 | 
				
			||||||
 | 
					        with open(cmake_toolchain_file, 'w') as f:
 | 
				
			||||||
 | 
					            __write_cmake_toolchain_file(f, toolchain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        configure.append('-DCMAKE_TOOLCHAIN_FILE=' + cmake_toolchain_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if env is None:
 | 
					    if env is None:
 | 
				
			||||||
        env = toolchain.env
 | 
					        env = toolchain.env
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
@@ -91,16 +105,17 @@ def configure(toolchain, src, build, args=(), env=None):
 | 
				
			|||||||
    subprocess.check_call(configure, env=env, cwd=build)
 | 
					    subprocess.check_call(configure, env=env, cwd=build)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CmakeProject(Project):
 | 
					class CmakeProject(Project):
 | 
				
			||||||
    def __init__(self, url, md5, installed, configure_args=[],
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 windows_configure_args=[],
 | 
					                 configure_args: list[str]=[],
 | 
				
			||||||
                 env=None,
 | 
					                 windows_configure_args: list[str]=[],
 | 
				
			||||||
 | 
					                 env: Optional[Mapping[str, str]]=None,
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        Project.__init__(self, url, md5, installed, **kwargs)
 | 
					        Project.__init__(self, url, md5, installed, **kwargs)
 | 
				
			||||||
        self.configure_args = configure_args
 | 
					        self.configure_args = configure_args
 | 
				
			||||||
        self.windows_configure_args = windows_configure_args
 | 
					        self.windows_configure_args = windows_configure_args
 | 
				
			||||||
        self.env = env
 | 
					        self.env = env
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def configure(self, toolchain):
 | 
					    def configure(self, toolchain: AnyToolchain) -> str:
 | 
				
			||||||
        src = self.unpack(toolchain)
 | 
					        src = self.unpack(toolchain)
 | 
				
			||||||
        build = self.make_build_path(toolchain)
 | 
					        build = self.make_build_path(toolchain)
 | 
				
			||||||
        configure_args = self.configure_args
 | 
					        configure_args = self.configure_args
 | 
				
			||||||
@@ -109,7 +124,7 @@ class CmakeProject(Project):
 | 
				
			|||||||
        configure(toolchain, src, build, configure_args, self.env)
 | 
					        configure(toolchain, src, build, configure_args, self.env)
 | 
				
			||||||
        return build
 | 
					        return build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _build(self, toolchain):
 | 
					    def _build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        build = self.configure(toolchain)
 | 
					        build = self.configure(toolchain)
 | 
				
			||||||
        subprocess.check_call(['ninja', '-v', 'install'],
 | 
					        subprocess.check_call(['ninja', '-v', 'install'],
 | 
				
			||||||
                              cwd=build, env=toolchain.env)
 | 
					                              cwd=build, env=toolchain.env)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,50 @@
 | 
				
			|||||||
from build.verify import verify_file_digest
 | 
					from typing import Sequence, Union
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
import urllib.request
 | 
					import urllib.request
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def download_and_verify(url, md5, parent_path):
 | 
					from .verify import verify_file_digest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def __to_string_sequence(x: Union[str, Sequence[str]]) -> Sequence[str]:
 | 
				
			||||||
 | 
					    if isinstance(x, str):
 | 
				
			||||||
 | 
					        return (x,)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def __get_any(x: Union[str, Sequence[str]]) -> str:
 | 
				
			||||||
 | 
					    if isinstance(x, str):
 | 
				
			||||||
 | 
					        return x
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return x[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def __download_one(url: str, path: str) -> None:
 | 
				
			||||||
 | 
					    print("download", url)
 | 
				
			||||||
 | 
					    urllib.request.urlretrieve(url, path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def __download(urls: Sequence[str], path: str) -> None:
 | 
				
			||||||
 | 
					    for url in urls[:-1]:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            __download_one(url, path)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            print("download error:", sys.exc_info()[0])
 | 
				
			||||||
 | 
					    __download_one(urls[-1], path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def __download_and_verify_to(urls: Sequence[str], md5: str, path: str) -> None:
 | 
				
			||||||
 | 
					    __download(urls, path)
 | 
				
			||||||
 | 
					    if not verify_file_digest(path, md5):
 | 
				
			||||||
 | 
					        raise RuntimeError("Digest mismatch")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def download_basename(urls: Union[str, Sequence[str]]) -> str:
 | 
				
			||||||
 | 
					    return os.path.basename(__get_any(urls))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def download_and_verify(urls: Union[str, Sequence[str]], md5: str, parent_path: str) -> str:
 | 
				
			||||||
    """Download a file, verify its MD5 checksum and return the local path."""
 | 
					    """Download a file, verify its MD5 checksum and return the local path."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    base = download_basename(urls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    os.makedirs(parent_path, exist_ok=True)
 | 
					    os.makedirs(parent_path, exist_ok=True)
 | 
				
			||||||
    path = os.path.join(parent_path, os.path.basename(url))
 | 
					    path = os.path.join(parent_path, base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        if verify_file_digest(path, md5): return path
 | 
					        if verify_file_digest(path, md5): return path
 | 
				
			||||||
@@ -16,11 +54,6 @@ def download_and_verify(url, md5, parent_path):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    tmp_path = path + '.tmp'
 | 
					    tmp_path = path + '.tmp'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print("download", url)
 | 
					    __download_and_verify_to(__to_string_sequence(urls), md5, tmp_path)
 | 
				
			||||||
    urllib.request.urlretrieve(url, tmp_path)
 | 
					 | 
				
			||||||
    if not verify_file_digest(tmp_path, md5):
 | 
					 | 
				
			||||||
        os.unlink(tmp_path)
 | 
					 | 
				
			||||||
        raise RuntimeError("Digest mismatch")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    os.rename(tmp_path, path)
 | 
					    os.rename(tmp_path, path)
 | 
				
			||||||
    return path
 | 
					    return path
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,8 +29,8 @@ libogg = CmakeProject(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
opus = AutotoolsProject(
 | 
					opus = AutotoolsProject(
 | 
				
			||||||
    'https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz',
 | 
					    'https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz',
 | 
				
			||||||
    '65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d',
 | 
					    'c9b32b4253be5ae63d1ff16eea06b94b5f0f2951b7a02aceef58e3a3ce49c51f',
 | 
				
			||||||
    'lib/libopus.a',
 | 
					    'lib/libopus.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
@@ -43,8 +43,8 @@ opus = AutotoolsProject(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
flac = AutotoolsProject(
 | 
					flac = AutotoolsProject(
 | 
				
			||||||
    'http://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz',
 | 
					    'http://downloads.xiph.org/releases/flac/flac-1.4.3.tar.xz',
 | 
				
			||||||
    'e322d58a1f48d23d9dd38f432672865f6f79e73a6f9cc5a5f57fcaa83eb5a8e4',
 | 
					    '6c58e69cd22348f441b861092b825e591d0b822e106de6eb0ee4d05d27205b70',
 | 
				
			||||||
    'lib/libFLAC.a',
 | 
					    'lib/libFLAC.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
@@ -57,8 +57,9 @@ flac = AutotoolsProject(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
zlib = ZlibProject(
 | 
					zlib = ZlibProject(
 | 
				
			||||||
    'http://zlib.net/zlib-1.2.13.tar.xz',
 | 
					    ('http://zlib.net/zlib-1.3.1.tar.xz',
 | 
				
			||||||
    'd14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98',
 | 
					     'https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.xz'),
 | 
				
			||||||
 | 
					    '38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32',
 | 
				
			||||||
    'lib/libz.a',
 | 
					    'lib/libz.a',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -111,11 +112,12 @@ libmodplug = AutotoolsProject(
 | 
				
			|||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					    patches='src/lib/modplug/patches',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libopenmpt = AutotoolsProject(
 | 
					libopenmpt = AutotoolsProject(
 | 
				
			||||||
    'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.6.6+release.autotools.tar.gz',
 | 
					    'https://lib.openmpt.org/files/libopenmpt/src/libopenmpt-0.7.9+release.autotools.tar.gz',
 | 
				
			||||||
    '6ddb9e26a430620944891796fefb1bbb38bd9148f6cfc558810c0d3f269876c7',
 | 
					    '0386e918d75d797e79d5b14edd0847165d8b359e9811ef57652c0a356a2dfcf4',
 | 
				
			||||||
    'lib/libopenmpt.a',
 | 
					    'lib/libopenmpt.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
@@ -127,12 +129,12 @@ libopenmpt = AutotoolsProject(
 | 
				
			|||||||
        '--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
 | 
					        '--without-portaudio', '--without-portaudiocpp', '--without-sndfile',
 | 
				
			||||||
        '--without-flac',
 | 
					        '--without-flac',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    base='libopenmpt-0.6.6+release.autotools',
 | 
					    base='libopenmpt-0.7.9+release.autotools',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wildmidi = CmakeProject(
 | 
					wildmidi = CmakeProject(
 | 
				
			||||||
    'https://github.com/Mindwerks/wildmidi/releases/download/wildmidi-0.4.5/wildmidi-0.4.5.tar.gz',
 | 
					    'https://github.com/Mindwerks/wildmidi/releases/download/wildmidi-0.4.6/wildmidi-0.4.6.tar.gz',
 | 
				
			||||||
    'd5e7bef00a7aa47534a53d43b1265f8d3d27f6a28e7f563c1cdf02ff4fa35b99',
 | 
					    '24ca992639ce76efa3737029fceb3672385d56e2ac0a15d50b40cc12d26e60de',
 | 
				
			||||||
    'lib/libWildMidi.a',
 | 
					    'lib/libWildMidi.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '-DBUILD_SHARED_LIBS=OFF',
 | 
					        '-DBUILD_SHARED_LIBS=OFF',
 | 
				
			||||||
@@ -149,13 +151,13 @@ gme = CmakeProject(
 | 
				
			|||||||
        '-DBUILD_SHARED_LIBS=OFF',
 | 
					        '-DBUILD_SHARED_LIBS=OFF',
 | 
				
			||||||
        '-DENABLE_UBSAN=OFF',
 | 
					        '-DENABLE_UBSAN=OFF',
 | 
				
			||||||
        '-DZLIB_INCLUDE_DIR=OFF',
 | 
					        '-DZLIB_INCLUDE_DIR=OFF',
 | 
				
			||||||
        '-DSDL2_DIR=OFF',
 | 
					        '-DCMAKE_DISABLE_FIND_PACKAGE_SDL2=ON',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ffmpeg = FfmpegProject(
 | 
					ffmpeg = FfmpegProject(
 | 
				
			||||||
    'http://ffmpeg.org/releases/ffmpeg-6.0.tar.xz',
 | 
					    'http://ffmpeg.org/releases/ffmpeg-6.1.tar.xz',
 | 
				
			||||||
    '57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082',
 | 
					    '488c76e57dd9b3bee901f71d5c95eaf1db4a5a31fe46a28654e837144207c270',
 | 
				
			||||||
    'lib/libavcodec.a',
 | 
					    'lib/libavcodec.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
@@ -462,6 +464,8 @@ ffmpeg = FfmpegProject(
 | 
				
			|||||||
        '--disable-decoder=pam',
 | 
					        '--disable-decoder=pam',
 | 
				
			||||||
        '--disable-decoder=pbm',
 | 
					        '--disable-decoder=pbm',
 | 
				
			||||||
        '--disable-decoder=pcx',
 | 
					        '--disable-decoder=pcx',
 | 
				
			||||||
 | 
					        '--disable-decoder=pdv',
 | 
				
			||||||
 | 
					        '--disable-decoder=pfm',
 | 
				
			||||||
        '--disable-decoder=pgm',
 | 
					        '--disable-decoder=pgm',
 | 
				
			||||||
        '--disable-decoder=pgmyuv',
 | 
					        '--disable-decoder=pgmyuv',
 | 
				
			||||||
        '--disable-decoder=pgssub',
 | 
					        '--disable-decoder=pgssub',
 | 
				
			||||||
@@ -598,14 +602,16 @@ ffmpeg = FfmpegProject(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
openssl = OpenSSLProject(
 | 
					openssl = OpenSSLProject(
 | 
				
			||||||
    'https://www.openssl.org/source/openssl-3.1.0.tar.gz',
 | 
					    ('https://www.openssl.org/source/openssl-3.1.4.tar.gz',
 | 
				
			||||||
    'aaa925ad9828745c4cad9d9efeb273deca820f2cdcf2c3ac7d7c1212b7c497b4',
 | 
					     'https://artfiles.org/openssl.org/source/openssl-3.1.4.tar.gz'),
 | 
				
			||||||
 | 
					    '840af5366ab9b522bde525826be3ef0fb0af81c6a9ebd84caa600fea1731eee3',
 | 
				
			||||||
    'include/openssl/ossl_typ.h',
 | 
					    'include/openssl/ossl_typ.h',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
curl = CmakeProject(
 | 
					curl = CmakeProject(
 | 
				
			||||||
    'https://curl.se/download/curl-8.0.1.tar.xz',
 | 
					    ('https://curl.se/download/curl-8.5.0.tar.xz',
 | 
				
			||||||
    '0a381cd82f4d00a9a334438b8ca239afea5bfefcfa9a1025f2bf118e79e0b5f0',
 | 
					     'https://github.com/curl/curl/releases/download/curl-8_5_0/curl-8.5.0.tar.xz'),
 | 
				
			||||||
 | 
					    '42ab8db9e20d8290a3b633e7fbb3cec15db34df65fd1015ef8ac1e4723750eeb',
 | 
				
			||||||
    'lib/libcurl.a',
 | 
					    'lib/libcurl.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '-DBUILD_CURL_EXE=OFF',
 | 
					        '-DBUILD_CURL_EXE=OFF',
 | 
				
			||||||
@@ -638,8 +644,8 @@ curl = CmakeProject(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libnfs = AutotoolsProject(
 | 
					libnfs = AutotoolsProject(
 | 
				
			||||||
    'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.2.tar.gz',
 | 
					    'https://github.com/sahlberg/libnfs/archive/libnfs-5.0.3.tar.gz',
 | 
				
			||||||
    '637e56643b19da9fba98f06847788c4dad308b723156a64748041035dcdf9bd3',
 | 
					    'd945cb4f4c8f82ee1f3640893a168810f794a28e1010bb007ec5add345e9df3e',
 | 
				
			||||||
    'lib/libnfs.a',
 | 
					    'lib/libnfs.a',
 | 
				
			||||||
    [
 | 
					    [
 | 
				
			||||||
        '--disable-shared', '--enable-static',
 | 
					        '--disable-shared', '--enable-static',
 | 
				
			||||||
@@ -650,7 +656,7 @@ libnfs = AutotoolsProject(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        '--disable-utils', '--disable-examples',
 | 
					        '--disable-utils', '--disable-examples',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    base='libnfs-libnfs-5.0.2',
 | 
					    base='libnfs-libnfs-5.0.3',
 | 
				
			||||||
    autoreconf=True,
 | 
					    autoreconf=True,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +1,17 @@
 | 
				
			|||||||
import subprocess, multiprocessing
 | 
					import subprocess, multiprocessing
 | 
				
			||||||
 | 
					from typing import Optional, Sequence, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.project import Project
 | 
					from build.project import Project
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MakeProject(Project):
 | 
					class MakeProject(Project):
 | 
				
			||||||
    def __init__(self, url, md5, installed,
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 install_target='install',
 | 
					                 install_target: str='install',
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        Project.__init__(self, url, md5, installed, **kwargs)
 | 
					        Project.__init__(self, url, md5, installed, **kwargs)
 | 
				
			||||||
        self.install_target = install_target
 | 
					        self.install_target = install_target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_simultaneous_jobs(self):
 | 
					    def get_simultaneous_jobs(self) -> int:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            # use twice as many simultaneous jobs as we have CPU cores
 | 
					            # use twice as many simultaneous jobs as we have CPU cores
 | 
				
			||||||
            return multiprocessing.cpu_count() * 2
 | 
					            return multiprocessing.cpu_count() * 2
 | 
				
			||||||
@@ -17,17 +19,17 @@ class MakeProject(Project):
 | 
				
			|||||||
            # default to 12, if multiprocessing.cpu_count() is not implemented
 | 
					            # default to 12, if multiprocessing.cpu_count() is not implemented
 | 
				
			||||||
            return 12
 | 
					            return 12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_args(self, toolchain):
 | 
					    def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
 | 
					        return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_install_args(self, toolchain):
 | 
					    def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        return ['--quiet', self.install_target]
 | 
					        return ['--quiet', self.install_target]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def make(self, toolchain, wd, args):
 | 
					    def make(self, toolchain: AnyToolchain, wd: str, args: list[str]) -> None:
 | 
				
			||||||
        subprocess.check_call(['make'] + args,
 | 
					        subprocess.check_call(['make'] + args,
 | 
				
			||||||
                              cwd=wd, env=toolchain.env)
 | 
					                              cwd=wd, env=toolchain.env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_make(self, toolchain, wd, install=True):
 | 
					    def build_make(self, toolchain: AnyToolchain, wd: str, install: bool=True) -> None:
 | 
				
			||||||
        self.make(toolchain, wd, self.get_make_args(toolchain))
 | 
					        self.make(toolchain, wd, self.get_make_args(toolchain))
 | 
				
			||||||
        if install:
 | 
					        if install:
 | 
				
			||||||
            self.make(toolchain, wd, self.get_make_install_args(toolchain))
 | 
					            self.make(toolchain, wd, self.get_make_install_args(toolchain))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,17 @@
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import platform
 | 
					import platform
 | 
				
			||||||
 | 
					from typing import Optional, Sequence, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.project import Project
 | 
					from build.project import Project
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def make_cross_file(toolchain):
 | 
					def __no_ccache(cmd: str) -> str:
 | 
				
			||||||
 | 
					    if cmd.startswith('ccache '):
 | 
				
			||||||
 | 
					        cmd = cmd[7:]
 | 
				
			||||||
 | 
					    return cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_cross_file(toolchain: AnyToolchain) -> str:
 | 
				
			||||||
    if toolchain.is_windows:
 | 
					    if toolchain.is_windows:
 | 
				
			||||||
        system = 'windows'
 | 
					        system = 'windows'
 | 
				
			||||||
        windres = "windres = '%s'" % toolchain.windres
 | 
					        windres = "windres = '%s'" % toolchain.windres
 | 
				
			||||||
@@ -23,7 +30,7 @@ def make_cross_file(toolchain):
 | 
				
			|||||||
        cpu = 'arm64-v8a'
 | 
					        cpu = 'arm64-v8a'
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        cpu_family = 'x86'
 | 
					        cpu_family = 'x86'
 | 
				
			||||||
        if 'x86_64' in toolchain.arch:
 | 
					        if 'x86_64' in toolchain.host_triplet:
 | 
				
			||||||
            cpu = 'x86_64'
 | 
					            cpu = 'x86_64'
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            cpu = 'i686'
 | 
					            cpu = 'i686'
 | 
				
			||||||
@@ -38,8 +45,8 @@ def make_cross_file(toolchain):
 | 
				
			|||||||
    with open(path, 'w') as f:
 | 
					    with open(path, 'w') as f:
 | 
				
			||||||
        f.write(f"""
 | 
					        f.write(f"""
 | 
				
			||||||
[binaries]
 | 
					[binaries]
 | 
				
			||||||
c = '{toolchain.cc}'
 | 
					c = '{__no_ccache(toolchain.cc)}'
 | 
				
			||||||
cpp = '{toolchain.cxx}'
 | 
					cpp = '{__no_ccache(toolchain.cxx)}'
 | 
				
			||||||
ar = '{toolchain.ar}'
 | 
					ar = '{toolchain.ar}'
 | 
				
			||||||
strip = '{toolchain.strip}'
 | 
					strip = '{toolchain.strip}'
 | 
				
			||||||
pkgconfig = '{toolchain.pkg_config}'
 | 
					pkgconfig = '{toolchain.pkg_config}'
 | 
				
			||||||
@@ -56,7 +63,7 @@ pkgconfig = '{toolchain.pkg_config}'
 | 
				
			|||||||
root = '{toolchain.install_prefix}'
 | 
					root = '{toolchain.install_prefix}'
 | 
				
			||||||
""")
 | 
					""")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if 'android' in toolchain.arch:
 | 
					        if toolchain.is_android:
 | 
				
			||||||
            f.write("""
 | 
					            f.write("""
 | 
				
			||||||
# Keep Meson from executing Android-x86 test binariees
 | 
					# Keep Meson from executing Android-x86 test binariees
 | 
				
			||||||
needs_exe_wrapper = true
 | 
					needs_exe_wrapper = true
 | 
				
			||||||
@@ -80,8 +87,7 @@ endian = '{endian}'
 | 
				
			|||||||
""")
 | 
					""")
 | 
				
			||||||
    return path
 | 
					    return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def configure(toolchain, src, build, args=()):
 | 
					def configure(toolchain: AnyToolchain, src: str, build: str, args: list[str]=[]) -> None:
 | 
				
			||||||
    cross_file = make_cross_file(toolchain)
 | 
					 | 
				
			||||||
    configure = [
 | 
					    configure = [
 | 
				
			||||||
        'meson', 'setup',
 | 
					        'meson', 'setup',
 | 
				
			||||||
        build, src,
 | 
					        build, src,
 | 
				
			||||||
@@ -91,10 +97,13 @@ def configure(toolchain, src, build, args=()):
 | 
				
			|||||||
        '--buildtype', 'plain',
 | 
					        '--buildtype', 'plain',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        '--default-library=static',
 | 
					        '--default-library=static',
 | 
				
			||||||
 | 
					 | 
				
			||||||
        '--cross-file', cross_file,
 | 
					 | 
				
			||||||
    ] + args
 | 
					    ] + args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if toolchain.host_triplet is not None:
 | 
				
			||||||
 | 
					        # cross-compiling: write a cross-file
 | 
				
			||||||
 | 
					        cross_file = make_cross_file(toolchain)
 | 
				
			||||||
 | 
					        configure.append(f'--cross-file={cross_file}')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    env = toolchain.env.copy()
 | 
					    env = toolchain.env.copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Meson 0.54 requires the BOOST_ROOT environment variable
 | 
					    # Meson 0.54 requires the BOOST_ROOT environment variable
 | 
				
			||||||
@@ -103,18 +112,19 @@ def configure(toolchain, src, build, args=()):
 | 
				
			|||||||
    subprocess.check_call(configure, env=env)
 | 
					    subprocess.check_call(configure, env=env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MesonProject(Project):
 | 
					class MesonProject(Project):
 | 
				
			||||||
    def __init__(self, url, md5, installed, configure_args=[],
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
 | 
					                 configure_args: list[str]=[],
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        Project.__init__(self, url, md5, installed, **kwargs)
 | 
					        Project.__init__(self, url, md5, installed, **kwargs)
 | 
				
			||||||
        self.configure_args = configure_args
 | 
					        self.configure_args = configure_args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def configure(self, toolchain):
 | 
					    def configure(self, toolchain: AnyToolchain) -> str:
 | 
				
			||||||
        src = self.unpack(toolchain)
 | 
					        src = self.unpack(toolchain)
 | 
				
			||||||
        build = self.make_build_path(toolchain)
 | 
					        build = self.make_build_path(toolchain)
 | 
				
			||||||
        configure(toolchain, src, build, self.configure_args)
 | 
					        configure(toolchain, src, build, self.configure_args)
 | 
				
			||||||
        return build
 | 
					        return build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _build(self, toolchain):
 | 
					    def _build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        build = self.configure(toolchain)
 | 
					        build = self.configure(toolchain)
 | 
				
			||||||
        subprocess.check_call(['ninja', '-v', 'install'],
 | 
					        subprocess.check_call(['ninja', '-v', 'install'],
 | 
				
			||||||
                              cwd=build, env=toolchain.env)
 | 
					                              cwd=build, env=toolchain.env)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,15 @@
 | 
				
			|||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from typing import Optional, Sequence, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.makeproject import MakeProject
 | 
					from build.makeproject import MakeProject
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class OpenSSLProject(MakeProject):
 | 
					class OpenSSLProject(MakeProject):
 | 
				
			||||||
    def __init__(self, url, md5, installed,
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        MakeProject.__init__(self, url, md5, installed, install_target='install_dev', **kwargs)
 | 
					        MakeProject.__init__(self, url, md5, installed, install_target='install_dev', **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_args(self, toolchain):
 | 
					    def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        return MakeProject.get_make_args(self, toolchain) + [
 | 
					        return MakeProject.get_make_args(self, toolchain) + [
 | 
				
			||||||
            'CC=' + toolchain.cc,
 | 
					            'CC=' + toolchain.cc,
 | 
				
			||||||
            'CFLAGS=' + toolchain.cflags,
 | 
					            'CFLAGS=' + toolchain.cflags,
 | 
				
			||||||
@@ -17,45 +19,60 @@ class OpenSSLProject(MakeProject):
 | 
				
			|||||||
            'build_libs',
 | 
					            'build_libs',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_install_args(self, toolchain):
 | 
					    def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        # OpenSSL's Makefile runs "ranlib" during installation
 | 
					        # OpenSSL's Makefile runs "ranlib" during installation
 | 
				
			||||||
        return MakeProject.get_make_install_args(self, toolchain) + [
 | 
					        return MakeProject.get_make_install_args(self, toolchain) + [
 | 
				
			||||||
            'RANLIB=' + toolchain.ranlib,
 | 
					            'RANLIB=' + toolchain.ranlib,
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _build(self, toolchain):
 | 
					    def _build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        src = self.unpack(toolchain, out_of_tree=False)
 | 
					        src = self.unpack(toolchain, out_of_tree=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # OpenSSL has a weird target architecture scheme with lots of
 | 
					        # OpenSSL has a weird target architecture scheme with lots of
 | 
				
			||||||
        # hard-coded architectures; this table translates between our
 | 
					        # hard-coded architectures; this table translates between our
 | 
				
			||||||
        # "toolchain_arch" (HOST_TRIPLET) and the OpenSSL target
 | 
					        # host triplet and the OpenSSL target
 | 
				
			||||||
        openssl_archs = {
 | 
					        openssl_archs = {
 | 
				
			||||||
            # not using "android-*" because those OpenSSL targets want
 | 
					            # not using "android-*" because those OpenSSL targets want
 | 
				
			||||||
            # to know where the SDK is, but our own build scripts
 | 
					            # to know where the SDK is, but our own build scripts
 | 
				
			||||||
            # prepared everything already to look like a regular Linux
 | 
					            # prepared everything already to look like a regular Linux
 | 
				
			||||||
            # build
 | 
					            # build
 | 
				
			||||||
            'arm-linux-androideabi': 'linux-generic32',
 | 
					            'armv7a-linux-androideabi': 'linux-generic32',
 | 
				
			||||||
            'aarch64-linux-android': 'linux-aarch64',
 | 
					            'aarch64-linux-android': 'linux-aarch64',
 | 
				
			||||||
            'i686-linux-android': 'linux-x86-clang',
 | 
					            'i686-linux-android': 'linux-x86-clang',
 | 
				
			||||||
            'x86_64-linux-android': 'linux-x86_64-clang',
 | 
					            'x86_64-linux-android': 'linux-x86_64-clang',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Kobo
 | 
					            # generic Linux
 | 
				
			||||||
            'arm-linux-gnueabihf': 'linux-generic32',
 | 
					            'arm-linux-gnueabihf': 'linux-generic32',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Windows
 | 
					            # Windows
 | 
				
			||||||
            'i686-w64-mingw32': 'mingw',
 | 
					            'i686-w64-mingw32': 'mingw',
 | 
				
			||||||
            'x86_64-w64-mingw32': 'mingw64',
 | 
					            'x86_64-w64-mingw32': 'mingw64',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Apple
 | 
				
			||||||
 | 
					            'x86_64-apple-darwin': 'darwin64-x86_64-cc',
 | 
				
			||||||
 | 
					            'aarch64-apple-darwin': 'darwin64-arm64-cc',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        openssl_arch = openssl_archs[toolchain.arch]
 | 
					        configure = [
 | 
				
			||||||
 | 
					            './Configure',
 | 
				
			||||||
 | 
					            'no-shared',
 | 
				
			||||||
 | 
					            'no-module',
 | 
				
			||||||
 | 
					            'no-engine',
 | 
				
			||||||
 | 
					            'no-static-engine',
 | 
				
			||||||
 | 
					            'no-async',
 | 
				
			||||||
 | 
					            'no-tests',
 | 
				
			||||||
 | 
					            'no-makedepend',
 | 
				
			||||||
 | 
					            '--libdir=lib', # no "lib64" on amd64, please
 | 
				
			||||||
 | 
					            '--prefix=' + toolchain.install_prefix,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subprocess.check_call(['./Configure',
 | 
					        if toolchain.is_windows:
 | 
				
			||||||
                               'no-shared',
 | 
					            # workaround for build failures
 | 
				
			||||||
                               'no-module', 'no-engine', 'no-static-engine',
 | 
					            configure.append('no-asm')
 | 
				
			||||||
                               'no-async',
 | 
					
 | 
				
			||||||
                               'no-tests',
 | 
					        if toolchain.host_triplet is not None:
 | 
				
			||||||
                               'no-asm', # "asm" causes build failures on Windows
 | 
					            configure.append(openssl_archs[toolchain.host_triplet])
 | 
				
			||||||
                               openssl_arch,
 | 
					            configure.append(f'--cross-compile-prefix={toolchain.host_triplet}-')
 | 
				
			||||||
                               '--prefix=' + toolchain.install_prefix],
 | 
					
 | 
				
			||||||
                              cwd=src, env=toolchain.env)
 | 
					        subprocess.check_call(configure, cwd=src, env=toolchain.env)
 | 
				
			||||||
        self.build_make(toolchain, src)
 | 
					        self.build_make(toolchain, src)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,21 @@
 | 
				
			|||||||
import os, shutil
 | 
					import os, shutil
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
 | 
					from typing import cast, BinaryIO, Optional, Sequence, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.download import download_and_verify
 | 
					from build.download import download_basename, download_and_verify
 | 
				
			||||||
from build.tar import untar
 | 
					from build.tar import untar
 | 
				
			||||||
from build.quilt import push_all
 | 
					from build.quilt import push_all
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Project:
 | 
					class Project:
 | 
				
			||||||
    def __init__(self, url, md5, installed, name=None, version=None,
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 base=None,
 | 
					                 name: Optional[str]=None, version: Optional[str]=None,
 | 
				
			||||||
                 patches=None,
 | 
					                 base: Optional[str]=None,
 | 
				
			||||||
 | 
					                 patches: Optional[str]=None,
 | 
				
			||||||
                 edits=None,
 | 
					                 edits=None,
 | 
				
			||||||
                 use_cxx=False):
 | 
					                 use_cxx: bool=False):
 | 
				
			||||||
        if base is None:
 | 
					        if base is None:
 | 
				
			||||||
            basename = os.path.basename(url)
 | 
					            basename = download_basename(url)
 | 
				
			||||||
            m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
 | 
					            m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
 | 
				
			||||||
            if not m: raise RuntimeError('Could not identify tarball name: ' + basename)
 | 
					            if not m: raise RuntimeError('Could not identify tarball name: ' + basename)
 | 
				
			||||||
            self.base = m.group(1)
 | 
					            self.base = m.group(1)
 | 
				
			||||||
@@ -39,10 +42,10 @@ class Project:
 | 
				
			|||||||
        self.edits = edits
 | 
					        self.edits = edits
 | 
				
			||||||
        self.use_cxx = use_cxx
 | 
					        self.use_cxx = use_cxx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def download(self, toolchain):
 | 
					    def download(self, toolchain: AnyToolchain) -> str:
 | 
				
			||||||
        return download_and_verify(self.url, self.md5, toolchain.tarball_path)
 | 
					        return download_and_verify(self.url, self.md5, toolchain.tarball_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def is_installed(self, toolchain):
 | 
					    def is_installed(self, toolchain: AnyToolchain) -> bool:
 | 
				
			||||||
        tarball = self.download(toolchain)
 | 
					        tarball = self.download(toolchain)
 | 
				
			||||||
        installed = os.path.join(toolchain.install_prefix, self.installed)
 | 
					        installed = os.path.join(toolchain.install_prefix, self.installed)
 | 
				
			||||||
        tarball_mtime = os.path.getmtime(tarball)
 | 
					        tarball_mtime = os.path.getmtime(tarball)
 | 
				
			||||||
@@ -51,7 +54,7 @@ class Project:
 | 
				
			|||||||
        except FileNotFoundError:
 | 
					        except FileNotFoundError:
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def unpack(self, toolchain, out_of_tree=True):
 | 
					    def unpack(self, toolchain: AnyToolchain, out_of_tree: bool=True) -> str:
 | 
				
			||||||
        if out_of_tree:
 | 
					        if out_of_tree:
 | 
				
			||||||
            parent_path = toolchain.src_path
 | 
					            parent_path = toolchain.src_path
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
@@ -72,7 +75,7 @@ class Project:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return path
 | 
					        return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def make_build_path(self, toolchain, lazy=False):
 | 
					    def make_build_path(self, toolchain: AnyToolchain, lazy: bool=False) -> str:
 | 
				
			||||||
        path = os.path.join(toolchain.build_path, self.base)
 | 
					        path = os.path.join(toolchain.build_path, self.base)
 | 
				
			||||||
        if lazy and os.path.isdir(path):
 | 
					        if lazy and os.path.isdir(path):
 | 
				
			||||||
            return path
 | 
					            return path
 | 
				
			||||||
@@ -83,5 +86,5 @@ class Project:
 | 
				
			|||||||
        os.makedirs(path, exist_ok=True)
 | 
					        os.makedirs(path, exist_ok=True)
 | 
				
			||||||
        return path
 | 
					        return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build(self, toolchain):
 | 
					    def build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        self._build(toolchain)
 | 
					        self._build(toolchain)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,12 @@
 | 
				
			|||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from typing import Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_quilt(toolchain, cwd, patches_path, *args):
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run_quilt(toolchain: AnyToolchain, cwd: str, patches_path: str, *args: str) -> None:
 | 
				
			||||||
    env = dict(toolchain.env)
 | 
					    env = dict(toolchain.env)
 | 
				
			||||||
    env['QUILT_PATCHES'] = patches_path
 | 
					    env['QUILT_PATCHES'] = patches_path
 | 
				
			||||||
    subprocess.check_call(['quilt'] + list(args), cwd=cwd, env=env)
 | 
					    subprocess.check_call(['quilt'] + list(args), cwd=cwd, env=env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def push_all(toolchain, src_path, patches_path):
 | 
					def push_all(toolchain: AnyToolchain, src_path: str, patches_path: str) -> None:
 | 
				
			||||||
    run_quilt(toolchain, src_path, patches_path, 'push', '-a')
 | 
					    run_quilt(toolchain, src_path, patches_path, 'push', '-a')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import os, shutil, subprocess
 | 
					import os, shutil, subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def untar(tarball_path, parent_path, base, lazy=False):
 | 
					def untar(tarball_path: str, parent_path: str, base: str,
 | 
				
			||||||
 | 
					          lazy: bool=False) -> str:
 | 
				
			||||||
    path = os.path.join(parent_path, base)
 | 
					    path = os.path.join(parent_path, base)
 | 
				
			||||||
    if lazy and os.path.isdir(path):
 | 
					    if lazy and os.path.isdir(path):
 | 
				
			||||||
        return path
 | 
					        return path
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										175
									
								
								python/build/toolchain.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								python/build/toolchain.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					import os.path
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					from typing import Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					android_abis = {
 | 
				
			||||||
 | 
					    'armeabi-v7a': {
 | 
				
			||||||
 | 
					        'arch': 'armv7a-linux-androideabi',
 | 
				
			||||||
 | 
					        'ndk_arch': 'arm',
 | 
				
			||||||
 | 
					        'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    'arm64-v8a': {
 | 
				
			||||||
 | 
					        'arch': 'aarch64-linux-android',
 | 
				
			||||||
 | 
					        'ndk_arch': 'arm64',
 | 
				
			||||||
 | 
					        'cflags': '-fpic',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    'x86': {
 | 
				
			||||||
 | 
					        'arch': 'i686-linux-android',
 | 
				
			||||||
 | 
					        'ndk_arch': 'x86',
 | 
				
			||||||
 | 
					        'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    'x86_64': {
 | 
				
			||||||
 | 
					        'arch': 'x86_64-linux-android',
 | 
				
			||||||
 | 
					        'ndk_arch': 'x86_64',
 | 
				
			||||||
 | 
					        'cflags': '-fPIC -m64',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AndroidNdkToolchain:
 | 
				
			||||||
 | 
					    def __init__(self, top_path: str, lib_path: str,
 | 
				
			||||||
 | 
					                 tarball_path: str, src_path: str,
 | 
				
			||||||
 | 
					                 ndk_path: str, android_abi: str,
 | 
				
			||||||
 | 
					                 use_cxx):
 | 
				
			||||||
 | 
					        # build host configuration
 | 
				
			||||||
 | 
					        build_arch = 'linux-x86_64'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # select the NDK target
 | 
				
			||||||
 | 
					        abi_info = android_abis[android_abi]
 | 
				
			||||||
 | 
					        host_triplet = abi_info['arch']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        arch_path = os.path.join(lib_path, host_triplet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.tarball_path = tarball_path
 | 
				
			||||||
 | 
					        self.src_path = src_path
 | 
				
			||||||
 | 
					        self.build_path = os.path.join(arch_path, 'build')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ndk_arch = abi_info['ndk_arch']
 | 
				
			||||||
 | 
					        android_api_level = '24'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        install_prefix = os.path.join(arch_path, 'root')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.host_triplet = host_triplet
 | 
				
			||||||
 | 
					        self.install_prefix = install_prefix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
 | 
				
			||||||
 | 
					        llvm_triple = host_triplet + android_api_level
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        common_flags = '-Os -g'
 | 
				
			||||||
 | 
					        common_flags += ' ' + abi_info['cflags']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        llvm_bin = os.path.join(llvm_path, 'bin')
 | 
				
			||||||
 | 
					        self.cc = os.path.join(llvm_bin, 'clang')
 | 
				
			||||||
 | 
					        self.cxx = os.path.join(llvm_bin, 'clang++')
 | 
				
			||||||
 | 
					        common_flags += ' -target ' + llvm_triple
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ar = os.path.join(llvm_bin, 'llvm-ar')
 | 
				
			||||||
 | 
					        self.arflags = 'rcs'
 | 
				
			||||||
 | 
					        self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
 | 
				
			||||||
 | 
					        self.nm = os.path.join(llvm_bin, 'llvm-nm')
 | 
				
			||||||
 | 
					        self.strip = os.path.join(llvm_bin, 'llvm-strip')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.cflags = common_flags
 | 
				
			||||||
 | 
					        self.cxxflags = common_flags
 | 
				
			||||||
 | 
					        self.cppflags = ' -isystem ' + os.path.join(install_prefix, 'include')
 | 
				
			||||||
 | 
					        self.ldflags = ' -L' + os.path.join(install_prefix, 'lib') + \
 | 
				
			||||||
 | 
					            ' -Wl,--exclude-libs=ALL' + \
 | 
				
			||||||
 | 
					            ' ' + common_flags
 | 
				
			||||||
 | 
					        self.ldflags = common_flags
 | 
				
			||||||
 | 
					        self.libs = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_arm = ndk_arch == 'arm'
 | 
				
			||||||
 | 
					        self.is_armv7 = self.is_arm and 'armv7' in self.cflags
 | 
				
			||||||
 | 
					        self.is_aarch64 = ndk_arch == 'arm64'
 | 
				
			||||||
 | 
					        self.is_windows = False
 | 
				
			||||||
 | 
					        self.is_android = True
 | 
				
			||||||
 | 
					        self.is_darwin = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        libstdcxx_flags = ''
 | 
				
			||||||
 | 
					        libstdcxx_cxxflags = ''
 | 
				
			||||||
 | 
					        libstdcxx_ldflags = ''
 | 
				
			||||||
 | 
					        libstdcxx_libs = '-static-libstdc++'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.is_armv7:
 | 
				
			||||||
 | 
					            # On 32 bit ARM, clang generates no ".eh_frame" section;
 | 
				
			||||||
 | 
					            # instead, the LLVM unwinder library is used for unwinding
 | 
				
			||||||
 | 
					            # the stack after a C++ exception was thrown
 | 
				
			||||||
 | 
					            libstdcxx_libs += ' -lunwind'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if use_cxx:
 | 
				
			||||||
 | 
					            self.cxxflags += ' ' + libstdcxx_cxxflags
 | 
				
			||||||
 | 
					            self.ldflags += ' ' + libstdcxx_ldflags
 | 
				
			||||||
 | 
					            self.libs += ' ' + libstdcxx_libs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.env = dict(os.environ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # redirect pkg-config to use our root directory instead of the
 | 
				
			||||||
 | 
					        # default one on the build host
 | 
				
			||||||
 | 
					        bin_dir = os.path.join(install_prefix, 'bin')
 | 
				
			||||||
 | 
					        os.makedirs(bin_dir, exist_ok=True)
 | 
				
			||||||
 | 
					        self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
 | 
				
			||||||
 | 
					                                      os.path.join(bin_dir, 'pkg-config'))
 | 
				
			||||||
 | 
					        self.env['PKG_CONFIG'] = self.pkg_config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MingwToolchain:
 | 
				
			||||||
 | 
					    def __init__(self, top_path: str,
 | 
				
			||||||
 | 
					                 toolchain_path, host_triplet, x64: bool,
 | 
				
			||||||
 | 
					                 tarball_path, src_path, build_path, install_prefix):
 | 
				
			||||||
 | 
					        self.host_triplet = host_triplet
 | 
				
			||||||
 | 
					        self.tarball_path = tarball_path
 | 
				
			||||||
 | 
					        self.src_path = src_path
 | 
				
			||||||
 | 
					        self.build_path = build_path
 | 
				
			||||||
 | 
					        self.install_prefix = install_prefix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        toolchain_bin = os.path.join(toolchain_path, 'bin')
 | 
				
			||||||
 | 
					        self.cc = os.path.join(toolchain_bin, host_triplet + '-gcc')
 | 
				
			||||||
 | 
					        self.cxx = os.path.join(toolchain_bin, host_triplet + '-g++')
 | 
				
			||||||
 | 
					        self.ar = os.path.join(toolchain_bin, host_triplet + '-ar')
 | 
				
			||||||
 | 
					        self.arflags = 'rcs'
 | 
				
			||||||
 | 
					        self.ranlib = os.path.join(toolchain_bin, host_triplet + '-ranlib')
 | 
				
			||||||
 | 
					        self.nm = os.path.join(toolchain_bin, host_triplet + '-nm')
 | 
				
			||||||
 | 
					        self.strip = os.path.join(toolchain_bin, host_triplet + '-strip')
 | 
				
			||||||
 | 
					        self.windres = os.path.join(toolchain_bin, host_triplet + '-windres')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        common_flags = '-O2 -g'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not x64:
 | 
				
			||||||
 | 
					            # enable SSE support which is required for LAME
 | 
				
			||||||
 | 
					            common_flags += ' -march=pentium3'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.cflags = common_flags
 | 
				
			||||||
 | 
					        self.cxxflags = common_flags
 | 
				
			||||||
 | 
					        self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
 | 
				
			||||||
 | 
					                        ' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
 | 
				
			||||||
 | 
					        self.ldflags = '-L' + os.path.join(install_prefix, 'lib') + \
 | 
				
			||||||
 | 
					                       ' -static-libstdc++ -static-libgcc'
 | 
				
			||||||
 | 
					        self.libs = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Explicitly disable _FORTIFY_SOURCE because it is broken with
 | 
				
			||||||
 | 
					        # mingw.  This prevents some libraries such as libFLAC to
 | 
				
			||||||
 | 
					        # enable it.
 | 
				
			||||||
 | 
					        self.cppflags += ' -D_FORTIFY_SOURCE=0'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.is_arm = host_triplet.startswith('arm')
 | 
				
			||||||
 | 
					        self.is_armv7 = self.is_arm and 'armv7' in self.cflags
 | 
				
			||||||
 | 
					        self.is_aarch64 = host_triplet == 'aarch64'
 | 
				
			||||||
 | 
					        self.is_windows = 'mingw32' in host_triplet
 | 
				
			||||||
 | 
					        self.is_android = False
 | 
				
			||||||
 | 
					        self.is_darwin = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.env = dict(os.environ)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # redirect pkg-config to use our root directory instead of the
 | 
				
			||||||
 | 
					        # default one on the build host
 | 
				
			||||||
 | 
					        import shutil
 | 
				
			||||||
 | 
					        bin_dir = os.path.join(install_prefix, 'bin')
 | 
				
			||||||
 | 
					        os.makedirs(bin_dir, exist_ok=True)
 | 
				
			||||||
 | 
					        self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
 | 
				
			||||||
 | 
					                                      os.path.join(bin_dir, 'pkg-config'))
 | 
				
			||||||
 | 
					        self.env['PKG_CONFIG'] = self.pkg_config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AnyToolchain = Union[AndroidNdkToolchain, MingwToolchain]
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import hashlib
 | 
					import hashlib
 | 
				
			||||||
 | 
					from typing import cast, Any, BinaryIO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def feed_file(h, f):
 | 
					def feed_file(h: Any, f: BinaryIO) -> None:
 | 
				
			||||||
    """Feed data read from an open file into the hashlib instance."""
 | 
					    """Feed data read from an open file into the hashlib instance."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
@@ -10,20 +11,20 @@ def feed_file(h, f):
 | 
				
			|||||||
            break
 | 
					            break
 | 
				
			||||||
        h.update(data)
 | 
					        h.update(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def feed_file_path(h, path):
 | 
					def feed_file_path(h: Any, path: str) -> None:
 | 
				
			||||||
    """Feed data read from a file (to be opened by this function) into the hashlib instance."""
 | 
					    """Feed data read from a file (to be opened by this function) into the hashlib instance."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    with open(path, 'rb') as f:
 | 
					    with open(path, 'rb') as f:
 | 
				
			||||||
        feed_file(h, f)
 | 
					        feed_file(h, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def file_digest(algorithm, path):
 | 
					def file_digest(algorithm: Any, path: str) -> str:
 | 
				
			||||||
    """Calculate the digest of a file and return it in hexadecimal notation."""
 | 
					    """Calculate the digest of a file and return it in hexadecimal notation."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    h = algorithm()
 | 
					    h = algorithm()
 | 
				
			||||||
    feed_file_path(h, path)
 | 
					    feed_file_path(h, path)
 | 
				
			||||||
    return h.hexdigest()
 | 
					    return cast(str, h.hexdigest())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def guess_digest_algorithm(digest):
 | 
					def guess_digest_algorithm(digest: str) -> Any:
 | 
				
			||||||
    l = len(digest)
 | 
					    l = len(digest)
 | 
				
			||||||
    if l == 32:
 | 
					    if l == 32:
 | 
				
			||||||
        return hashlib.md5
 | 
					        return hashlib.md5
 | 
				
			||||||
@@ -36,7 +37,7 @@ def guess_digest_algorithm(digest):
 | 
				
			|||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def verify_file_digest(path, expected_digest):
 | 
					def verify_file_digest(path: str, expected_digest: str) -> bool:
 | 
				
			||||||
    """Verify the digest of a file, and return True if the digest matches with the given expected digest."""
 | 
					    """Verify the digest of a file, and return True if the digest matches with the given expected digest."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    algorithm = guess_digest_algorithm(expected_digest)
 | 
					    algorithm = guess_digest_algorithm(expected_digest)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,15 @@
 | 
				
			|||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					from typing import Optional, Sequence, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from build.makeproject import MakeProject
 | 
					from build.makeproject import MakeProject
 | 
				
			||||||
 | 
					from .toolchain import AnyToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ZlibProject(MakeProject):
 | 
					class ZlibProject(MakeProject):
 | 
				
			||||||
    def __init__(self, url, md5, installed,
 | 
					    def __init__(self, url: Union[str, Sequence[str]], md5: str, installed: str,
 | 
				
			||||||
                 **kwargs):
 | 
					                 **kwargs):
 | 
				
			||||||
        MakeProject.__init__(self, url, md5, installed, **kwargs)
 | 
					        MakeProject.__init__(self, url, md5, installed, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_args(self, toolchain):
 | 
					    def get_make_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        return MakeProject.get_make_args(self, toolchain) + [
 | 
					        return MakeProject.get_make_args(self, toolchain) + [
 | 
				
			||||||
            'CC=' + toolchain.cc + ' ' + toolchain.cppflags + ' ' + toolchain.cflags,
 | 
					            'CC=' + toolchain.cc + ' ' + toolchain.cppflags + ' ' + toolchain.cflags,
 | 
				
			||||||
            'CPP=' + toolchain.cc + ' -E ' + toolchain.cppflags,
 | 
					            'CPP=' + toolchain.cc + ' -E ' + toolchain.cppflags,
 | 
				
			||||||
@@ -18,13 +20,13 @@ class ZlibProject(MakeProject):
 | 
				
			|||||||
            'libz.a'
 | 
					            'libz.a'
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_make_install_args(self, toolchain):
 | 
					    def get_make_install_args(self, toolchain: AnyToolchain) -> list[str]:
 | 
				
			||||||
        return [
 | 
					        return [
 | 
				
			||||||
            'RANLIB=' + toolchain.ranlib,
 | 
					            'RANLIB=' + toolchain.ranlib,
 | 
				
			||||||
            self.install_target
 | 
					            self.install_target
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _build(self, toolchain):
 | 
					    def _build(self, toolchain: AnyToolchain) -> None:
 | 
				
			||||||
        src = self.unpack(toolchain, out_of_tree=False)
 | 
					        src = self.unpack(toolchain, out_of_tree=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        subprocess.check_call(['./configure', '--prefix=' + toolchain.install_prefix, '--static'],
 | 
					        subprocess.check_call(['./configure', '--prefix=' + toolchain.install_prefix, '--static'],
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <fmt/format.h>
 | 
					#include <fmt/format.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iterator> // for std::back_inserter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static constexpr Domain exception_domain("exception");
 | 
					static constexpr Domain exception_domain("exception");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -153,7 +153,7 @@ update_directory_stat(Storage &storage, Directory &directory) noexcept
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
FindAncestorLoop(Storage &storage, Directory *parent,
 | 
					FindAncestorLoop(Storage &storage, Directory *parent,
 | 
				
			||||||
		 unsigned inode, unsigned device) noexcept
 | 
							 uint64_t inode, uint64_t device) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifndef _WIN32
 | 
					#ifndef _WIN32
 | 
				
			||||||
	if (device == 0 && inode == 0)
 | 
						if (device == 0 && inode == 0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#include <libavutil/mem.h>
 | 
					#include <libavutil/mem.h>
 | 
				
			||||||
 | 
					#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(58, 29, 100)
 | 
				
			||||||
 | 
					#include <libavutil/error.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AvioStream::~AvioStream()
 | 
					AvioStream::~AvioStream()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bool
 | 
					bool
 | 
				
			||||||
FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
 | 
					FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
 | 
				
			||||||
			unsigned channels, FLAC__uint64 total_frames)
 | 
								unsigned channels, FLAC__uint64 total_frames) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(!initialized);
 | 
						assert(!initialized);
 | 
				
			||||||
	assert(!unsupported);
 | 
						assert(!unsupported);
 | 
				
			||||||
@@ -60,7 +60,7 @@ FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void
 | 
					inline void
 | 
				
			||||||
FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info)
 | 
					FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (initialized)
 | 
						if (initialized)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -72,7 +72,7 @@ FlacDecoder::OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void
 | 
					inline void
 | 
				
			||||||
FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
 | 
					FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ReplayGainInfo rgi;
 | 
						ReplayGainInfo rgi;
 | 
				
			||||||
	if (flac_parse_replay_gain(rgi, vc))
 | 
						if (flac_parse_replay_gain(rgi, vc))
 | 
				
			||||||
@@ -86,7 +86,7 @@ FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata)
 | 
					FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (unsupported)
 | 
						if (unsupported)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
@@ -106,7 +106,7 @@ FlacDecoder::OnMetadata(const FLAC__StreamMetadata &metadata)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline bool
 | 
					inline bool
 | 
				
			||||||
FlacDecoder::OnFirstFrame(const FLAC__FrameHeader &header)
 | 
					FlacDecoder::OnFirstFrame(const FLAC__FrameHeader &header) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (unsupported)
 | 
						if (unsupported)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
@@ -139,7 +139,7 @@ FlacDecoder::GetDeltaPosition(const FLAC__StreamDecoder &sd)
 | 
				
			|||||||
FLAC__StreamDecoderWriteStatus
 | 
					FLAC__StreamDecoderWriteStatus
 | 
				
			||||||
FlacDecoder::OnWrite(const FLAC__Frame &frame,
 | 
					FlacDecoder::OnWrite(const FLAC__Frame &frame,
 | 
				
			||||||
		     const FLAC__int32 *const buf[],
 | 
							     const FLAC__int32 *const buf[],
 | 
				
			||||||
		     FLAC__uint64 nbytes)
 | 
							     FLAC__uint64 nbytes) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!initialized && !OnFirstFrame(frame.header))
 | 
						if (!initialized && !OnFirstFrame(frame.header))
 | 
				
			||||||
		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | 
							return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -65,20 +65,21 @@ struct FlacDecoder : public FlacInput {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	ConstBuffer<void> chunk = nullptr;
 | 
						ConstBuffer<void> chunk = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FlacDecoder(DecoderClient &_client, InputStream &_input_stream)
 | 
						FlacDecoder(DecoderClient &_client,
 | 
				
			||||||
 | 
							    InputStream &_input_stream) noexcept
 | 
				
			||||||
		:FlacInput(_input_stream, &_client) {}
 | 
							:FlacInput(_input_stream, &_client) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Wrapper for DecoderClient::Ready().
 | 
						 * Wrapper for DecoderClient::Ready().
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
 | 
						bool Initialize(unsigned sample_rate, unsigned bits_per_sample,
 | 
				
			||||||
			unsigned channels, FLAC__uint64 total_frames);
 | 
								unsigned channels, FLAC__uint64 total_frames) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void OnMetadata(const FLAC__StreamMetadata &metadata);
 | 
						void OnMetadata(const FLAC__StreamMetadata &metadata) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FLAC__StreamDecoderWriteStatus OnWrite(const FLAC__Frame &frame,
 | 
						FLAC__StreamDecoderWriteStatus OnWrite(const FLAC__Frame &frame,
 | 
				
			||||||
					       const FLAC__int32 *const buf[],
 | 
										       const FLAC__int32 *const buf[],
 | 
				
			||||||
					       FLAC__uint64 nbytes);
 | 
										       FLAC__uint64 nbytes) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Calculate the delta (in bytes) between the last frame and
 | 
						 * Calculate the delta (in bytes) between the last frame and
 | 
				
			||||||
@@ -87,8 +88,8 @@ struct FlacDecoder : public FlacInput {
 | 
				
			|||||||
	FLAC__uint64 GetDeltaPosition(const FLAC__StreamDecoder &sd);
 | 
						FLAC__uint64 GetDeltaPosition(const FLAC__StreamDecoder &sd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info);
 | 
						void OnStreamInfo(const FLAC__StreamMetadata_StreamInfo &stream_info) noexcept;
 | 
				
			||||||
	void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc);
 | 
						void OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * This function attempts to call DecoderClient::Ready() in case there
 | 
						 * This function attempts to call DecoderClient::Ready() in case there
 | 
				
			||||||
@@ -97,7 +98,7 @@ private:
 | 
				
			|||||||
	 * providing the STREAMINFO block from the beginning of the file
 | 
						 * providing the STREAMINFO block from the beginning of the file
 | 
				
			||||||
	 * (e.g. when seeking with SqueezeBox Server).
 | 
						 * (e.g. when seeking with SqueezeBox Server).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	bool OnFirstFrame(const FLAC__FrameHeader &header);
 | 
						bool OnFirstFrame(const FLAC__FrameHeader &header) noexcept;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _FLAC_COMMON_H */
 | 
					#endif /* _FLAC_COMMON_H */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
#include "lib/xiph/FlacMetadataChain.hxx"
 | 
					#include "lib/xiph/FlacMetadataChain.hxx"
 | 
				
			||||||
#include "OggCodec.hxx"
 | 
					#include "OggCodec.hxx"
 | 
				
			||||||
#include "input/InputStream.hxx"
 | 
					#include "input/InputStream.hxx"
 | 
				
			||||||
 | 
					#include "input/LocalOpen.hxx"
 | 
				
			||||||
#include "fs/Path.hxx"
 | 
					#include "fs/Path.hxx"
 | 
				
			||||||
#include "fs/NarrowPath.hxx"
 | 
					#include "fs/NarrowPath.hxx"
 | 
				
			||||||
#include "Log.hxx"
 | 
					#include "Log.hxx"
 | 
				
			||||||
@@ -32,7 +33,8 @@
 | 
				
			|||||||
#error libFLAC is too old
 | 
					#error libFLAC is too old
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void flacPrintErroredState(FLAC__StreamDecoderState state)
 | 
					static void
 | 
				
			||||||
 | 
					flacPrintErroredState(FLAC__StreamDecoderState state) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	switch (state) {
 | 
						switch (state) {
 | 
				
			||||||
	case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
 | 
						case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
 | 
				
			||||||
@@ -53,8 +55,9 @@ static void flacPrintErroredState(FLAC__StreamDecoderState state)
 | 
				
			|||||||
	LogError(flac_domain, FLAC__StreamDecoderStateString[state]);
 | 
						LogError(flac_domain, FLAC__StreamDecoderStateString[state]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
 | 
					static void
 | 
				
			||||||
			 const FLAC__StreamMetadata * block, void *vdata)
 | 
					flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
 | 
				
			||||||
 | 
						     const FLAC__StreamMetadata * block, void *vdata) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &fd = *(FlacDecoder *)vdata;
 | 
						auto &fd = *(FlacDecoder *)vdata;
 | 
				
			||||||
	fd.OnMetadata(*block);
 | 
						fd.OnMetadata(*block);
 | 
				
			||||||
@@ -62,29 +65,45 @@ static void flacMetadata([[maybe_unused]] const FLAC__StreamDecoder * dec,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static FLAC__StreamDecoderWriteStatus
 | 
					static FLAC__StreamDecoderWriteStatus
 | 
				
			||||||
flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
 | 
					flac_write_cb(const FLAC__StreamDecoder *dec, const FLAC__Frame *frame,
 | 
				
			||||||
	      const FLAC__int32 *const buf[], void *vdata)
 | 
						      const FLAC__int32 *const buf[], void *vdata) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto &fd = *(FlacDecoder *)vdata;
 | 
						auto &fd = *(FlacDecoder *)vdata;
 | 
				
			||||||
	return fd.OnWrite(*frame, buf, fd.GetDeltaPosition(*dec));
 | 
						return fd.OnWrite(*frame, buf, fd.GetDeltaPosition(*dec));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
flac_scan_file(Path path_fs, TagHandler &handler)
 | 
					flac_scan_file(Path path_fs, TagHandler &handler) noexcept {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	FlacMetadataChain chain;
 | 
						FlacMetadataChain chain;
 | 
				
			||||||
	if (!chain.Read(NarrowPath(path_fs))) {
 | 
						const bool succeed = [&chain, &path_fs]() noexcept {
 | 
				
			||||||
 | 
							// read by NarrowPath
 | 
				
			||||||
 | 
							if (chain.Read(NarrowPath(path_fs))) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (std::is_same_v<Path::value_type, char> ||
 | 
				
			||||||
 | 
							    chain.GetStatus() != FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// read by InputStream
 | 
				
			||||||
 | 
							Mutex mutex;
 | 
				
			||||||
 | 
							auto is = OpenLocalInputStream(path_fs, mutex);
 | 
				
			||||||
 | 
							if (is && chain.Read(*is)) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!succeed) {
 | 
				
			||||||
		FmtDebug(flac_domain,
 | 
							FmtDebug(flac_domain,
 | 
				
			||||||
			 "Failed to read FLAC tags: {}",
 | 
								 "Failed to read FLAC tags: {}",
 | 
				
			||||||
			 chain.GetStatusString());
 | 
								 chain.GetStatusString());
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	chain.Scan(handler);
 | 
						chain.Scan(handler);
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
flac_scan_stream(InputStream &is, TagHandler &handler)
 | 
					flac_scan_stream(InputStream &is, TagHandler &handler) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FlacMetadataChain chain;
 | 
						FlacMetadataChain chain;
 | 
				
			||||||
	if (!chain.Read(is)) {
 | 
						if (!chain.Read(is)) {
 | 
				
			||||||
@@ -102,7 +121,7 @@ flac_scan_stream(InputStream &is, TagHandler &handler)
 | 
				
			|||||||
 * Some glue code around FLAC__stream_decoder_new().
 | 
					 * Some glue code around FLAC__stream_decoder_new().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static FlacStreamDecoder
 | 
					static FlacStreamDecoder
 | 
				
			||||||
flac_decoder_new()
 | 
					flac_decoder_new() noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FlacStreamDecoder sd;
 | 
						FlacStreamDecoder sd;
 | 
				
			||||||
	if(!FLAC__stream_decoder_set_metadata_respond(sd.get(), FLAC__METADATA_TYPE_VORBIS_COMMENT))
 | 
						if(!FLAC__stream_decoder_set_metadata_respond(sd.get(), FLAC__METADATA_TYPE_VORBIS_COMMENT))
 | 
				
			||||||
@@ -113,7 +132,7 @@ flac_decoder_new()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd)
 | 
					flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!FLAC__stream_decoder_process_until_end_of_metadata(sd)) {
 | 
						if (!FLAC__stream_decoder_process_until_end_of_metadata(sd)) {
 | 
				
			||||||
		if (FLAC__stream_decoder_get_state(sd) != FLAC__STREAM_DECODER_END_OF_STREAM)
 | 
							if (FLAC__stream_decoder_get_state(sd) != FLAC__STREAM_DECODER_END_OF_STREAM)
 | 
				
			||||||
@@ -231,7 +250,7 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FLAC__StreamDecoderInitStatus
 | 
					static FLAC__StreamDecoderInitStatus
 | 
				
			||||||
stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
 | 
					stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return FLAC__stream_decoder_init_ogg_stream(flac_dec,
 | 
						return FLAC__stream_decoder_init_ogg_stream(flac_dec,
 | 
				
			||||||
						    FlacInput::Read,
 | 
											    FlacInput::Read,
 | 
				
			||||||
@@ -246,7 +265,7 @@ stream_init_oggflac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FLAC__StreamDecoderInitStatus
 | 
					static FLAC__StreamDecoderInitStatus
 | 
				
			||||||
stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
 | 
					stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return FLAC__stream_decoder_init_stream(flac_dec,
 | 
						return FLAC__stream_decoder_init_stream(flac_dec,
 | 
				
			||||||
						FlacInput::Read,
 | 
											FlacInput::Read,
 | 
				
			||||||
@@ -261,7 +280,8 @@ stream_init_flac(FLAC__StreamDecoder *flac_dec, FlacDecoder *data)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static FLAC__StreamDecoderInitStatus
 | 
					static FLAC__StreamDecoderInitStatus
 | 
				
			||||||
stream_init(FLAC__StreamDecoder *flac_dec, FlacDecoder *data, bool is_ogg)
 | 
					stream_init(FLAC__StreamDecoder *flac_dec, FlacDecoder *data,
 | 
				
			||||||
 | 
						    bool is_ogg) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return is_ogg
 | 
						return is_ogg
 | 
				
			||||||
		? stream_init_oggflac(flac_dec, data)
 | 
							? stream_init_oggflac(flac_dec, data)
 | 
				
			||||||
@@ -307,7 +327,7 @@ flac_decode(DecoderClient &client, InputStream &input_stream)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
oggflac_init([[maybe_unused]] const ConfigBlock &block)
 | 
					oggflac_init([[maybe_unused]] const ConfigBlock &block) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return !!FLAC_API_SUPPORTS_OGG_FLAC;
 | 
						return !!FLAC_API_SUPPORTS_OGG_FLAC;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,12 +22,11 @@
 | 
				
			|||||||
#include "../DecoderAPI.hxx"
 | 
					#include "../DecoderAPI.hxx"
 | 
				
			||||||
#include "input/InputStream.hxx"
 | 
					#include "input/InputStream.hxx"
 | 
				
			||||||
#include "Log.hxx"
 | 
					#include "Log.hxx"
 | 
				
			||||||
#include "util/Compiler.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <exception>
 | 
					#include <exception>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderReadStatus
 | 
					inline FLAC__StreamDecoderReadStatus
 | 
				
			||||||
FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
 | 
					FlacInput::Read(FLAC__byte buffer[], size_t *bytes) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes);
 | 
						size_t r = decoder_read(client, input_stream, (void *)buffer, *bytes);
 | 
				
			||||||
	*bytes = r;
 | 
						*bytes = r;
 | 
				
			||||||
@@ -44,8 +43,8 @@ FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
 | 
				
			|||||||
	return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
 | 
						return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderSeekStatus
 | 
					inline FLAC__StreamDecoderSeekStatus
 | 
				
			||||||
FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
 | 
					FlacInput::Seek(FLAC__uint64 absolute_byte_offset) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!input_stream.IsSeekable())
 | 
						if (!input_stream.IsSeekable())
 | 
				
			||||||
		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
 | 
							return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
 | 
				
			||||||
@@ -59,8 +58,8 @@ FlacInput::Seek(FLAC__uint64 absolute_byte_offset)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderTellStatus
 | 
					inline FLAC__StreamDecoderTellStatus
 | 
				
			||||||
FlacInput::Tell(FLAC__uint64 *absolute_byte_offset)
 | 
					FlacInput::Tell(FLAC__uint64 *absolute_byte_offset) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!input_stream.IsSeekable())
 | 
						if (!input_stream.IsSeekable())
 | 
				
			||||||
		return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
 | 
							return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
 | 
				
			||||||
@@ -69,8 +68,8 @@ FlacInput::Tell(FLAC__uint64 *absolute_byte_offset)
 | 
				
			|||||||
	return FLAC__STREAM_DECODER_TELL_STATUS_OK;
 | 
						return FLAC__STREAM_DECODER_TELL_STATUS_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderLengthStatus
 | 
					inline FLAC__StreamDecoderLengthStatus
 | 
				
			||||||
FlacInput::Length(FLAC__uint64 *stream_length)
 | 
					FlacInput::Length(FLAC__uint64 *stream_length) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!input_stream.KnownSize())
 | 
						if (!input_stream.KnownSize())
 | 
				
			||||||
		return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
 | 
							return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
 | 
				
			||||||
@@ -79,8 +78,8 @@ FlacInput::Length(FLAC__uint64 *stream_length)
 | 
				
			|||||||
	return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 | 
						return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FLAC__bool
 | 
					inline FLAC__bool
 | 
				
			||||||
FlacInput::Eof()
 | 
					FlacInput::Eof() noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return (client != nullptr &&
 | 
						return (client != nullptr &&
 | 
				
			||||||
		client->GetCommand() != DecoderCommand::NONE &&
 | 
							client->GetCommand() != DecoderCommand::NONE &&
 | 
				
			||||||
@@ -88,8 +87,8 @@ FlacInput::Eof()
 | 
				
			|||||||
		input_stream.LockIsEOF();
 | 
							input_stream.LockIsEOF();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					inline void
 | 
				
			||||||
FlacInput::Error(FLAC__StreamDecoderErrorStatus status)
 | 
					FlacInput::Error(FLAC__StreamDecoderErrorStatus status) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (client == nullptr ||
 | 
						if (client == nullptr ||
 | 
				
			||||||
	    client->GetCommand() != DecoderCommand::STOP)
 | 
						    client->GetCommand() != DecoderCommand::STOP)
 | 
				
			||||||
@@ -100,7 +99,7 @@ FlacInput::Error(FLAC__StreamDecoderErrorStatus status)
 | 
				
			|||||||
FLAC__StreamDecoderReadStatus
 | 
					FLAC__StreamDecoderReadStatus
 | 
				
			||||||
FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
					FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
		FLAC__byte buffer[], size_t *bytes,
 | 
							FLAC__byte buffer[], size_t *bytes,
 | 
				
			||||||
		void *client_data)
 | 
							void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,7 +108,7 @@ FlacInput::Read([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderSeekStatus
 | 
					FLAC__StreamDecoderSeekStatus
 | 
				
			||||||
FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
					FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
		FLAC__uint64 absolute_byte_offset, void *client_data)
 | 
							FLAC__uint64 absolute_byte_offset, void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -118,7 +117,7 @@ FlacInput::Seek([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderTellStatus
 | 
					FLAC__StreamDecoderTellStatus
 | 
				
			||||||
FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
					FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
		FLAC__uint64 *absolute_byte_offset, void *client_data)
 | 
							FLAC__uint64 *absolute_byte_offset, void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -127,7 +126,7 @@ FlacInput::Tell([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FLAC__StreamDecoderLengthStatus
 | 
					FLAC__StreamDecoderLengthStatus
 | 
				
			||||||
FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
					FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
		  FLAC__uint64 *stream_length, void *client_data)
 | 
							  FLAC__uint64 *stream_length, void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -136,7 +135,7 @@ FlacInput::Length([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FLAC__bool
 | 
					FLAC__bool
 | 
				
			||||||
FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
					FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
	       void *client_data)
 | 
						       void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -145,7 +144,8 @@ FlacInput::Eof([[maybe_unused]] const FLAC__StreamDecoder *flac_decoder,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
FlacInput::Error([[maybe_unused]] const FLAC__StreamDecoder *decoder,
 | 
					FlacInput::Error([[maybe_unused]] const FLAC__StreamDecoder *decoder,
 | 
				
			||||||
		 FLAC__StreamDecoderErrorStatus status, void *client_data)
 | 
							 FLAC__StreamDecoderErrorStatus status,
 | 
				
			||||||
 | 
							 void *client_data) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	auto *i = (FlacInput *)client_data;
 | 
						auto *i = (FlacInput *)client_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,36 +48,38 @@ public:
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	FLAC__StreamDecoderReadStatus Read(FLAC__byte buffer[], size_t *bytes);
 | 
						FLAC__StreamDecoderReadStatus Read(FLAC__byte buffer[], size_t *bytes) noexcept;
 | 
				
			||||||
	FLAC__StreamDecoderSeekStatus Seek(FLAC__uint64 absolute_byte_offset);
 | 
						FLAC__StreamDecoderSeekStatus Seek(FLAC__uint64 absolute_byte_offset) noexcept;
 | 
				
			||||||
	FLAC__StreamDecoderTellStatus Tell(FLAC__uint64 *absolute_byte_offset);
 | 
						FLAC__StreamDecoderTellStatus Tell(FLAC__uint64 *absolute_byte_offset) noexcept;
 | 
				
			||||||
	FLAC__StreamDecoderLengthStatus Length(FLAC__uint64 *stream_length);
 | 
						FLAC__StreamDecoderLengthStatus Length(FLAC__uint64 *stream_length) noexcept;
 | 
				
			||||||
	FLAC__bool Eof();
 | 
						FLAC__bool Eof() noexcept;
 | 
				
			||||||
	void Error(FLAC__StreamDecoderErrorStatus status);
 | 
						void Error(FLAC__StreamDecoderErrorStatus status) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	static FLAC__StreamDecoderReadStatus
 | 
						static FLAC__StreamDecoderReadStatus
 | 
				
			||||||
	Read(const FLAC__StreamDecoder *flac_decoder,
 | 
						Read(const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
	     FLAC__byte buffer[], size_t *bytes, void *client_data);
 | 
						     FLAC__byte buffer[], size_t *bytes, void *client_data) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static FLAC__StreamDecoderSeekStatus
 | 
						static FLAC__StreamDecoderSeekStatus
 | 
				
			||||||
	Seek(const FLAC__StreamDecoder *flac_decoder,
 | 
						Seek(const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
	     FLAC__uint64 absolute_byte_offset, void *client_data);
 | 
						     FLAC__uint64 absolute_byte_offset, void *client_data) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static FLAC__StreamDecoderTellStatus
 | 
						static FLAC__StreamDecoderTellStatus
 | 
				
			||||||
	Tell(const FLAC__StreamDecoder *flac_decoder,
 | 
						Tell(const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
	     FLAC__uint64 *absolute_byte_offset, void *client_data);
 | 
						     FLAC__uint64 *absolute_byte_offset, void *client_data) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static FLAC__StreamDecoderLengthStatus
 | 
						static FLAC__StreamDecoderLengthStatus
 | 
				
			||||||
	Length(const FLAC__StreamDecoder *flac_decoder,
 | 
						Length(const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
	       FLAC__uint64 *stream_length, void *client_data);
 | 
						       FLAC__uint64 *stream_length, void *client_data) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static FLAC__bool
 | 
						static FLAC__bool
 | 
				
			||||||
	Eof(const FLAC__StreamDecoder *flac_decoder, void *client_data);
 | 
						Eof(const FLAC__StreamDecoder *flac_decoder,
 | 
				
			||||||
 | 
						    void *client_data) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static void
 | 
						static void
 | 
				
			||||||
	Error(const FLAC__StreamDecoder *decoder,
 | 
						Error(const FLAC__StreamDecoder *decoder,
 | 
				
			||||||
	      FLAC__StreamDecoderErrorStatus status, void *client_data);
 | 
						      FLAC__StreamDecoderErrorStatus status,
 | 
				
			||||||
 | 
						      void *client_data) noexcept;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,8 @@ FlacPcmImport::Open(unsigned sample_rate, unsigned bits_per_sample,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
FlacImportStereo(T *dest, const FLAC__int32 *const src[], size_t n_frames)
 | 
					FlacImportStereo(T *dest, const FLAC__int32 *const src[],
 | 
				
			||||||
 | 
							 size_t n_frames) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (size_t i = 0; i != n_frames; ++i) {
 | 
						for (size_t i = 0; i != n_frames; ++i) {
 | 
				
			||||||
		*dest++ = (T)src[0][i];
 | 
							*dest++ = (T)src[0][i];
 | 
				
			||||||
@@ -50,7 +51,7 @@ FlacImportStereo(T *dest, const FLAC__int32 *const src[], size_t n_frames)
 | 
				
			|||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
					FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
				
			||||||
	      unsigned n_channels)
 | 
						      unsigned n_channels) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	for (size_t i = 0; i != n_frames; ++i)
 | 
						for (size_t i = 0; i != n_frames; ++i)
 | 
				
			||||||
		for (unsigned c = 0; c != n_channels; ++c)
 | 
							for (unsigned c = 0; c != n_channels; ++c)
 | 
				
			||||||
@@ -60,7 +61,7 @@ FlacImportAny(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
				
			|||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
					FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
				
			||||||
	   unsigned n_channels)
 | 
						   unsigned n_channels) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (n_channels == 2)
 | 
						if (n_channels == 2)
 | 
				
			||||||
		FlacImportStereo(dest, src, n_frames);
 | 
							FlacImportStereo(dest, src, n_frames);
 | 
				
			||||||
@@ -71,7 +72,7 @@ FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames,
 | 
				
			|||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
static ConstBuffer<void>
 | 
					static ConstBuffer<void>
 | 
				
			||||||
FlacImport(PcmBuffer &buffer, const FLAC__int32 *const src[], size_t n_frames,
 | 
					FlacImport(PcmBuffer &buffer, const FLAC__int32 *const src[], size_t n_frames,
 | 
				
			||||||
	   unsigned n_channels)
 | 
						   unsigned n_channels) noexcept
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t n_samples = n_frames * n_channels;
 | 
						size_t n_samples = n_frames * n_channels;
 | 
				
			||||||
	size_t dest_size = n_samples * sizeof(T);
 | 
						size_t dest_size = n_samples * sizeof(T);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,7 +43,7 @@ public:
 | 
				
			|||||||
	void Open(unsigned sample_rate, unsigned bits_per_sample,
 | 
						void Open(unsigned sample_rate, unsigned bits_per_sample,
 | 
				
			||||||
		  unsigned channels);
 | 
							  unsigned channels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const AudioFormat &GetAudioFormat() const {
 | 
						const AudioFormat &GetAudioFormat() const noexcept {
 | 
				
			||||||
		return audio_format;
 | 
							return audio_format;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -562,7 +562,21 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mad_bit_skip(ptr, 16);
 | 
						mad_bit_skip(ptr, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lame->peak = MAD_F(mad_bit_read(ptr, 32) << 5); /* peak */
 | 
						/* The lame peak value is a float multiplied by 2^23 and stored as an
 | 
				
			||||||
 | 
						 * unsigned integer (it is always positive). MAD's fixed-point format uses
 | 
				
			||||||
 | 
						 * 28 bits for the fractional part, so shift the 23 bit fraction up before
 | 
				
			||||||
 | 
						 * converting to a float.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						unsigned long peak_int = mad_bit_read(ptr, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LAME_PEAK_FRACBITS 23
 | 
				
			||||||
 | 
					#if MAD_F_FRACBITS > LAME_PEAK_FRACBITS
 | 
				
			||||||
 | 
						peak_int <<= (MAD_F_FRACBITS - LAME_PEAK_FRACBITS);
 | 
				
			||||||
 | 
					#elif LAME_PEAK_FRACBITS > MAD_F_FRACBITS
 | 
				
			||||||
 | 
						peak_int >>= (LAME_PEAK_FRACBITS - MAD_F_FRACBITS);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lame->peak = mad_f_todouble(peak_int); /* peak */
 | 
				
			||||||
	FmtDebug(mad_domain, "LAME peak found: {}", lame->peak);
 | 
						FmtDebug(mad_domain, "LAME peak found: {}", lame->peak);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lame->track_gain = 0;
 | 
						lame->track_gain = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,6 +66,9 @@ FfmpegFilter::FilterPCM(ConstBuffer<void> src)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
	frame->nb_samples = src.size / in_audio_frame_size;
 | 
						frame->nb_samples = src.size / in_audio_frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						frame->pts = pts;
 | 
				
			||||||
 | 
						pts += frame->nb_samples;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	frame.GetBuffer();
 | 
						frame.GetBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(frame.GetData(0), src.data, src.size);
 | 
						memcpy(frame.GetData(0), src.data, src.size);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,14 +17,15 @@
 | 
				
			|||||||
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
					 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef MPD_FFMPEG_FILTER__HXX
 | 
					#pragma once
 | 
				
			||||||
#define MPD_FFMPEG_FILTER__HXX
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "filter/Filter.hxx"
 | 
					#include "filter/Filter.hxx"
 | 
				
			||||||
#include "lib/ffmpeg/Buffer.hxx"
 | 
					#include "lib/ffmpeg/Buffer.hxx"
 | 
				
			||||||
#include "lib/ffmpeg/Filter.hxx"
 | 
					#include "lib/ffmpeg/Filter.hxx"
 | 
				
			||||||
#include "lib/ffmpeg/Frame.hxx"
 | 
					#include "lib/ffmpeg/Frame.hxx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * A #Filter implementation using FFmpeg's libavfilter.
 | 
					 * A #Filter implementation using FFmpeg's libavfilter.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -46,6 +47,11 @@ class FfmpegFilter final : public Filter {
 | 
				
			|||||||
	const size_t in_audio_frame_size;
 | 
						const size_t in_audio_frame_size;
 | 
				
			||||||
	const size_t out_audio_frame_size;
 | 
						const size_t out_audio_frame_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Presentation timestamp.  A counter for `AVFrame::pts`.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						int_least64_t pts = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @param _graph a checked and configured AVFilterGraph
 | 
						 * @param _graph a checked and configured AVFilterGraph
 | 
				
			||||||
@@ -63,5 +69,3 @@ public:
 | 
				
			|||||||
	/* virtual methods from class Filter */
 | 
						/* virtual methods from class Filter */
 | 
				
			||||||
	ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
 | 
						ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -234,7 +234,7 @@ AlsaInputStream::PrepareSockets() noexcept
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
AlsaInputStream::DispatchSockets() noexcept
 | 
					AlsaInputStream::DispatchSockets() noexcept
 | 
				
			||||||
{
 | 
					try {
 | 
				
			||||||
	non_block.DispatchSockets(*this, capture_handle);
 | 
						non_block.DispatchSockets(*this, capture_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const std::scoped_lock<Mutex> protect(mutex);
 | 
						const std::scoped_lock<Mutex> protect(mutex);
 | 
				
			||||||
@@ -253,16 +253,17 @@ AlsaInputStream::DispatchSockets() noexcept
 | 
				
			|||||||
		if (n_frames == -EAGAIN)
 | 
							if (n_frames == -EAGAIN)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (Recover(n_frames) < 0) {
 | 
							if (Recover(n_frames) < 0)
 | 
				
			||||||
			postponed_exception = std::make_exception_ptr(std::runtime_error("PCM error - stream aborted"));
 | 
								throw std::runtime_error("PCM error - stream aborted");
 | 
				
			||||||
			InvokeOnAvailable();
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t nbytes = n_frames * frame_size;
 | 
						size_t nbytes = n_frames * frame_size;
 | 
				
			||||||
	CommitWriteBuffer(nbytes);
 | 
						CommitWriteBuffer(nbytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					catch (...) {
 | 
				
			||||||
 | 
						postponed_exception = std::current_exception();
 | 
				
			||||||
 | 
						InvokeOnAvailable();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline int
 | 
					inline int
 | 
				
			||||||
AlsaInputStream::Recover(int err)
 | 
					AlsaInputStream::Recover(int err)
 | 
				
			||||||
@@ -369,9 +370,14 @@ AlsaInputStream::ConfigureCapture(AudioFormat audio_format)
 | 
				
			|||||||
		 period_size_min, period_size_max,
 | 
							 period_size_min, period_size_max,
 | 
				
			||||||
		 period_time_min, period_time_max);
 | 
							 period_time_min, period_time_max);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* choose the maximum possible buffer_size ... */
 | 
						/* choose the maximum buffer_time up to limit of 2 seconds ... */
 | 
				
			||||||
	snd_pcm_hw_params_set_buffer_size(capture_handle, hw_params,
 | 
						unsigned buffer_time = buffer_time_max;
 | 
				
			||||||
					  buffer_size_max);
 | 
						if (buffer_time > 2000000U)
 | 
				
			||||||
 | 
							buffer_time = 2000000U;
 | 
				
			||||||
 | 
						int direction = -1;
 | 
				
			||||||
 | 
						if ((err = snd_pcm_hw_params_set_buffer_time_near(capture_handle,
 | 
				
			||||||
 | 
									hw_params, &buffer_time, &direction)) < 0)
 | 
				
			||||||
 | 
							throw Alsa::MakeError(err, "Cannot set buffer time");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* ... and calculate the period_size to have four periods in
 | 
						/* ... and calculate the period_size to have four periods in
 | 
				
			||||||
	   one buffer; this way, we get woken up often enough to avoid
 | 
						   one buffer; this way, we get woken up often enough to avoid
 | 
				
			||||||
@@ -379,7 +385,7 @@ AlsaInputStream::ConfigureCapture(AudioFormat audio_format)
 | 
				
			|||||||
	snd_pcm_uframes_t buffer_size;
 | 
						snd_pcm_uframes_t buffer_size;
 | 
				
			||||||
	if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) == 0) {
 | 
						if (snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size) == 0) {
 | 
				
			||||||
		snd_pcm_uframes_t period_size = buffer_size / 4;
 | 
							snd_pcm_uframes_t period_size = buffer_size / 4;
 | 
				
			||||||
		int direction = -1;
 | 
							direction = -1;
 | 
				
			||||||
		if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle,
 | 
							if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle,
 | 
				
			||||||
		                             hw_params, &period_size, &direction)) < 0)
 | 
							                             hw_params, &period_size, &direction)) < 0)
 | 
				
			||||||
			throw Alsa::MakeError(err, "Cannot set period size");
 | 
								throw Alsa::MakeError(err, "Cannot set period size");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
Index: curl-7.84.0/CMakeLists.txt
 | 
					Index: curl-7.85.0/CMakeLists.txt
 | 
				
			||||||
===================================================================
 | 
					===================================================================
 | 
				
			||||||
--- curl-7.84.0.orig/CMakeLists.txt
 | 
					--- curl-7.85.0.orig/CMakeLists.txt
 | 
				
			||||||
+++ curl-7.84.0/CMakeLists.txt
 | 
					+++ curl-7.85.0/CMakeLists.txt
 | 
				
			||||||
@@ -1536,7 +1536,7 @@ set(includedir              "\${prefix}/
 | 
					@@ -1655,7 +1655,7 @@
 | 
				
			||||||
 set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 | 
					   set(LDFLAGS                 "${CMAKE_SHARED_LINKER_FLAGS}")
 | 
				
			||||||
 set(LIBCURL_LIBS            "")
 | 
					   set(LIBCURL_LIBS            "")
 | 
				
			||||||
 set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 | 
					   set(libdir                  "${CMAKE_INSTALL_PREFIX}/lib")
 | 
				
			||||||
-foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 | 
					-  foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 | 
				
			||||||
+foreach(_lib ${CURL_LIBS})
 | 
					+  foreach(_lib ${CURL_LIBS})
 | 
				
			||||||
   if(TARGET "${_lib}")
 | 
					     if(TARGET "${_lib}")
 | 
				
			||||||
     set(_libname "${_lib}")
 | 
					       set(_libname "${_lib}")
 | 
				
			||||||
     get_target_property(_imported "${_libname}" IMPORTED)
 | 
					       get_target_property(_imported "${_libname}" IMPORTED)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ template<>
 | 
				
			|||||||
struct fmt::formatter<AVSampleFormat> : formatter<string_view>
 | 
					struct fmt::formatter<AVSampleFormat> : formatter<string_view>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	template<typename FormatContext>
 | 
						template<typename FormatContext>
 | 
				
			||||||
	auto format(const AVSampleFormat format, FormatContext &ctx) {
 | 
						auto format(const AVSampleFormat format, FormatContext &ctx) const {
 | 
				
			||||||
		const char *name = av_get_sample_fmt_name(format);
 | 
							const char *name = av_get_sample_fmt_name(format);
 | 
				
			||||||
		if (name == nullptr)
 | 
							if (name == nullptr)
 | 
				
			||||||
			name = "?";
 | 
								name = "?";
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ template<>
 | 
				
			|||||||
struct fmt::formatter<SampleFormat> : formatter<string_view>
 | 
					struct fmt::formatter<SampleFormat> : formatter<string_view>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	template<typename FormatContext>
 | 
						template<typename FormatContext>
 | 
				
			||||||
	auto format(const SampleFormat format, FormatContext &ctx) {
 | 
						auto format(const SampleFormat format, FormatContext &ctx) const {
 | 
				
			||||||
		return formatter<string_view>::format(sample_format_to_string(format),
 | 
							return formatter<string_view>::format(sample_format_to_string(format),
 | 
				
			||||||
						      ctx);
 | 
											      ctx);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -49,7 +49,7 @@ template<>
 | 
				
			|||||||
struct fmt::formatter<AudioFormat> : formatter<string_view>
 | 
					struct fmt::formatter<AudioFormat> : formatter<string_view>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	template<typename FormatContext>
 | 
						template<typename FormatContext>
 | 
				
			||||||
	auto format(const AudioFormat &af, FormatContext &ctx) {
 | 
						auto format(const AudioFormat &af, FormatContext &ctx) const {
 | 
				
			||||||
		return formatter<string_view>::format(ToString(af).c_str(),
 | 
							return formatter<string_view>::format(ToString(af).c_str(),
 | 
				
			||||||
						      ctx);
 | 
											      ctx);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ template<>
 | 
				
			|||||||
struct fmt::formatter<std::exception_ptr> : formatter<string_view>
 | 
					struct fmt::formatter<std::exception_ptr> : formatter<string_view>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	template<typename FormatContext>
 | 
						template<typename FormatContext>
 | 
				
			||||||
	auto format(std::exception_ptr e, FormatContext &ctx) {
 | 
						auto format(std::exception_ptr e, FormatContext &ctx) const {
 | 
				
			||||||
		return formatter<string_view>::format(GetFullMessage(e), ctx);
 | 
							return formatter<string_view>::format(GetFullMessage(e), ctx);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,7 +29,7 @@ template<>
 | 
				
			|||||||
struct fmt::formatter<Path> : formatter<string_view>
 | 
					struct fmt::formatter<Path> : formatter<string_view>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	template<typename FormatContext>
 | 
						template<typename FormatContext>
 | 
				
			||||||
	auto format(Path path, FormatContext &ctx) {
 | 
						auto format(Path path, FormatContext &ctx) const {
 | 
				
			||||||
		return formatter<string_view>::format(path.ToUTF8(), ctx);
 | 
							return formatter<string_view>::format(path.ToUTF8(), ctx);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
icu_dep = dependency('icu-i18n', version: '>= 50', required: get_option('icu'))
 | 
					icu_i18n_dep = dependency('icu-i18n', version: '>= 50', required: get_option('icu'))
 | 
				
			||||||
conf.set('HAVE_ICU', icu_dep.found())
 | 
					icu_uc_dep = dependency('icu-uc', version: '>= 50', required: get_option('icu'))
 | 
				
			||||||
 | 
					have_icu = icu_i18n_dep.found() and icu_uc_dep.found()
 | 
				
			||||||
 | 
					conf.set('HAVE_ICU', have_icu)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
icu_sources = [
 | 
					icu_sources = [
 | 
				
			||||||
  'CaseFold.cxx',
 | 
					  'CaseFold.cxx',
 | 
				
			||||||
@@ -13,7 +15,7 @@ if is_windows
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
iconv_dep = []
 | 
					iconv_dep = []
 | 
				
			||||||
if icu_dep.found()
 | 
					if have_icu
 | 
				
			||||||
  icu_sources += [
 | 
					  icu_sources += [
 | 
				
			||||||
    'Util.cxx',
 | 
					    'Util.cxx',
 | 
				
			||||||
    'Init.cxx',
 | 
					    'Init.cxx',
 | 
				
			||||||
@@ -44,7 +46,8 @@ icu = static_library(
 | 
				
			|||||||
  icu_sources,
 | 
					  icu_sources,
 | 
				
			||||||
  include_directories: inc,
 | 
					  include_directories: inc,
 | 
				
			||||||
  dependencies: [
 | 
					  dependencies: [
 | 
				
			||||||
    icu_dep,
 | 
					    icu_i18n_dep,
 | 
				
			||||||
 | 
					    icu_uc_dep,
 | 
				
			||||||
    iconv_dep,
 | 
					    iconv_dep,
 | 
				
			||||||
    fmt_dep,
 | 
					    fmt_dep,
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/lib/modplug/patches/no_register
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/lib/modplug/patches/no_register
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					Index: libmodplug-0.8.9.0/src/fastmix.cpp
 | 
				
			||||||
 | 
					===================================================================
 | 
				
			||||||
 | 
					--- libmodplug-0.8.9.0.orig/src/fastmix.cpp
 | 
				
			||||||
 | 
					+++ libmodplug-0.8.9.0/src/fastmix.cpp
 | 
				
			||||||
 | 
					@@ -288,7 +288,7 @@ CzWINDOWEDFIR sfir;
 | 
				
			||||||
 | 
					 // MIXING MACROS
 | 
				
			||||||
 | 
					 // ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 #define SNDMIX_BEGINSAMPLELOOP8\
 | 
				
			||||||
 | 
					-	register MODCHANNEL * const pChn = pChannel;\
 | 
				
			||||||
 | 
					+	MODCHANNEL * const pChn = pChannel;\
 | 
				
			||||||
 | 
					 	nPos = pChn->nPosLo;\
 | 
				
			||||||
 | 
					 	const signed char *p = (signed char *)(pChn->pCurrentSample+pChn->nPos);\
 | 
				
			||||||
 | 
					 	if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
 | 
				
			||||||
 | 
					@@ -296,7 +296,7 @@ CzWINDOWEDFIR sfir;
 | 
				
			||||||
 | 
					 	do {
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 #define SNDMIX_BEGINSAMPLELOOP16\
 | 
				
			||||||
 | 
					-	register MODCHANNEL * const pChn = pChannel;\
 | 
				
			||||||
 | 
					+	MODCHANNEL * const pChn = pChannel;\
 | 
				
			||||||
 | 
					 	nPos = pChn->nPosLo;\
 | 
				
			||||||
 | 
					 	const signed short *p = (signed short *)(pChn->pCurrentSample+(pChn->nPos*2));\
 | 
				
			||||||
 | 
					 	if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/lib/modplug/patches/series
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/lib/modplug/patches/series
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					no_register
 | 
				
			||||||
@@ -1026,7 +1026,7 @@ WasapiOutput::EnumerateDevices(IMMDeviceEnumerator &enumerator)
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		FmtNotice(wasapi_output_domain,
 | 
							FmtNotice(wasapi_output_domain,
 | 
				
			||||||
			  "Device \"{}\" \"{}\"", i, name);
 | 
								  "Device \"{}\" \"{}\"", i, name.c_str());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class TagMask {
 | 
					class TagMask {
 | 
				
			||||||
	typedef uint_least32_t mask_t;
 | 
						typedef uint_least32_t mask_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* the mask must have enough bits to represent all tags
 | 
				
			||||||
 | 
						   supported by MPD */
 | 
				
			||||||
 | 
						static_assert(TAG_NUM_OF_ITEM_TYPES <= sizeof(mask_t) * 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mask_t value;
 | 
						mask_t value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit constexpr TagMask(uint_least32_t _value) noexcept
 | 
						explicit constexpr TagMask(uint_least32_t _value) noexcept
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
#include "WindowsCond.hxx"
 | 
					#include "WindowsCond.hxx"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <system_error> // for std::error_category
 | 
				
			||||||
#include <variant>
 | 
					#include <variant>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class WinFutureErrc : int {
 | 
					enum class WinFutureErrc : int {
 | 
				
			||||||
@@ -130,7 +131,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void set_value(const T &value) {
 | 
						void set_value(const T &value) {
 | 
				
			||||||
		std::unique_lock<CriticalSection> lock(mutex);
 | 
							std::unique_lock<CriticalSection> lock(mutex);
 | 
				
			||||||
		if (!std::holds_alternative<std::monostate>(&result)) {
 | 
							if (!std::holds_alternative<std::monostate>(result)) {
 | 
				
			||||||
			throw WinFutureError(WinFutureErrc::promise_already_satisfied);
 | 
								throw WinFutureError(WinFutureErrc::promise_already_satisfied);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		result.template emplace<T>(value);
 | 
							result.template emplace<T>(value);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,17 +52,17 @@ public:
 | 
				
			|||||||
		using R = std::invoke_result_t<std::decay_t<Function>>;
 | 
							using R = std::invoke_result_t<std::decay_t<Function>>;
 | 
				
			||||||
		auto promise = std::make_shared<Promise<R>>();
 | 
							auto promise = std::make_shared<Promise<R>>();
 | 
				
			||||||
		auto future = promise->get_future();
 | 
							auto future = promise->get_future();
 | 
				
			||||||
		Push([function = std::forward<Function>(function),
 | 
							Push([func = std::forward<Function>(function),
 | 
				
			||||||
			      promise = std::move(promise)]() mutable {
 | 
								      prom = std::move(promise)]() mutable {
 | 
				
			||||||
			try {
 | 
								try {
 | 
				
			||||||
				if constexpr (std::is_void_v<R>) {
 | 
									if constexpr (std::is_void_v<R>) {
 | 
				
			||||||
					std::invoke(std::forward<Function>(function));
 | 
										std::invoke(std::forward<Function>(func));
 | 
				
			||||||
					promise->set_value();
 | 
										prom->set_value();
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					promise->set_value(std::invoke(std::forward<Function>(function)));
 | 
										prom->set_value(std::invoke(std::forward<Function>(func)));
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			} catch (...) {
 | 
								} catch (...) {
 | 
				
			||||||
				promise->set_exception(std::current_exception());
 | 
									prom->set_exception(std::current_exception());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
		return future;
 | 
							return future;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,9 +100,11 @@ FormatHResultError(HRESULT result, const char *fmt, ...) noexcept
 | 
				
			|||||||
	va_start(args1, fmt);
 | 
						va_start(args1, fmt);
 | 
				
			||||||
	va_copy(args2, args1);
 | 
						va_copy(args2, args1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const int size = vsnprintf(nullptr, 0, fmt, args1);
 | 
						int size = vsnprintf(nullptr, 0, fmt, args1);
 | 
				
			||||||
	va_end(args1);
 | 
						va_end(args1);
 | 
				
			||||||
	assert(size >= 0);
 | 
					
 | 
				
			||||||
 | 
						if (size < 0)
 | 
				
			||||||
 | 
							size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto buffer = std::make_unique<char[]>(size + 1);
 | 
						auto buffer = std::make_unique<char[]>(size + 1);
 | 
				
			||||||
	vsprintf(buffer.get(), fmt, args2);
 | 
						vsprintf(buffer.get(), fmt, args2);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,13 @@
 | 
				
			|||||||
[wrap-file]
 | 
					[wrap-file]
 | 
				
			||||||
directory = fmt-9.1.0
 | 
					directory = fmt-11.0.2
 | 
				
			||||||
source_url = https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz
 | 
					source_url = https://github.com/fmtlib/fmt/archive/11.0.2.tar.gz
 | 
				
			||||||
source_filename = fmt-9.1.0.tar.gz
 | 
					source_filename = fmt-11.0.2.tar.gz
 | 
				
			||||||
source_hash = 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2
 | 
					source_hash = 6cb1e6d37bdcb756dbbe59be438790db409cdb4868c66e888d5df9f13f7c027f
 | 
				
			||||||
patch_filename = fmt_9.1.0-1_patch.zip
 | 
					patch_filename = fmt_11.0.2-1_patch.zip
 | 
				
			||||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_9.1.0-1/get_patch
 | 
					patch_url = https://wrapdb.mesonbuild.com/v2/fmt_11.0.2-1/get_patch
 | 
				
			||||||
patch_hash = 4557b9ba87b3eb63694ed9b21d1a2117d4a97ca56b91085b10288e9a5294adf8
 | 
					patch_hash = 90c9e3b8e8f29713d40ca949f6f93ad115d78d7fb921064112bc6179e6427c5e
 | 
				
			||||||
wrapdb_version = 9.1.0-1
 | 
					source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_11.0.2-1/fmt-11.0.2.tar.gz
 | 
				
			||||||
 | 
					wrapdb_version = 11.0.2-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[provide]
 | 
					[provide]
 | 
				
			||||||
fmt = fmt_dep
 | 
					fmt = fmt_dep
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,13 @@
 | 
				
			|||||||
[wrap-file]
 | 
					[wrap-file]
 | 
				
			||||||
directory = sqlite-amalgamation-3410200
 | 
					directory = sqlite-amalgamation-3470100
 | 
				
			||||||
source_url = https://www.sqlite.org/2023/sqlite-amalgamation-3410200.zip
 | 
					source_url = https://www.sqlite.org/2024/sqlite-amalgamation-3470100.zip
 | 
				
			||||||
source_filename = sqlite-amalgamation-3410200.zip
 | 
					source_filename = sqlite-amalgamation-3470100.zip
 | 
				
			||||||
source_hash = 01df06a84803c1ab4d62c64e995b151b2dbcf5dbc93bbc5eee213cb18225d987
 | 
					source_hash = 9da21e6b14ef6a943cdc30f973df259fb390bb4483f77e7f171b9b6e977e5458
 | 
				
			||||||
patch_filename = sqlite3_3.41.2-2_patch.zip
 | 
					patch_filename = sqlite3_3.47.1-1_patch.zip
 | 
				
			||||||
patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.41.2-2/get_patch
 | 
					patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.47.1-1/get_patch
 | 
				
			||||||
patch_hash = 246681dfb731a14bfa61bcde651d5581a7e1c7d14851bfb57a941fac540a6810
 | 
					patch_hash = 7a298e69c663abfccd2d3632c6897b4f90627d36fd7fa137240c1d97c9a86466
 | 
				
			||||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.41.2-2/sqlite-amalgamation-3410200.zip
 | 
					source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.47.1-1/sqlite-amalgamation-3470100.zip
 | 
				
			||||||
wrapdb_version = 3.41.2-2
 | 
					wrapdb_version = 3.47.1-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[provide]
 | 
					[provide]
 | 
				
			||||||
sqlite3 = sqlite3_dep
 | 
					sqlite3 = sqlite3_dep
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,10 @@ systemd_system_unit_dir = get_option('systemd_system_unit_dir')
 | 
				
			|||||||
if systemd_system_unit_dir == ''
 | 
					if systemd_system_unit_dir == ''
 | 
				
			||||||
  systemd = dependency('systemd', required: false)
 | 
					  systemd = dependency('systemd', required: false)
 | 
				
			||||||
  if systemd.found()
 | 
					  if systemd.found()
 | 
				
			||||||
      systemd_system_unit_dir = systemd.get_variable(pkgconfig: 'systemdsystemunitdir')
 | 
					      systemd_system_unit_dir = systemd.get_variable(
 | 
				
			||||||
 | 
					        pkgconfig: 'systemdsystemunitdir',
 | 
				
			||||||
 | 
					        pkgconfig_define: ['rootprefix', get_option('prefix')],
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
if systemd_system_unit_dir == ''
 | 
					if systemd_system_unit_dir == ''
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,10 @@ systemd_user_unit_dir = get_option('systemd_user_unit_dir')
 | 
				
			|||||||
if systemd_user_unit_dir == ''
 | 
					if systemd_user_unit_dir == ''
 | 
				
			||||||
  systemd = dependency('systemd', required: false)
 | 
					  systemd = dependency('systemd', required: false)
 | 
				
			||||||
  if systemd.found()
 | 
					  if systemd.found()
 | 
				
			||||||
    systemd_user_unit_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir')
 | 
					    systemd_user_unit_dir = systemd.get_variable(
 | 
				
			||||||
 | 
					      pkgconfig: 'systemduserunitdir',
 | 
				
			||||||
 | 
					      pkgconfig_define: ['prefix', get_option('prefix')],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
if systemd_user_unit_dir == ''
 | 
					if systemd_user_unit_dir == ''
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,66 +29,12 @@ sys.path[0] = os.path.join(mpd_path, 'python')
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# output directories
 | 
					# output directories
 | 
				
			||||||
from build.dirs import lib_path, tarball_path, src_path
 | 
					from build.dirs import lib_path, tarball_path, src_path
 | 
				
			||||||
 | 
					from build.toolchain import MingwToolchain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
arch_path = os.path.join(lib_path, host_arch)
 | 
					arch_path = os.path.join(lib_path, host_arch)
 | 
				
			||||||
build_path = os.path.join(arch_path, 'build')
 | 
					build_path = os.path.join(arch_path, 'build')
 | 
				
			||||||
root_path = os.path.join(arch_path, 'root')
 | 
					root_path = os.path.join(arch_path, 'root')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CrossGccToolchain:
 | 
					 | 
				
			||||||
    def __init__(self, toolchain_path, arch,
 | 
					 | 
				
			||||||
                 tarball_path, src_path, build_path, install_prefix):
 | 
					 | 
				
			||||||
        self.arch = arch
 | 
					 | 
				
			||||||
        self.actual_arch = arch
 | 
					 | 
				
			||||||
        self.tarball_path = tarball_path
 | 
					 | 
				
			||||||
        self.src_path = src_path
 | 
					 | 
				
			||||||
        self.build_path = build_path
 | 
					 | 
				
			||||||
        self.install_prefix = install_prefix
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        toolchain_bin = os.path.join(toolchain_path, 'bin')
 | 
					 | 
				
			||||||
        self.cc = os.path.join(toolchain_bin, arch + '-gcc')
 | 
					 | 
				
			||||||
        self.cxx = os.path.join(toolchain_bin, arch + '-g++')
 | 
					 | 
				
			||||||
        self.ar = os.path.join(toolchain_bin, arch + '-ar')
 | 
					 | 
				
			||||||
        self.arflags = 'rcs'
 | 
					 | 
				
			||||||
        self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
 | 
					 | 
				
			||||||
        self.nm = os.path.join(toolchain_bin, arch + '-nm')
 | 
					 | 
				
			||||||
        self.strip = os.path.join(toolchain_bin, arch + '-strip')
 | 
					 | 
				
			||||||
        self.windres = os.path.join(toolchain_bin, arch + '-windres')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        common_flags = '-O2 -g'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if not x64:
 | 
					 | 
				
			||||||
            # enable SSE support which is required for LAME
 | 
					 | 
				
			||||||
            common_flags += ' -march=pentium3'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.cflags = common_flags
 | 
					 | 
				
			||||||
        self.cxxflags = common_flags
 | 
					 | 
				
			||||||
        self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
 | 
					 | 
				
			||||||
                        ' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
 | 
					 | 
				
			||||||
        self.ldflags = '-L' + os.path.join(install_prefix, 'lib') + \
 | 
					 | 
				
			||||||
                       ' -static-libstdc++ -static-libgcc'
 | 
					 | 
				
			||||||
        self.libs = ''
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Explicitly disable _FORTIFY_SOURCE because it is broken with
 | 
					 | 
				
			||||||
        # mingw.  This prevents some libraries such as libFLAC to
 | 
					 | 
				
			||||||
        # enable it.
 | 
					 | 
				
			||||||
        self.cppflags += ' -D_FORTIFY_SOURCE=0'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.is_arm = arch.startswith('arm')
 | 
					 | 
				
			||||||
        self.is_armv7 = self.is_arm and 'armv7' in self.cflags
 | 
					 | 
				
			||||||
        self.is_aarch64 = arch == 'aarch64'
 | 
					 | 
				
			||||||
        self.is_windows = 'mingw32' in arch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.env = dict(os.environ)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # redirect pkg-config to use our root directory instead of the
 | 
					 | 
				
			||||||
        # default one on the build host
 | 
					 | 
				
			||||||
        import shutil
 | 
					 | 
				
			||||||
        bin_dir = os.path.join(install_prefix, 'bin')
 | 
					 | 
				
			||||||
        os.makedirs(bin_dir, exist_ok=True)
 | 
					 | 
				
			||||||
        self.pkg_config = shutil.copy(os.path.join(mpd_path, 'build', 'pkg-config.sh'),
 | 
					 | 
				
			||||||
                                      os.path.join(bin_dir, 'pkg-config'))
 | 
					 | 
				
			||||||
        self.env['PKG_CONFIG'] = self.pkg_config
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# a list of third-party libraries to be used by MPD on Android
 | 
					# a list of third-party libraries to be used by MPD on Android
 | 
				
			||||||
from build.libs import *
 | 
					from build.libs import *
 | 
				
			||||||
thirdparty_libs = [
 | 
					thirdparty_libs = [
 | 
				
			||||||
@@ -111,8 +57,9 @@ thirdparty_libs = [
 | 
				
			|||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# build the third-party libraries
 | 
					# build the third-party libraries
 | 
				
			||||||
toolchain = CrossGccToolchain('/usr', host_arch,
 | 
					toolchain = MingwToolchain(mpd_path,
 | 
				
			||||||
                              tarball_path, src_path, build_path, root_path)
 | 
					                           '/usr', host_arch, x64,
 | 
				
			||||||
 | 
					                           tarball_path, src_path, build_path, root_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for x in thirdparty_libs:
 | 
					for x in thirdparty_libs:
 | 
				
			||||||
    if not x.is_installed(toolchain):
 | 
					    if not x.is_installed(toolchain):
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user