Commit 680629ac authored by Konstantin A. Lepikhov's avatar Konstantin A. Lepikhov

Merge tag 'v0.23.13' of https://github.com/MusicPlayerDaemon/MPD into sisyphus

release v0.23.13
parents 3344811b 8842650c
ver 0.23.13 (2023/05/22)
* input
- curl: fix busy loop after connection failed
- curl: hide "404" log messages for non-existent ".mpdignore" files
* archive
- zzip: fix crash bug
* database
- simple: reveal hidden songs after deleting containing CUE
* decoder
- ffmpeg: reorder to a lower priority than "gme"
- gme: require GME 0.6 or later
* output
- pipewire: fix corruption bug due to missing lock
* Linux
- shut down if parent process dies in --no-daemon mode
- determine systemd unit directories via pkg-config
* support libfmt 10
ver 0.23.12 (2023/01/17) ver 0.23.12 (2023/01/17)
* input * input
- curl: require CURL 7.55.0 or later - curl: require CURL 7.55.0 or later
......
...@@ -100,6 +100,7 @@ class AndroidNdkToolchain: ...@@ -100,6 +100,7 @@ class AndroidNdkToolchain:
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections' common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
self.ar = os.path.join(llvm_bin, 'llvm-ar') self.ar = os.path.join(llvm_bin, 'llvm-ar')
self.arflags = 'rcs'
self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib') self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
self.nm = os.path.join(llvm_bin, 'llvm-nm') self.nm = os.path.join(llvm_bin, 'llvm-nm')
self.strip = os.path.join(llvm_bin, 'llvm-strip') self.strip = os.path.join(llvm_bin, 'llvm-strip')
......
...@@ -181,7 +181,7 @@ ...@@ -181,7 +181,7 @@
# #
#database { #database {
# plugin "simple" # plugin "simple"
# path "~/.local/share/mpd/db # path "~/.local/share/mpd/db"
# cache_directory "~/.local/share/mpd/cache" # cache_directory "~/.local/share/mpd/cache"
#} #}
# #
......
...@@ -611,6 +611,11 @@ If ReplayGain is enabled, then the setting ``replaygain_preamp`` is ...@@ -611,6 +611,11 @@ If ReplayGain is enabled, then the setting ``replaygain_preamp`` is
set to a value (in dB) between ``-15`` and ``15``. This is the gain set to a value (in dB) between ``-15`` and ``15``. This is the gain
applied to songs with ReplayGain tags. applied to songs with ReplayGain tags.
On songs without ReplayGain tags, the setting
``replaygain_missing_preamp`` is used instead. If this setting is not
configured, then no ReplayGain is applied to such songs, and they will
appear too loud.
ReplayGain is usually implemented with a software volume filter (which ReplayGain is usually implemented with a software volume filter (which
prevents `Bit-perfect playback`_). To use a hardware mixer, set prevents `Bit-perfect playback`_). To use a hardware mixer, set
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section ``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section
......
project( project(
'mpd', 'mpd',
['c', 'cpp'], ['c', 'cpp'],
version: '0.23.12', version: '0.23.13',
meson_version: '>= 0.56.0', meson_version: '>= 0.56.0',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',
......
...@@ -45,14 +45,27 @@ class AutotoolsProject(MakeProject): ...@@ -45,14 +45,27 @@ class AutotoolsProject(MakeProject):
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags, 'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
'LIBS=' + toolchain.libs + ' ' + self.libs, 'LIBS=' + toolchain.libs + ' ' + self.libs,
'AR=' + toolchain.ar, 'AR=' + toolchain.ar,
'ARFLAGS=' + toolchain.arflags,
'RANLIB=' + toolchain.ranlib, 'RANLIB=' + toolchain.ranlib,
'STRIP=' + toolchain.strip, 'STRIP=' + toolchain.strip,
'--host=' + toolchain.arch, '--host=' + toolchain.arch,
'--prefix=' + toolchain.install_prefix, '--prefix=' + toolchain.install_prefix,
'--enable-silent-rules', '--disable-silent-rules',
] + self.configure_args ] + self.configure_args
subprocess.check_call(configure, cwd=build, env=toolchain.env) try:
print(configure)
subprocess.check_call(configure, cwd=build, env=toolchain.env)
except subprocess.CalledProcessError:
# dump config.log after a failed configure run
try:
with open(os.path.join(build, 'config.log')) as f:
sys.stdout.write(f.read())
except:
pass
# re-raise the exception
raise
return build return build
def _build(self, toolchain): def _build(self, toolchain):
......
import os import os
import re
import subprocess import subprocess
from build.project import Project from build.project import Project
...@@ -25,13 +26,33 @@ set(CMAKE_SYSTEM_PROCESSOR {toolchain.actual_arch.split('-', 1)[0]}) ...@@ -25,13 +26,33 @@ set(CMAKE_SYSTEM_PROCESSOR {toolchain.actual_arch.split('-', 1)[0]})
set(CMAKE_C_COMPILER_TARGET {toolchain.actual_arch}) set(CMAKE_C_COMPILER_TARGET {toolchain.actual_arch})
set(CMAKE_CXX_COMPILER_TARGET {toolchain.actual_arch}) set(CMAKE_CXX_COMPILER_TARGET {toolchain.actual_arch})
set(CMAKE_C_FLAGS "{toolchain.cflags} {toolchain.cppflags}") set(CMAKE_C_FLAGS_INIT "{toolchain.cflags} {toolchain.cppflags}")
set(CMAKE_CXX_FLAGS "{toolchain.cxxflags} {toolchain.cppflags}") set(CMAKE_CXX_FLAGS_INIT "{toolchain.cxxflags} {toolchain.cppflags}")
""") """)
__write_cmake_compiler(f, 'C', toolchain.cc) __write_cmake_compiler(f, 'C', toolchain.cc)
__write_cmake_compiler(f, 'CXX', toolchain.cxx) __write_cmake_compiler(f, 'CXX', toolchain.cxx)
def configure(toolchain, src, build, args=()): if cmake_system_name == 'Darwin':
# On macOS, cmake forcibly adds an "-isysroot" flag even if
# one is already present in the flags variable; this breaks
# cross-compiling for iOS, and can be worked around by setting
# the CMAKE_OSX_SYSROOT variable
# (https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_SYSROOT.html).
m = re.search(r'-isysroot +(\S+)', toolchain.cflags)
if m:
sysroot = m.group(1)
print(f'set(CMAKE_OSX_SYSROOT {sysroot})', file=f)
# search libraries and headers only in the sysroot, not on
# the build host
f.write(f"""
set(CMAKE_FIND_ROOT_PATH "{toolchain.install_prefix};{sysroot}")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
""")
def configure(toolchain, src, build, args=(), env=None):
cross_args = [] cross_args = []
if toolchain.is_windows: if toolchain.is_windows:
...@@ -61,15 +82,23 @@ def configure(toolchain, src, build, args=()): ...@@ -61,15 +82,23 @@ def configure(toolchain, src, build, args=()):
'-GNinja', '-GNinja',
] + cross_args + args ] + cross_args + args
subprocess.check_call(configure, env=toolchain.env, cwd=build) if env is None:
env = toolchain.env
else:
env = {**toolchain.env, **env}
print(configure)
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, md5, installed, configure_args=[],
windows_configure_args=[], windows_configure_args=[],
env=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
def configure(self, toolchain): def configure(self, toolchain):
src = self.unpack(toolchain) src = self.unpack(toolchain)
...@@ -77,10 +106,10 @@ class CmakeProject(Project): ...@@ -77,10 +106,10 @@ class CmakeProject(Project):
configure_args = self.configure_args configure_args = self.configure_args
if toolchain.is_windows: if toolchain.is_windows:
configure_args = configure_args + self.windows_configure_args configure_args = configure_args + self.windows_configure_args
configure(toolchain, src, build, configure_args) configure(toolchain, src, build, configure_args, self.env)
return build return build
def _build(self, toolchain): def _build(self, toolchain):
build = self.configure(toolchain) build = self.configure(toolchain)
subprocess.check_call(['ninja', 'install'], subprocess.check_call(['ninja', '-v', 'install'],
cwd=build, env=toolchain.env) cwd=build, env=toolchain.env)
import subprocess import subprocess, multiprocessing
from build.project import Project from build.project import Project
...@@ -10,7 +10,12 @@ class MakeProject(Project): ...@@ -10,7 +10,12 @@ class MakeProject(Project):
self.install_target = install_target self.install_target = install_target
def get_simultaneous_jobs(self): def get_simultaneous_jobs(self):
return 12 try:
# use twice as many simultaneous jobs as we have CPU cores
return multiprocessing.cpu_count() * 2
except NotImplementedError:
# default to 12, if multiprocessing.cpu_count() is not implemented
return 12
def get_make_args(self, toolchain): def get_make_args(self, toolchain):
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())] return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
...@@ -19,7 +24,7 @@ class MakeProject(Project): ...@@ -19,7 +24,7 @@ class MakeProject(Project):
return ['--quiet', self.install_target] return ['--quiet', self.install_target]
def make(self, toolchain, wd, args): def make(self, toolchain, wd, args):
subprocess.check_call(['/usr/bin/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, wd, install=True):
......
import os.path, subprocess, sys import os
import subprocess
import platform import platform
from build.project import Project from build.project import Project
...@@ -115,5 +116,5 @@ class MesonProject(Project): ...@@ -115,5 +116,5 @@ class MesonProject(Project):
def _build(self, toolchain): def _build(self, toolchain):
build = self.configure(toolchain) build = self.configure(toolchain)
subprocess.check_call(['ninja', 'install'], subprocess.check_call(['ninja', '-v', 'install'],
cwd=build, env=toolchain.env) cwd=build, env=toolchain.env)
...@@ -14,13 +14,14 @@ class Project: ...@@ -14,13 +14,14 @@ class Project:
if base is None: if base is None:
basename = os.path.basename(url) basename = os.path.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 if not m: raise RuntimeError('Could not identify tarball name: ' + basename)
self.base = m.group(1) self.base = m.group(1)
else: else:
self.base = base self.base = base
if name is None or version is None: if name is None or version is None:
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*(?:-(?:alpha|beta)\d+)?)(\+.*)?$', self.base) m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*(?:-(?:alpha|beta)\d+)?)(\+.*)?$', self.base)
if not m: raise RuntimeError('Could not identify tarball name: ' + self.base)
if name is None: name = m.group(1) if name is None: name = m.group(1)
if version is None: version = m.group(2) if version is None: version = m.group(2)
...@@ -55,8 +56,8 @@ class Project: ...@@ -55,8 +56,8 @@ class Project:
parent_path = toolchain.src_path parent_path = toolchain.src_path
else: else:
parent_path = toolchain.build_path parent_path = toolchain.build_path
path = untar(self.download(toolchain), parent_path, self.base) path = untar(self.download(toolchain), parent_path, self.base,
lazy=out_of_tree and self.patches is None)
if self.patches is not None: if self.patches is not None:
push_all(toolchain, path, self.patches) push_all(toolchain, path, self.patches)
...@@ -71,8 +72,10 @@ class Project: ...@@ -71,8 +72,10 @@ class Project:
return path return path
def make_build_path(self, toolchain): def make_build_path(self, toolchain, lazy=False):
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):
return path
try: try:
shutil.rmtree(path) shutil.rmtree(path)
except FileNotFoundError: except FileNotFoundError:
......
import os, shutil, subprocess import os, shutil, subprocess
def untar(tarball_path, parent_path, base): def untar(tarball_path, parent_path, base, lazy=False):
path = os.path.join(parent_path, base) path = os.path.join(parent_path, base)
if lazy and os.path.isdir(path):
return path
try: try:
shutil.rmtree(path) shutil.rmtree(path)
except FileNotFoundError: except FileNotFoundError:
pass pass
os.makedirs(parent_path, exist_ok=True) os.makedirs(parent_path, exist_ok=True)
try: try:
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path]) subprocess.check_call(['tar', 'xfC', tarball_path, parent_path])
except FileNotFoundError: except FileNotFoundError:
import tarfile import tarfile
tar = tarfile.open(tarball_path) tar = tarfile.open(tarball_path)
......
import os.path, subprocess import subprocess
from build.project import Project from build.makeproject import MakeProject
class ZlibProject(Project): class ZlibProject(MakeProject):
def __init__(self, url, md5, installed, def __init__(self, url, md5, installed,
**kwargs): **kwargs):
Project.__init__(self, url, md5, installed, **kwargs) MakeProject.__init__(self, url, md5, installed, **kwargs)
def get_make_args(self, toolchain):
return MakeProject.get_make_args(self, toolchain) + [
'CC=' + toolchain.cc + ' ' + toolchain.cppflags + ' ' + toolchain.cflags,
'CPP=' + toolchain.cc + ' -E ' + toolchain.cppflags,
'AR=' + toolchain.ar,
'ARFLAGS=' + toolchain.arflags,
'RANLIB=' + toolchain.ranlib,
'LDSHARED=' + toolchain.cc + ' -shared',
'libz.a'
]
def get_make_install_args(self, toolchain):
return [
'RANLIB=' + toolchain.ranlib,
self.install_target
]
def _build(self, toolchain): def _build(self, toolchain):
src = self.unpack(toolchain, out_of_tree=False) src = self.unpack(toolchain, out_of_tree=False)
subprocess.check_call(['/usr/bin/make', '--quiet', subprocess.check_call(['./configure', '--prefix=' + toolchain.install_prefix, '--static'],
'-f', 'win32/Makefile.gcc', cwd=src, env=toolchain.env)
'PREFIX=' + toolchain.arch + '-', self.build_make(toolchain, src)
'-j12',
'install',
'INCLUDE_PATH='+ os.path.join(toolchain.install_prefix, 'include'),
'LIBRARY_PATH=' + os.path.join(toolchain.install_prefix, 'lib'),
'BINARY_PATH=' + os.path.join(toolchain.install_prefix, 'bin'),
],
cwd=src, env=toolchain.env)
...@@ -352,12 +352,16 @@ ParseCommandLine(int argc, char **argv, CommandLineOptions &options, ...@@ -352,12 +352,16 @@ ParseCommandLine(int argc, char **argv, CommandLineOptions &options,
break; break;
case OPTION_NO_DAEMON: case OPTION_NO_DAEMON:
#ifdef ENABLE_DAEMON
options.daemon = false; options.daemon = false;
#endif
break; break;
#ifdef __linux__ #ifdef __linux__
case OPTION_SYSTEMD: case OPTION_SYSTEMD:
#ifdef ENABLE_DAEMON
options.daemon = false; options.daemon = false;
#endif
options.systemd = true; options.systemd = true;
break; break;
#endif #endif
......
...@@ -20,11 +20,18 @@ ...@@ -20,11 +20,18 @@
#ifndef MPD_COMMAND_LINE_HXX #ifndef MPD_COMMAND_LINE_HXX
#define MPD_COMMAND_LINE_HXX #define MPD_COMMAND_LINE_HXX
#include "config.h" // for ENABLE_DAEMON
struct ConfigData; struct ConfigData;
struct CommandLineOptions { struct CommandLineOptions {
bool kill = false; bool kill = false;
#ifdef ENABLE_DAEMON
bool daemon = true; bool daemon = true;
#else
static constexpr bool daemon = false;
#endif
#ifdef __linux__ #ifdef __linux__
bool systemd = false; bool systemd = false;
......
...@@ -482,7 +482,10 @@ MainConfigured(const CommandLineOptions &options, ...@@ -482,7 +482,10 @@ MainConfigured(const CommandLineOptions &options,
#ifndef ANDROID #ifndef ANDROID
setup_log_output(); setup_log_output();
const ScopeSignalHandlersInit signal_handlers_init(instance); const ScopeSignalHandlersInit signal_handlers_init{
instance,
options.daemon,
};
#endif #endif
instance.io_thread.Start(); instance.io_thread.Start();
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "TagPrint.hxx" #include "TagPrint.hxx"
#include "client/Response.hxx" #include "client/Response.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "lib/fmt/AudioFormatFormatter.hxx"
#include "time/ChronoUtil.hxx" #include "time/ChronoUtil.hxx"
#include "util/StringBuffer.hxx" #include "util/StringBuffer.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
...@@ -93,7 +94,7 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept ...@@ -93,7 +94,7 @@ song_print_info(Response &r, const LightSong &song, bool base) noexcept
time_print(r, "Last-Modified", song.mtime); time_print(r, "Last-Modified", song.mtime);
if (song.audio_format.IsDefined()) if (song.audio_format.IsDefined())
r.Fmt(FMT_STRING("Format: {}\n"), ToString(song.audio_format)); r.Fmt(FMT_STRING("Format: {}\n"), song.audio_format);
tag_print_values(r, song.tag); tag_print_values(r, song.tag);
...@@ -116,7 +117,7 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept ...@@ -116,7 +117,7 @@ song_print_info(Response &r, const DetachedSong &song, bool base) noexcept
time_print(r, "Last-Modified", song.GetLastModified()); time_print(r, "Last-Modified", song.GetLastModified());
if (const auto &f = song.GetAudioFormat(); f.IsDefined()) if (const auto &f = song.GetAudioFormat(); f.IsDefined())
r.Fmt(FMT_STRING("Format: {}\n"), ToString(f)); r.Fmt(FMT_STRING("Format: {}\n"), f);
tag_print_values(r, song.GetTag()); tag_print_values(r, song.GetTag());
......
...@@ -63,6 +63,9 @@ song_save(BufferedOutputStream &os, const Song &song) ...@@ -63,6 +63,9 @@ song_save(BufferedOutputStream &os, const Song &song)
if (song.audio_format.IsDefined()) if (song.audio_format.IsDefined())
os.Format("Format: %s\n", ToString(song.audio_format).c_str()); os.Format("Format: %s\n", ToString(song.audio_format).c_str());
if (song.in_playlist)
os.Write("InPlaylist: yes\n");
if (!IsNegative(song.mtime)) if (!IsNegative(song.mtime))
os.Format(SONG_MTIME ": %li\n", os.Format(SONG_MTIME ": %li\n",
(long)std::chrono::system_clock::to_time_t(song.mtime)); (long)std::chrono::system_clock::to_time_t(song.mtime));
...@@ -86,7 +89,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song) ...@@ -86,7 +89,7 @@ song_save(BufferedOutputStream &os, const DetachedSong &song)
DetachedSong DetachedSong
song_load(LineReader &file, const char *uri, song_load(LineReader &file, const char *uri,
std::string *target_r) std::string *target_r, bool *in_playlist_r)
{ {
DetachedSong song(uri); DetachedSong song(uri);
...@@ -132,6 +135,9 @@ song_load(LineReader &file, const char *uri, ...@@ -132,6 +135,9 @@ song_load(LineReader &file, const char *uri,
song.SetStartTime(SongTime::FromMS(start_ms)); song.SetStartTime(SongTime::FromMS(start_ms));
song.SetEndTime(SongTime::FromMS(end_ms)); song.SetEndTime(SongTime::FromMS(end_ms));
} else if (StringIsEqual(line, "InPlaylist")) {
if (in_playlist_r != nullptr)
*in_playlist_r = StringIsEqual(value, "yes");
} else { } else {
throw FormatRuntimeError("unknown line in db: %s", line); throw FormatRuntimeError("unknown line in db: %s", line);
} }
......
...@@ -44,6 +44,6 @@ song_save(BufferedOutputStream &os, const DetachedSong &song); ...@@ -44,6 +44,6 @@ song_save(BufferedOutputStream &os, const DetachedSong &song);
*/ */
DetachedSong DetachedSong
song_load(LineReader &file, const char *uri, song_load(LineReader &file, const char *uri,
std::string *target_r=nullptr); std::string *target_r=nullptr, bool *in_playlist_r=nullptr);
#endif #endif
...@@ -35,8 +35,9 @@ tag_print_types(Response &r) noexcept ...@@ -35,8 +35,9 @@ tag_print_types(Response &r) noexcept
} }
void void
tag_print(Response &r, TagType type, StringView value) noexcept tag_print(Response &r, TagType type, StringView _value) noexcept
{ {
const std::string_view value{_value};
r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value); r.Fmt(FMT_STRING("{}: {}\n"), tag_item_names[type], value);
} }
......
...@@ -36,5 +36,5 @@ time_print(Response &r, const char *name, ...@@ -36,5 +36,5 @@ time_print(Response &r, const char *name,
return; return;
} }
r.Fmt(FMT_STRING("{}: {}\n"), name, s); r.Fmt(FMT_STRING("{}: {}\n"), name, s.c_str());
} }
...@@ -41,6 +41,8 @@ ...@@ -41,6 +41,8 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <limits.h> // for UINT_MAX
CommandResult CommandResult
handle_listfiles_db(Client &client, Response &r, const char *uri) handle_listfiles_db(Client &client, Response &r, const char *uri)
{ {
......
...@@ -100,10 +100,6 @@ handle_listfiles_local(Response &r, Path path_fs) ...@@ -100,10 +100,6 @@ handle_listfiles_local(Response &r, Path path_fs)
return CommandResult::OK; return CommandResult::OK;
} }
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif
gcc_pure gcc_pure
static bool static bool
IsValidName(const StringView s) noexcept IsValidName(const StringView s) noexcept
...@@ -130,7 +126,8 @@ public: ...@@ -130,7 +126,8 @@ public:
explicit PrintCommentHandler(Response &_response) noexcept explicit PrintCommentHandler(Response &_response) noexcept
:NullTagHandler(WANT_PAIR), response(_response) {} :NullTagHandler(WANT_PAIR), response(_response) {}
void OnPair(StringView key, StringView value) noexcept override { void OnPair(StringView _key, StringView _value) noexcept override {
const std::string_view key{_key}, value{_value};
if (IsValidName(key) && IsValidValue(value)) if (IsValidName(key) && IsValidValue(value))
response.Fmt(FMT_STRING("{}: {}\n"), key, value); response.Fmt(FMT_STRING("{}: {}\n"), key, value);
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "Partition.hxx" #include "Partition.hxx"
#include "Instance.hxx" #include "Instance.hxx"
#include "IdleFlags.hxx" #include "IdleFlags.hxx"
#include "lib/fmt/AudioFormatFormatter.hxx"
#include "util/StringBuffer.hxx" #include "util/StringBuffer.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/Exception.hxx" #include "util/Exception.hxx"
...@@ -185,7 +186,7 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r) ...@@ -185,7 +186,7 @@ handle_status(Client &client, [[maybe_unused]] Request args, Response &r)
if (player_status.audio_format.IsDefined()) if (player_status.audio_format.IsDefined())
r.Fmt(FMT_STRING(COMMAND_STATUS_AUDIO ": {}\n"), r.Fmt(FMT_STRING(COMMAND_STATUS_AUDIO ": {}\n"),
ToString(player_status.audio_format)); player_status.audio_format);
} }
#ifdef ENABLE_DATABASE #ifdef ENABLE_DATABASE
......
...@@ -83,10 +83,6 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader) ...@@ -83,10 +83,6 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
} }
} }
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif
CommandResult CommandResult
handle_listfiles_storage(Response &r, Storage &storage, const char *uri) handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
{ {
......
...@@ -127,6 +127,18 @@ Directory::LookupTargetSong(std::string_view _target) noexcept ...@@ -127,6 +127,18 @@ Directory::LookupTargetSong(std::string_view _target) noexcept
} }
void void
Directory::ClearInPlaylist() noexcept
{
assert(holding_db_lock());
for (auto &child : children)
child.ClearInPlaylist();
for (auto &song : songs)
song.in_playlist = false;
}
void
Directory::PruneEmpty() noexcept Directory::PruneEmpty() noexcept
{ {
assert(holding_db_lock()); assert(holding_db_lock());
......
...@@ -288,6 +288,14 @@ public: ...@@ -288,6 +288,14 @@ public:
SongPtr RemoveSong(Song *song) noexcept; SongPtr RemoveSong(Song *song) noexcept;
/** /**
* Recursively walk through the whole tree and set all
* `Song::in_playlist` fields to `false`.
*
* Caller must lock the #db_mutex.
*/
void ClearInPlaylist() noexcept;
/**
* Caller must lock the #db_mutex. * Caller must lock the #db_mutex.
*/ */
void PruneEmpty() noexcept; void PruneEmpty() noexcept;
......
...@@ -168,12 +168,14 @@ directory_load(LineReader &file, Directory &directory) ...@@ -168,12 +168,14 @@ directory_load(LineReader &file, Directory &directory)
throw FormatRuntimeError("Duplicate song '%s'", name); throw FormatRuntimeError("Duplicate song '%s'", name);
std::string target; std::string target;
bool in_playlist = false;
auto detached_song = song_load(file, name, auto detached_song = song_load(file, name,
&target); &target, &in_playlist);
auto song = std::make_unique<Song>(std::move(detached_song), auto song = std::make_unique<Song>(std::move(detached_song),
directory); directory);
song->target = std::move(target); song->target = std::move(target);
song->in_playlist = in_playlist;
directory.AddSong(std::move(song)); directory.AddSong(std::move(song));
} else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) { } else if ((p = StringAfterPrefix(line, PLAYLIST_META_BEGIN))) {
......
...@@ -51,6 +51,15 @@ LockFindSong(Directory &directory, std::string_view name) noexcept ...@@ -51,6 +51,15 @@ LockFindSong(Directory &directory, std::string_view name) noexcept
return directory.FindSong(name); return directory.FindSong(name);
} }
[[gnu::pure]]
static bool
IsAcceptableFilename(std::string_view name) noexcept
{
return !name.empty() &&
/* newlines cannot be represented in MPD's protocol */
name.find('\n') == name.npos;
}
void void
UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory, UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
const char *name) noexcept const char *name) noexcept
...@@ -58,6 +67,9 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory, ...@@ -58,6 +67,9 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
const char *tmp = std::strchr(name, '/'); const char *tmp = std::strchr(name, '/');
if (tmp) { if (tmp) {
const std::string_view child_name(name, tmp - name); const std::string_view child_name(name, tmp - name);
if (!IsAcceptableFilename(child_name))
return;
//add dir is not there already //add dir is not there already
Directory *subdir = LockMakeChild(directory, child_name); Directory *subdir = LockMakeChild(directory, child_name);
subdir->device = DEVICE_INARCHIVE; subdir->device = DEVICE_INARCHIVE;
...@@ -65,11 +77,8 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory, ...@@ -65,11 +77,8 @@ UpdateWalk::UpdateArchiveTree(ArchiveFile &archive, Directory &directory,
//create directories first //create directories first
UpdateArchiveTree(archive, *subdir, tmp + 1); UpdateArchiveTree(archive, *subdir, tmp + 1);
} else { } else {
if (StringIsEmpty(name)) { if (!IsAcceptableFilename(name))
LogWarning(update_domain,
"archive returned directory only");
return; return;
}
//add file //add file
Song *song = LockFindSong(directory, name); Song *song = LockFindSong(directory, name);
......
...@@ -531,6 +531,7 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept ...@@ -531,6 +531,7 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard) noexcept
{ {
const ScopeDatabaseLock protect; const ScopeDatabaseLock protect;
root.ClearInPlaylist();
PurgeDanglingFromPlaylists(root); PurgeDanglingFromPlaylists(root);
} }
......
...@@ -114,12 +114,12 @@ constexpr const struct DecoderPlugin *decoder_plugins[] = { ...@@ -114,12 +114,12 @@ constexpr const struct DecoderPlugin *decoder_plugins[] = {
#ifdef ENABLE_ADPLUG #ifdef ENABLE_ADPLUG
&adplug_decoder_plugin, &adplug_decoder_plugin,
#endif #endif
#ifdef ENABLE_FFMPEG
&ffmpeg_decoder_plugin,
#endif
#ifdef ENABLE_GME #ifdef ENABLE_GME
&gme_decoder_plugin, &gme_decoder_plugin,
#endif #endif
#ifdef ENABLE_FFMPEG
&ffmpeg_decoder_plugin,
#endif
&pcm_decoder_plugin, &pcm_decoder_plugin,
nullptr nullptr
}; };
......
...@@ -56,20 +56,17 @@ struct GmeContainerPath { ...@@ -56,20 +56,17 @@ struct GmeContainerPath {
unsigned track; unsigned track;
}; };
#if GME_VERSION >= 0x000600
static int gme_accuracy; static int gme_accuracy;
#endif
static unsigned gme_default_fade; static unsigned gme_default_fade;
static bool static bool
gme_plugin_init([[maybe_unused]] const ConfigBlock &block) gme_plugin_init([[maybe_unused]] const ConfigBlock &block)
{ {
#if GME_VERSION >= 0x000600
auto accuracy = block.GetBlockParam("accuracy"); auto accuracy = block.GetBlockParam("accuracy");
gme_accuracy = accuracy != nullptr gme_accuracy = accuracy != nullptr
? (int)accuracy->GetBoolValue() ? (int)accuracy->GetBoolValue()
: -1; : -1;
#endif
auto fade = block.GetBlockParam("default_fade"); auto fade = block.GetBlockParam("default_fade");
gme_default_fade = fade != nullptr gme_default_fade = fade != nullptr
? fade->GetUnsignedValue() * 1000 ? fade->GetUnsignedValue() * 1000
...@@ -163,10 +160,8 @@ gme_file_decode(DecoderClient &client, Path path_fs) ...@@ -163,10 +160,8 @@ gme_file_decode(DecoderClient &client, Path path_fs)
FmtDebug(gme_domain, "emulator type '{}'", FmtDebug(gme_domain, "emulator type '{}'",
gme_type_system(gme_type(emu))); gme_type_system(gme_type(emu)));
#if GME_VERSION >= 0x000600
if (gme_accuracy >= 0) if (gme_accuracy >= 0)
gme_enable_accuracy(emu, gme_accuracy); gme_enable_accuracy(emu, gme_accuracy);
#endif
gme_info_t *ti; gme_info_t *ti;
const char *gme_err = gme_track_info(emu, &ti, container.track); const char *gme_err = gme_track_info(emu, &ti, container.track);
......
...@@ -81,7 +81,7 @@ if libfaad_dep.found() ...@@ -81,7 +81,7 @@ if libfaad_dep.found()
decoder_plugins_sources += 'FaadDecoderPlugin.cxx' decoder_plugins_sources += 'FaadDecoderPlugin.cxx'
endif endif
libgme_dep = c_compiler.find_library('gme', required: get_option('gme')) libgme_dep = dependency('libgme', version: '>= 0.6', required: get_option('gme'))
decoder_features.set('ENABLE_GME', libgme_dep.found()) decoder_features.set('ENABLE_GME', libgme_dep.found())
if libgme_dep.found() if libgme_dep.found()
decoder_plugins_sources += 'GmeDecoderPlugin.cxx' decoder_plugins_sources += 'GmeDecoderPlugin.cxx'
......
...@@ -272,9 +272,8 @@ EventLoop::Run() noexcept ...@@ -272,9 +272,8 @@ EventLoop::Run() noexcept
#endif #endif
assert(IsInside()); assert(IsInside());
assert(!quit);
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP
assert(alive); assert(alive || quit);
assert(busy); assert(busy);
wake_event.Schedule(SocketEvent::READ); wake_event.Schedule(SocketEvent::READ);
...@@ -299,7 +298,7 @@ EventLoop::Run() noexcept ...@@ -299,7 +298,7 @@ EventLoop::Run() noexcept
steady_clock_cache.flush(); steady_clock_cache.flush();
do { while (!quit) {
again = false; again = false;
/* invoke timers */ /* invoke timers */
...@@ -361,7 +360,7 @@ EventLoop::Run() noexcept ...@@ -361,7 +360,7 @@ EventLoop::Run() noexcept
socket_event.Dispatch(); socket_event.Dispatch();
} }
} while (!quit); }
#ifdef HAVE_THREADED_EVENT_LOOP #ifdef HAVE_THREADED_EVENT_LOOP
#ifndef NDEBUG #ifndef NDEBUG
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "Charset.hxx" #include "Charset.hxx"
#include "Features.hxx" #include "Features.hxx"
#include "Domain.hxx" #include "Domain.hxx"
#include "Log.hxx"
#include "lib/icu/Converter.hxx" #include "lib/icu/Converter.hxx"
#include "util/AllocatedString.hxx" #include "util/AllocatedString.hxx"
#include "config.h" #include "config.h"
...@@ -45,11 +44,9 @@ SetFSCharset(const char *charset) ...@@ -45,11 +44,9 @@ SetFSCharset(const char *charset)
assert(charset != nullptr); assert(charset != nullptr);
assert(fs_converter == nullptr); assert(fs_converter == nullptr);
fs_charset = charset;
fs_converter = IcuConverter::Create(charset); fs_converter = IcuConverter::Create(charset);
assert(fs_converter != nullptr); assert(fs_converter != nullptr);
FmtDebug(path_domain,
"SetFSCharset: fs charset is {}", fs_charset);
} }
#endif #endif
......
...@@ -101,9 +101,17 @@ AsyncInputStream::Seek(std::unique_lock<Mutex> &lock, ...@@ -101,9 +101,17 @@ AsyncInputStream::Seek(std::unique_lock<Mutex> &lock,
assert(IsReady()); assert(IsReady());
assert(seek_state == SeekState::NONE); assert(seek_state == SeekState::NONE);
if (new_offset == offset) if (new_offset == offset) {
/* no-op */ /* no-op, but if the stream is not open anymore (maybe
because it has failed), nothing can be read, so we
should check for errors here instead of pretending
everything's fine */
if (!open)
Check();
return; return;
}
if (!IsSeekable()) if (!IsSeekable())
throw std::runtime_error("Not seekable"); throw std::runtime_error("Not seekable");
......
...@@ -417,7 +417,6 @@ CurlInputStream::InitEasy() ...@@ -417,7 +417,6 @@ CurlInputStream::InitEasy()
request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases); request->SetOption(CURLOPT_HTTP200ALIASES, http_200_aliases);
request->SetOption(CURLOPT_FOLLOWLOCATION, 1L); request->SetOption(CURLOPT_FOLLOWLOCATION, 1L);
request->SetOption(CURLOPT_MAXREDIRS, 5L); request->SetOption(CURLOPT_MAXREDIRS, 5L);
request->SetOption(CURLOPT_FAILONERROR, 1L);
/* this option eliminates the probe request when /* this option eliminates the probe request when
username/password are specified */ username/password are specified */
......
...@@ -18,13 +18,13 @@ endif ...@@ -18,13 +18,13 @@ endif
conf.set('HAVE_MD5', crypto_md5_dep.found()) conf.set('HAVE_MD5', crypto_md5_dep.found())
if libavutil_dep.found() if ffmpeg_util_dep.found()
crypto_base64 = static_library( crypto_base64 = static_library(
'crypto_base64', 'crypto_base64',
'Base64.cxx', 'Base64.cxx',
include_directories: inc, include_directories: inc,
dependencies: [ dependencies: [
libavutil_dep, ffmpeg_util_dep,
], ],
) )
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "Iter.hxx" #include "Iter.hxx"
#include "Values.hxx" #include "Values.hxx"
#include <cstdint>
#include <stdexcept> #include <stdexcept>
namespace ODBus { namespace ODBus {
......
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "LogError.hxx"
#include "Domain.hxx"
#include "Log.hxx"
extern "C" {
#include <libavutil/error.h>
}
void
LogFfmpegError(int errnum)
{
char msg[256];
av_strerror(errnum, msg, sizeof(msg));
LogError(ffmpeg_domain, msg);
}
void
LogFfmpegError(int errnum, const char *prefix)
{
char msg[256];
av_strerror(errnum, msg, sizeof(msg));
FmtError(ffmpeg_domain, "{}: {}", prefix, msg);
}
/*
* Copyright 2003-2021 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_FFMPEG_LOG_ERROR_HXX
#define MPD_FFMPEG_LOG_ERROR_HXX
void
LogFfmpegError(int errnum);
void
LogFfmpegError(int errnum, const char *prefix);
#endif
...@@ -13,6 +13,29 @@ else ...@@ -13,6 +13,29 @@ else
endif endif
conf.set('HAVE_LIBAVFILTER', libavfilter_dep.found()) conf.set('HAVE_LIBAVFILTER', libavfilter_dep.found())
if not libavutil_dep.found()
ffmpeg_util_dep = dependency('', required: false)
ffmpeg_dep = dependency('', required: false)
subdir_done()
endif
ffmpeg_util = static_library(
'ffmpeg_util',
'Interleave.cxx',
'Error.cxx',
include_directories: inc,
dependencies: [
libavutil_dep,
],
)
ffmpeg_util_dep = declare_dependency(
link_with: ffmpeg_util,
dependencies: [
libavutil_dep,
],
)
if not enable_ffmpeg if not enable_ffmpeg
ffmpeg_dep = dependency('', required: false) ffmpeg_dep = dependency('', required: false)
subdir_done() subdir_done()
...@@ -30,17 +53,16 @@ ffmpeg = static_library( ...@@ -30,17 +53,16 @@ ffmpeg = static_library(
'ffmpeg', 'ffmpeg',
'Init.cxx', 'Init.cxx',
'Interleave.cxx', 'Interleave.cxx',
'LogError.cxx',
'LogCallback.cxx', 'LogCallback.cxx',
'Error.cxx', 'Error.cxx',
'Domain.cxx', 'Domain.cxx',
ffmpeg_sources, ffmpeg_sources,
include_directories: inc, include_directories: inc,
dependencies: [ dependencies: [
ffmpeg_util_dep,
libavformat_dep, libavformat_dep,
libavcodec_dep, libavcodec_dep,
libavfilter_dep, libavfilter_dep,
libavutil_dep,
log_dep, log_dep,
], ],
) )
...@@ -48,9 +70,9 @@ ffmpeg = static_library( ...@@ -48,9 +70,9 @@ ffmpeg = static_library(
ffmpeg_dep = declare_dependency( ffmpeg_dep = declare_dependency(
link_with: ffmpeg, link_with: ffmpeg,
dependencies: [ dependencies: [
ffmpeg_util_dep,
libavformat_dep, libavformat_dep,
libavcodec_dep, libavcodec_dep,
libavfilter_dep, libavfilter_dep,
libavutil_dep,
], ],
) )
...@@ -627,7 +627,7 @@ osx_render(void *vdata, ...@@ -627,7 +627,7 @@ osx_render(void *vdata,
{ {
OSXOutput *od = (OSXOutput *) vdata; OSXOutput *od = (OSXOutput *) vdata;
int count = in_number_frames * od->asbd.mBytesPerFrame; std::size_t count = in_number_frames * od->asbd.mBytesPerFrame;
buffer_list->mBuffers[0].mDataByteSize = buffer_list->mBuffers[0].mDataByteSize =
od->ring_buffer->pop((uint8_t *)buffer_list->mBuffers[0].mData, od->ring_buffer->pop((uint8_t *)buffer_list->mBuffers[0].mData,
count); count);
......
...@@ -973,6 +973,8 @@ PipeWireOutput::SendTag(const Tag &tag) ...@@ -973,6 +973,8 @@ PipeWireOutput::SendTag(const Tag &tag)
struct spa_dict dict = SPA_DICT_INIT(items, n_items); struct spa_dict dict = SPA_DICT_INIT(items, n_items);
const PipeWire::ThreadLoopLock lock(thread_loop);
auto rc = pw_stream_update_properties(stream, &dict); auto rc = pw_stream_update_properties(stream, &dict);
if (rc < 0) if (rc < 0)
LogWarning(pipewire_output_domain, "Error updating properties"); LogWarning(pipewire_output_domain, "Error updating properties");
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "storage/StorageInterface.hxx" #include "storage/StorageInterface.hxx"
#include "storage/FileInfo.hxx" #include "storage/FileInfo.hxx"
#include "storage/MemoryDirectoryReader.hxx" #include "storage/MemoryDirectoryReader.hxx"
#include "lib/curl/Error.hxx"
#include "lib/curl/Init.hxx" #include "lib/curl/Init.hxx"
#include "lib/curl/Global.hxx" #include "lib/curl/Global.hxx"
#include "lib/curl/Slist.hxx" #include "lib/curl/Slist.hxx"
...@@ -300,8 +301,9 @@ private: ...@@ -300,8 +301,9 @@ private:
/* virtual methods from CurlResponseHandler */ /* virtual methods from CurlResponseHandler */
void OnHeaders(unsigned status, Curl::Headers &&headers) final { void OnHeaders(unsigned status, Curl::Headers &&headers) final {
if (status != 207) if (status != 207)
throw FormatRuntimeError("Status %d from WebDAV server; expected \"207 Multi-Status\"", throw HttpStatusError(status,
status); StringFormat<80>("Status %u from WebDAV server; expected \"207 Multi-Status\"",
status).c_str());
if (!IsXmlContentType(headers)) if (!IsXmlContentType(headers))
throw std::runtime_error("Unexpected Content-Type from WebDAV server"); throw std::runtime_error("Unexpected Content-Type from WebDAV server");
......
...@@ -30,6 +30,10 @@ ...@@ -30,6 +30,10 @@
#include <csignal> #include <csignal>
#ifdef __linux__
#include <sys/prctl.h>
#endif
static constexpr Domain signal_handlers_domain("signal_handlers"); static constexpr Domain signal_handlers_domain("signal_handlers");
static void static void
...@@ -60,7 +64,7 @@ handle_reload_event(void *ctx) noexcept ...@@ -60,7 +64,7 @@ handle_reload_event(void *ctx) noexcept
#endif #endif
void void
SignalHandlersInit(Instance &instance) SignalHandlersInit(Instance &instance, bool daemon)
{ {
auto &loop = instance.event_loop; auto &loop = instance.event_loop;
...@@ -79,6 +83,14 @@ SignalHandlersInit(Instance &instance) ...@@ -79,6 +83,14 @@ SignalHandlersInit(Instance &instance)
SignalMonitorRegister(SIGHUP, {&instance, handle_reload_event}); SignalMonitorRegister(SIGHUP, {&instance, handle_reload_event});
#endif #endif
if (!daemon) {
#ifdef __linux__
/* if MPD was not daemonized, shut it down when the
parent process dies */
prctl(PR_SET_PDEATHSIG, SIGTERM);
#endif
}
} }
void void
......
...@@ -23,15 +23,15 @@ ...@@ -23,15 +23,15 @@
struct Instance; struct Instance;
void void
SignalHandlersInit(Instance &instance); SignalHandlersInit(Instance &instance, bool daemon);
void void
SignalHandlersFinish() noexcept; SignalHandlersFinish() noexcept;
class ScopeSignalHandlersInit { class ScopeSignalHandlersInit {
public: public:
ScopeSignalHandlersInit(Instance &instance) { ScopeSignalHandlersInit(Instance &instance, bool daemon) {
SignalHandlersInit(instance); SignalHandlersInit(instance, daemon);
} }
~ScopeSignalHandlersInit() noexcept { ~ScopeSignalHandlersInit() noexcept {
......
...@@ -40,14 +40,17 @@ class ScopeExitGuard : F { ...@@ -40,14 +40,17 @@ class ScopeExitGuard : F {
bool enabled = true; bool enabled = true;
public: public:
explicit ScopeExitGuard(F &&f):F(std::forward<F>(f)) {} explicit ScopeExitGuard(F &&f) noexcept:F(std::forward<F>(f)) {}
ScopeExitGuard(ScopeExitGuard &&src) ScopeExitGuard(ScopeExitGuard &&src) noexcept
:F(std::move(src)), enabled(src.enabled) { :F(std::move(src)),
src.enabled = false; enabled(std::exchange(src.enabled, false)) {}
}
~ScopeExitGuard() { /* destructors are "noexcept" by default; this explicit
"noexcept" declaration allows the destructor to throw if
the function can throw; without this, a throwing function
would std::terminate() */
~ScopeExitGuard() noexcept(noexcept(std::declval<F>()())) {
if (enabled) if (enabled)
F::operator()(); F::operator()();
} }
...@@ -64,7 +67,7 @@ struct ScopeExitTag { ...@@ -64,7 +67,7 @@ struct ScopeExitTag {
parantheses at the end of the expression AtScopeExit() parantheses at the end of the expression AtScopeExit()
call */ call */
template<typename F> template<typename F>
ScopeExitGuard<F> operator+(F &&f) { ScopeExitGuard<F> operator+(F &&f) noexcept {
return ScopeExitGuard<F>(std::forward<F>(f)); return ScopeExitGuard<F>(std::forward<F>(f));
} }
}; };
......
...@@ -3,10 +3,11 @@ directory = expat-2.5.0 ...@@ -3,10 +3,11 @@ directory = expat-2.5.0
source_url = https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.xz source_url = https://github.com/libexpat/libexpat/releases/download/R_2_5_0/expat-2.5.0.tar.xz
source_filename = expat-2.5.0.tar.bz2 source_filename = expat-2.5.0.tar.bz2
source_hash = ef2420f0232c087801abf705e89ae65f6257df6b7931d37846a193ef2e8cdcbe source_hash = ef2420f0232c087801abf705e89ae65f6257df6b7931d37846a193ef2e8cdcbe
patch_filename = expat_2.5.0-1_patch.zip patch_filename = expat_2.5.0-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.5.0-1/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.5.0-2/get_patch
patch_hash = 0d0d6e07ed21cf4892126a8270f5fd182012ab34b3ebe24932a2bef5ca608a61 patch_hash = f6cc5ff0d909a2f51a907cc6ca655fb18517a0f58bbe67e4a9c621f1549560c9
wrapdb_version = 2.5.0-1 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.5.0-2/expat-2.5.0.tar.bz2
wrapdb_version = 2.5.0-2
[provide] [provide]
expat = expat_dep expat = expat_dep
[wrap-file] [wrap-file]
directory = sqlite-amalgamation-3390300 directory = sqlite-amalgamation-3410200
source_url = https://sqlite.org/2022/sqlite-amalgamation-3390300.zip source_url = https://www.sqlite.org/2023/sqlite-amalgamation-3410200.zip
source_filename = sqlite-amalgamation-3390300.zip source_filename = sqlite-amalgamation-3410200.zip
source_hash = a89db3030d229d860ae56a8bac50ac9761434047ae886e47e7c8f9f428fa98ad source_hash = 01df06a84803c1ab4d62c64e995b151b2dbcf5dbc93bbc5eee213cb18225d987
patch_filename = sqlite3_3.39.3-1_patch.zip patch_filename = sqlite3_3.41.2-2_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.39.3-1/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/sqlite3_3.41.2-2/get_patch
patch_hash = f5c41ff7b3da1108ed221b9a820b41188550cafb8a6c3d247bb40bd598775050 patch_hash = 246681dfb731a14bfa61bcde651d5581a7e1c7d14851bfb57a941fac540a6810
wrapdb_version = 3.39.3-1 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sqlite3_3.41.2-2/sqlite-amalgamation-3410200.zip
wrapdb_version = 3.41.2-2
[provide] [provide]
sqlite3 = sqlite3_dep sqlite3 = sqlite3_dep
systemd_system_unit_dir = get_option('systemd_system_unit_dir') 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)
if systemd.found()
systemd_system_unit_dir = systemd.get_variable(pkgconfig: 'systemdsystemunitdir')
endif
endif
if systemd_system_unit_dir == ''
systemd_system_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'system') systemd_system_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'system')
endif endif
......
systemd_user_unit_dir = get_option('systemd_user_unit_dir') 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)
if systemd.found()
systemd_user_unit_dir = systemd.get_variable(pkgconfig: 'systemduserunitdir')
endif
endif
if systemd_user_unit_dir == ''
systemd_user_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'user') systemd_user_unit_dir = join_paths(get_option('prefix'), 'lib', 'systemd', 'user')
endif endif
......
...@@ -48,6 +48,7 @@ class CrossGccToolchain: ...@@ -48,6 +48,7 @@ class CrossGccToolchain:
self.cc = os.path.join(toolchain_bin, arch + '-gcc') self.cc = os.path.join(toolchain_bin, arch + '-gcc')
self.cxx = os.path.join(toolchain_bin, arch + '-g++') self.cxx = os.path.join(toolchain_bin, arch + '-g++')
self.ar = os.path.join(toolchain_bin, arch + '-ar') self.ar = os.path.join(toolchain_bin, arch + '-ar')
self.arflags = 'rcs'
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib') self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
self.nm = os.path.join(toolchain_bin, arch + '-nm') self.nm = os.path.join(toolchain_bin, arch + '-nm')
self.strip = os.path.join(toolchain_bin, arch + '-strip') self.strip = os.path.join(toolchain_bin, arch + '-strip')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment