1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-05 20:41:47 +02:00

Merge remote-tracking branch 'upstream/master' into rm-createdirs

This commit is contained in:
John Ericson 2024-06-17 12:57:54 -04:00
commit a1bb668ccb
112 changed files with 2290 additions and 893 deletions

1
src/libutil/.version Symbolic link
View file

@ -0,0 +1 @@
../../.version

View file

@ -140,6 +140,7 @@ public:
};
#ifndef _WIN32 // Not needed on Windows, where we don't fork
namespace unix {
/**
* Close all file descriptors except those listed in the given set.
@ -152,13 +153,16 @@ void closeMostFDs(const std::set<Descriptor> & exceptions);
*/
void closeOnExec(Descriptor fd);
} // namespace unix
#endif
#ifdef _WIN32
# if _WIN32_WINNT >= 0x0600
#if defined(_WIN32) && _WIN32_WINNT >= 0x0600
namespace windows {
Path handleToPath(Descriptor handle);
std::wstring handleToFileName(Descriptor handle);
# endif
} // namespace windows
#endif
MakeError(EndOfFile, Error);

View file

@ -525,7 +525,7 @@ std::pair<AutoCloseFD, Path> createTempFile(const Path & prefix)
if (!fd)
throw SysError("creating temporary file '%s'", tmpl);
#ifndef _WIN32
closeOnExec(fd.get());
unix::closeOnExec(fd.get());
#endif
return {std::move(fd), tmpl};
}

View file

@ -52,11 +52,11 @@ bool Hash::operator == (const Hash & h2) const
std::strong_ordering Hash::operator <=> (const Hash & h) const
{
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
if (auto cmp = hashSize <=> h.hashSize; cmp != 0) return cmp;
for (unsigned int i = 0; i < hashSize; i++) {
if (auto cmp = hash[i] <=> h.hash[i]; cmp != 0) return cmp;
}
if (auto cmp = algo <=> h.algo; cmp != 0) return cmp;
return std::strong_ordering::equivalent;
}

View file

@ -0,0 +1,11 @@
sources += files(
'cgroup.cc',
'namespaces.cc',
)
include_dirs += include_directories('.')
headers += files(
'cgroup.hh',
'namespaces.hh',
)

332
src/libutil/meson.build Normal file
View file

