Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 |
NEWS
android
doc
meson.buildpython/build
autotools.pycmake.pydownload.pylibs.pymakeproject.pymeson.pyopenssl.pyproject.pyquilt.pytar.pytoolchain.pyverify.pyzlib.py
src
decoder
plugins
lib
modplug
patches
output
plugins
wasapi
tag
thread
win32
systemd
win32
11
NEWS
11
NEWS
@@ -1,3 +1,14 @@
|
|||||||
|
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="72"
|
||||||
android:versionName="0.23.12">
|
android:versionName="0.23.14">
|
||||||
|
|
||||||
<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 += [
|
||||||
|
@@ -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``.
|
||||||
|
@@ -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.14',
|
||||||
meson_version: '>= 0.56.0',
|
meson_version: '>= 0.56.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
|
@@ -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}")
|
||||||
@@ -52,36 +55,39 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE 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 +97,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 +116,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.tar.xz',
|
||||||
'd14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98',
|
'https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.xz'),
|
||||||
|
'8a9ba2898e1d0d774eca6ba5b4627a11e5588ba85c8851336eb38de4683050a7',
|
||||||
'lib/libz.a',
|
'lib/libz.a',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -111,6 +112,7 @@ libmodplug = AutotoolsProject(
|
|||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
],
|
],
|
||||||
|
patches='src/lib/modplug/patches',
|
||||||
)
|
)
|
||||||
|
|
||||||
libopenmpt = AutotoolsProject(
|
libopenmpt = AutotoolsProject(
|
||||||
@@ -149,7 +151,7 @@ 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',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -598,14 +600,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.3.tar.gz',
|
||||||
'aaa925ad9828745c4cad9d9efeb273deca820f2cdcf2c3ac7d7c1212b7c497b4',
|
'https://artfiles.org/openssl.org/source/openssl-3.1.3.tar.gz'),
|
||||||
|
'f0316a2ebd89e7f2352976445458689f80302093788c466692fb2a188b2eacf6',
|
||||||
'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.2.1.tar.xz',
|
||||||
'0a381cd82f4d00a9a334438b8ca239afea5bfefcfa9a1025f2bf118e79e0b5f0',
|
'https://github.com/curl/curl/releases/download/curl-8_2_1/curl-8.2.1.tar.xz'),
|
||||||
|
'dd322f6bd0a20e6cebdfd388f69e98c3d183bed792cf4713c8a7ef498cba4894',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_CURL_EXE=OFF',
|
'-DBUILD_CURL_EXE=OFF',
|
||||||
|
@@ -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'],
|
||||||
|
@@ -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;
|
||||||
|
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
|
||||||
|
@@ -130,7 +130,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;
|
||||||
|
@@ -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