@ -0,0 +1,332 @@
project('nix-util', 'cpp',
version : files('.version'),
default_options : [
'cpp_std=c++2a',
# TODO(Qyriad): increase the warning level
'warning_level=1',
'debug=true',
'optimization=2',
'errorlogs=true', # Please print logs for tests that fail
],
meson_version : '>= 1.1',
license : 'LGPL-2.1-or-later',
)
cxx = meson.get_compiler('cpp')
# These are private dependencies with pkg-config files. What private
# means is that the dependencies are used by the library but they are
# *not* used (e.g. `#include`-ed) in any installed header file, and only
# in regular source code (`*.cc`) or private, uninstalled headers. They
# are thus part of the *implementation* of the library, but not its
# *interface*.
#
# See `man pkg-config` for some details.
deps_private = [ ]
# These are public dependencies with pkg-config files. Public is the
# opposite of private: these dependencies are used in installed header
# files. They are part of the interface (and implementation) of the
# library.
#
# N.B. This concept is mostly unrelated to our own concept of a public
# (stable) API, for consumption outside of the Nix repository.
# `libnixutil` is an unstable C++ library, whose public interface is
# likewise unstable. `libutilc` conversely is a hopefully-soon stable
# C library, whose public interface --- including public but not private
# dependencies --- will also likewise soon be stable.
#
# N.B. For distributions that care about "ABI" stablity and not just
# "API" stability, the private dependencies also matter as they can
# potentially affect the public ABI.
deps_public = [ ]
# These are dependencencies without pkg-config files. Ideally they are
# just private, but they may also be public (e.g. boost).
deps_other = [ ]
configdata = configuration_data()
# Check for each of these functions, and create a define like `#define
# HAVE_LUTIMES 1`. The `#define` is unconditional, 0 for not found and 1
# for found. One therefore uses it with `#if` not `#ifdef`.
check_funcs = [
# Optionally used for changing the mtime of symlinks.
'lutimes',
# Optionally used for creating pipes on Unix
'pipe2',
# Optionally used to preallocate files to be large enough before
# writing to them.
'posix_fallocate',
# Optionally used to get more information about processes failing due
# to a signal on Unix.
'strsignal',
# Optionally used to try to close more file descriptors (e.g. before
# forking) on Unix.
'sysconf',
]
foreach funcspec : check_funcs
define_name = 'HAVE_' + funcspec.underscorify().to_upper()
define_value = cxx.has_function(funcspec).to_int()
configdata.set(define_name, define_value)
endforeach
# This is only conditional to work around
# https://github.com/mesonbuild/meson/issues/13293. It should be
# unconditional.
if not (host_machine.system() == 'windows' and cxx.get_id() == 'gcc')
deps_private += dependency('threads')
endif
if host_machine.system() == 'windows'
socket = cxx.find_library('ws2_32')
deps_other += socket
elif host_machine.system() == 'sunos'
socket = cxx.find_library('socket')
network_service_library = cxx.find_library('nsl')
deps_other += [socket, network_service_library]
endif
boost = dependency(
'boost',
modules : ['context', 'coroutine'],
)
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
# put in `deps_other`.
deps_other += boost
openssl = dependency(
'libcrypto',
'openssl',
version : '>= 1.1.1',
)
deps_private += openssl
libarchive = dependency('libarchive', version : '>= 3.1.2')
deps_public += libarchive
if get_option('default_library') == 'static'
# Workaround until https://github.com/libarchive/libarchive/issues/1446 is fixed
add_project_arguments('-lz', language : 'cpp')
endif
sodium = dependency('libsodium', 'sodium')
deps_private += sodium
brotli = [
dependency('libbrotlicommon'),
dependency('libbrotlidec'),
dependency('libbrotlienc'),
]
deps_private += brotli
cpuid_required = get_option('cpuid')
if host_machine.cpu_family() != 'x86_64' and cpuid_required.enabled()
warning('Force-enabling seccomp on non-x86_64 does not make sense')
endif
cpuid = dependency('libcpuid', 'cpuid', required : cpuid_required)
configdata.set('HAVE_LIBCPUID', cpuid.found().to_int())
deps_private += cpuid
nlohmann_json = dependency('nlohmann_json', version : '>= 3.9')
deps_public += nlohmann_json
config_h = configure_file(
configuration : configdata,
output : 'config-util.h',
)
add_project_arguments(
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
# It would be nice for our headers to be idempotent instead.
'-include', 'config-util.h',
'-Wno-deprecated-declarations',
'-Wimplicit-fallthrough',
'-Werror=switch',
'-Werror=switch-enum',
'-Wdeprecated-copy',
'-Wignored-qualifiers',
# Enable assertions in libstdc++ by default. Harmless on libc++. Benchmarked
# at ~1% overhead in `nix search`.
#
# FIXME: remove when we get meson 1.4.0 which will default this to on for us:
# https://mesonbuild.com/Release-notes-for-1-4-0.html#ndebug-setting-now-controls-c-stdlib-assertions
'-D_GLIBCXX_ASSERTIONS=1',
language : 'cpp',
)
sources = files(
'archive.cc',
'args.cc',
'canon-path.cc',
'compression.cc',
'compute-levels.cc',
'config.cc',
'current-process.cc',
'english.cc',
'environment-variables.cc',
'error.cc',
'exit.cc',
'experimental-features.cc',
'file-content-address.cc',
'file-descriptor.cc',
'file-system.cc',
'fs-sink.cc',
'git.cc',
'hash.cc',
'hilite.cc',
'json-utils.cc',
'logging.cc',
'memory-source-accessor.cc',
'position.cc',
'posix-source-accessor.cc',
'references.cc',
'serialise.cc',
'signature/local-keys.cc',
'signature/signer.cc',
'source-accessor.cc',
'source-path.cc',
'suggestions.cc',
'tarfile.cc',
'terminal.cc',
'thread-pool.cc',
'unix-domain-socket.cc',
'url.cc',
'users.cc',
'util.cc',
'xml-writer.cc',
)
include_dirs = [include_directories('.')]
headers = [config_h] + files(
'abstract-setting-to-json.hh',
'ansicolor.hh',
'archive.hh',
'args.hh',
'args/root.hh',
'callback.hh',
'canon-path.hh',
'chunked-vector.hh',
'closure.hh',
'comparator.hh',
'compression.hh',
'compute-levels.hh',
'config-impl.hh',
'config.hh',
'current-process.hh',
'english.hh',
'environment-variables.hh',
'error.hh',
'exit.hh',
'experimental-features.hh',
'file-content-address.hh',
'file-descriptor.hh',
'file-path-impl.hh',
'file-path.hh',
'file-system.hh',
'finally.hh',
'fmt.hh',
'fs-sink.hh',
'git.hh',
'hash.hh',
'hilite.hh',
'json-impls.hh',
'json-utils.hh',
'logging.hh',
'lru-cache.hh',
'memory-source-accessor.hh',
'muxable-pipe.hh',
'pool.hh',
'position.hh',
'posix-source-accessor.hh',
'processes.hh',
'ref.hh',
'references.hh',
'regex-combinators.hh',
'repair-flag.hh',
'serialise.hh',
'signals.hh',
'signature/local-keys.hh',
'signature/signer.hh',
'source-accessor.hh',
'source-path.hh',
'split.hh',
'suggestions.hh',
'sync.hh',
'tarfile.hh',
'terminal.hh',
'thread-pool.hh',
'topo-sort.hh',
'types.hh',
'unix-domain-socket.hh',
'url-parts.hh',
'url.hh',
'users.hh',
'util.hh',
'variant-wrapper.hh',
'xml-writer.hh',
)
if host_machine.system() == 'linux'
subdir('linux')
endif
if host_machine.system() == 'windows'
subdir('windows')
else
subdir('unix')
endif
if host_machine.system() == 'cygwin' or host_machine.system() == 'windows'
# Windows DLLs are stricter about symbol visibility than Unix shared
# objects --- see https://gcc.gnu.org/wiki/Visibility for details.
# This is a temporary sledgehammer to export everything like on Unix,
# and not detail with this yet.
#
# TODO do not do this, and instead do fine-grained export annotations.
linker_export_flags = ['-Wl,--export-all-symbols']
else
linker_export_flags = []
endif
this_library = library(
'nixutil',
sources,
dependencies : deps_public + deps_private + deps_other,
include_directories : include_dirs,
link_args: linker_export_flags,
install : true,
)
install_headers(headers, subdir : 'nix', preserve_path : true)
# Part of how we copy boost libraries to a separate installation to
# reduce closure size. These libraries will be copied to our `$out/bin`,
# and these `-l` flags will pick them up there.
#
# https://github.com/NixOS/nixpkgs/issues/45462
libraries_private = ['-lboost_context', '-lboost_coroutine']
if host_machine.system() == 'windows'
# `libraries_private` cannot contain ad-hoc dependencies (from
# `find_library), so we need to do this manually
libraries_private += ['-lws2_32']
endif
import('pkgconfig').generate(
this_library,
filebase : meson.project_name(),
name : 'Nix',
description : 'Nix Package Manager',
subdirs : ['nix'],
extra_cflags : ['-std=c++2a'],
requires : deps_public,
requires_private : deps_private,
libraries_private : libraries_private,
)
meson.override_dependency(meson.project_name(), declare_dependency(
include_directories : include_dirs,
link_with : this_library,
compile_args : ['-std=c++2a'],
dependencies : [],
))

View file

@ -0,0 +1,5 @@
# vim: filetype=meson
option('cpuid', type : 'feature',
description : 'determine microarchitecture levels with libcpuid (only relevant on x86_64)',
)

149
src/libutil/package.nix Normal file
View file

@ -0,0 +1,149 @@
{ lib
, stdenv
, releaseTools
, fileset
, meson
, ninja
, pkg-config
, boost
, brotli
, libarchive
, libcpuid
, libsodium
, nlohmann_json
, openssl
# Configuration Options
, versionSuffix ? ""
, officialRelease ? false
# Check test coverage of Nix. Probably want to use with at least
# one of `doCheck` or `doInstallCheck` enabled.
, withCoverageChecks ? false
}:
let
version = lib.fileContents ./.version + versionSuffix;
mkDerivation =
if withCoverageChecks
then
# TODO support `finalAttrs` args function in
# `releaseTools.coverageAnalysis`.
argsFun:
releaseTools.coverageAnalysis (let args = argsFun args; in args)
else stdenv.mkDerivation;
in
mkDerivation (finalAttrs: {
pname = "nix-util";
inherit version;
src = fileset.toSource {
root = ./.;
fileset = fileset.unions [
./meson.build
./meson.options
./linux/meson.build
./unix/meson.build
./windows/meson.build
(fileset.fileFilter (file: file.hasExt "cc") ./.)
(fileset.fileFilter (file: file.hasExt "hh") ./.)
];
};
outputs = [ "out" "dev" ];
nativeBuildInputs = [
meson
ninja
pkg-config
];
buildInputs = [
boost
brotli
libsodium
openssl
] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid
;
propagatedBuildInputs = [
libarchive
nlohmann_json
];
disallowedReferences = [ boost ];
preConfigure =
# "Inline" .version so it's not a symlink, and includes the suffix
''
echo ${version} > .version
''
# Copy some boost libraries so we don't get all of Boost in our
# closure. https://github.com/NixOS/nixpkgs/issues/45462
+ lib.optionalString (!stdenv.hostPlatform.isStatic) (''
mkdir -p $out/lib
cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
rm -f $out/lib/*.a
'' + lib.optionalString stdenv.hostPlatform.isLinux ''
chmod u+w $out/lib/*.so.*
patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
'' + lib.optionalString stdenv.hostPlatform.isDarwin ''
for LIB in $out/lib/*.dylib; do
chmod u+w $LIB
install_name_tool -id $LIB $LIB
install_name_tool -delete_rpath ${boost}/lib/ $LIB || true
done
install_name_tool -change ${boost}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib
''
);
mesonFlags = [
(lib.mesonEnable "cpuid" stdenv.hostPlatform.isx86_64)
];
env = {
# Needed for Meson to find Boost.
# https://github.com/NixOS/nixpkgs/issues/86131.
BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
} // lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
LDFLAGS = "-fuse-ld=gold";
};
enableParallelBuilding = true;
postInstall =
# Remove absolute path to boost libs that ends up in `Libs.private`
# by default, and would clash with out `disallowedReferences`. Part
# of the https://github.com/NixOS/nixpkgs/issues/45462 workaround.
''
sed -i "$out/lib/pkgconfig/nix-util.pc" -e 's, ${lib.getLib boost}[^ ]*,,g'
''
+ lib.optionalString stdenv.isDarwin ''
install_name_tool \
-change ${boost}/lib/libboost_context.dylib \
$out/lib/libboost_context.dylib \
$out/lib/libnixutil.dylib
'';
separateDebugInfo = !stdenv.hostPlatform.isStatic;
# TODO Always true after https://github.com/NixOS/nixpkgs/issues/318564
strictDeps = !withCoverageChecks;
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
meta = {
platforms = lib.platforms.unix ++ lib.platforms.windows;
};
} // lib.optionalAttrs withCoverageChecks {
lcovFilter = [ "*/boost/*" "*-tab.*" ];
hardeningDisable = [ "fortify" ];
})

View file

@ -79,7 +79,8 @@ TarArchive::TarArchive(Source & source, bool raw, std::optional<std::string> com
}
if (!raw) {
archive_read_support_format_all(archive);
archive_read_support_format_tar(archive);
archive_read_support_format_zip(archive);
} else {
archive_read_support_format_raw(archive);
archive_read_support_format_empty(archive);
@ -96,7 +97,8 @@ TarArchive::TarArchive(const Path & path)
, buffer(defaultBufferSize)
{
archive_read_support_filter_all(archive);
archive_read_support_format_all(archive);
archive_read_support_format_tar(archive);
archive_read_support_format_zip(archive);
archive_read_set_option(archive, NULL, "mac-ext", NULL);
check(archive_read_open_filename(archive, path.c_str(), 16384), "failed to open archive: %s");
}

View file

@ -24,7 +24,7 @@ AutoCloseFD createUnixDomainSocket()
if (!fdSocket)
throw SysError("cannot create Unix domain socket");
#ifndef _WIN32
closeOnExec(fdSocket.get());
unix::closeOnExec(fdSocket.get());
#endif
return fdSocket;
}

View file

@ -110,8 +110,8 @@ void Pipe::create()
if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe");
#else
if (pipe(fds) != 0) throw SysError("creating pipe");
closeOnExec(fds[0]);
closeOnExec(fds[1]);
unix::closeOnExec(fds[0]);
unix::closeOnExec(fds[1]);
#endif
readSide = fds[0];
writeSide = fds[1];
@ -120,7 +120,7 @@ void Pipe::create()
//////////////////////////////////////////////////////////////////////
void closeMostFDs(const std::set<int> & exceptions)
void unix::closeMostFDs(const std::set<int> & exceptions)
{
#if __linux__
try {
@ -139,14 +139,16 @@ void closeMostFDs(const std::set<int> & exceptions)
#endif
int maxFD = 0;
#if HAVE_SYSCONF
maxFD = sysconf(_SC_OPEN_MAX);
#endif
for (int fd = 0; fd < maxFD; ++fd)
if (!exceptions.count(fd))
close(fd); /* ignore result */
}
void closeOnExec(int fd)
void unix::closeOnExec(int fd)
{
int prev;
if ((prev = fcntl(fd, F_GETFD, 0)) == -1 ||

View file

@ -0,0 +1,17 @@
sources += files(
'environment-variables.cc',
'file-descriptor.cc',
'file-path.cc',
'file-system.cc',
'muxable-pipe.cc',
'processes.cc',
'signals.cc',
'users.cc',
)
include_dirs += include_directories('.')
headers += files(
'monitor-fd.hh',
'signals-impl.hh',
)

View file

@ -122,7 +122,7 @@ void Pipe::create()
#if _WIN32_WINNT >= 0x0600
std::wstring handleToFileName(HANDLE handle) {
std::wstring windows::handleToFileName(HANDLE handle) {
std::vector<wchar_t> buf(0x100);
DWORD dw = GetFinalPathNameByHandleW(handle, buf.data(), buf.size(), FILE_NAME_OPENED);
if (dw == 0) {
@ -141,7 +141,7 @@ std::wstring handleToFileName(HANDLE handle) {
}
Path handleToPath(HANDLE handle) {
Path windows::handleToPath(HANDLE handle) {
return os_string_to_string(handleToFileName(handle));
}

View file

@ -0,0 +1,19 @@
sources += files(
'environment-variables.cc',
'file-descriptor.cc',
'file-path.cc',
'file-system.cc',
'muxable-pipe.cc',
'processes.cc',
'users.cc',
'windows-async-pipe.cc',
'windows-error.cc',
)
include_dirs += include_directories('.')
headers += files(
'signals-impl.hh',
'windows-async-pipe.hh',
'windows-error.hh',
)