diff --git a/flake.nix b/flake.nix index 11c461896..c50ecf00a 100644 --- a/flake.nix +++ b/flake.nix @@ -204,6 +204,11 @@ # Binary package for various platforms. build = forAllSystems (system: self.packages.${system}.nix); + # FIXME(Qyriad): remove this when the migration to Meson has been completed. + mesonBuild = forAllSystems (system: self.packages.${system}.nix.override { + buildWithMeson = true; + }); + # Perl bindings for various platforms. perlBindings = forAllSystems (system: nixpkgsFor.${system}.native.nix.perl-bindings); @@ -262,6 +267,8 @@ }; checks = forAllSystems (system: { + # FIXME(Qyriad): remove this when the migration to Meson has been completed. + mesonBuild = self.hydraJobs.mesonBuild.${system}; binaryTarball = self.hydraJobs.binaryTarball.${system}; perlBindings = self.hydraJobs.perlBindings.${system}; nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system}; @@ -321,7 +328,12 @@ ++ lib.optional (stdenv.cc.isClang && !stdenv.buildPlatform.isDarwin) pkgs.buildPackages.bear ++ lib.optional (stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform) - pkgs.buildPackages.clang-tools; + pkgs.buildPackages.clang-tools + ++ [ + # FIXME(Qyriad): remove once the migration to Meson is complete. + pkgs.buildPackages.meson + pkgs.buildPackages.ninja + ]; src = null; diff --git a/meson.build b/meson.build new file mode 100644 index 000000000..4fc8ca112 --- /dev/null +++ b/meson.build @@ -0,0 +1,294 @@ +# +# OUTLINE: +# +# The top-level meson.build file (this file) handles general logic for build options, +# generation of config.h (which is put in the build directory, not the source root +# like the previous, autoconf-based build system did), the mechanism for header +# generation, and the few global C++ compiler arguments that are added to all targets in Lix. +# +# src/meson.build coordinates each of Lix's subcomponents (the lib dirs in ./src), +# which each have their own meson.build. Lix's components depend on each other, +# so each of `src/lib{util,store,fetchers,expr,main,cmd}/meson.build` rely on variables +# set in earlier `meson.build` files. Each of these also defines the install targets for +# their headers. +# +# src/meson.build also collects the miscellaneous source files that are in further subdirectories +# that become part of the final Nix command (things like `src/nix-build/*.cc`). +# +# Finally, src/nix/meson.build defines the Nix command itself, relying on all prior meson files. + +project('lix', 'cpp', + version : run_command('bash', '-c', 'echo -n $(cat ./.version)$VERSION_SUFFIX', check : true).stdout().strip(), + default_options : [ + 'cpp_std=c++20', + # TODO(Qyriad): increase the warning level + 'warning_level=1', + 'debug=true', + 'optimization=2', + ], +) + +fs = import('fs') + +prefix = get_option('prefix') +# For each of these paths, assume that it is relative to the prefix unless +# it is already an absolute path (which is the default for store-dir, state-dir, and log-dir). +path_opts = [ + # Meson built-ins. + 'datadir', + 'sysconfdir', + 'bindir', + 'mandir', + 'libdir', + 'includedir', + # Homecooked Lix directories. + 'store-dir', + 'state-dir', + 'log-dir', +] +foreach optname : path_opts + varname = optname.replace('-', '_') + path = get_option(optname) + if fs.is_absolute(path) + set_variable(varname, path) + else + set_variable(varname, prefix / path) + endif +endforeach + +cxx = meson.get_compiler('cpp') + +host_system = host_machine.cpu_family() + '-' + host_machine.system() +message('canonical Nix system name:', host_system) + +deps = [ ] +configdata = { } + +# +# Dependencies +# + +boehm = dependency('bdw-gc', required : get_option('gc')) +if boehm.found() + deps += boehm +endif +configdata += { + 'HAVE_BOEHMGC': boehm.found().to_int(), +} + +boost = dependency('boost', required : true, modules : ['context', 'coroutine', 'container']) +deps += boost + +cpuid = dependency('libcpuid', 'cpuid', required : get_option('cpuid')) +configdata += { + 'HAVE_LIBCPUID': cpuid.found().to_int(), + } +deps += cpuid + +seccomp = dependency('libseccomp', 'seccomp', required : get_option('seccomp-sandboxing')) +configdata += { + 'HAVE_SECCOMP': seccomp.found().to_int(), + } + +libarchive = dependency('libarchive', required : true) +deps += libarchive + +brotli = [ + dependency('libbrotlicommon', required : true), + dependency('libbrotlidec', required : true), + dependency('libbrotlienc', required : true), + ] +deps += brotli + +openssl = dependency('libcrypto', 'openssl', required : true) +deps += openssl + +aws_sdk = dependency('aws-cpp-sdk-core', required : true) +if aws_sdk.found() + # The AWS pkg-config adds -std=c++11. + aws_sdk = aws_sdk.partial_dependency( + compile_args : false, + includes : true, + link_args : true, + links : true, + sources : true, + ) + deps += aws_sdk + s = aws_sdk.version().split('.') + configdata += { + 'AWS_VERSION_MAJOR': s[0].to_int(), + 'AWS_VERSION_MINOR': s[1].to_int(), + 'AWS_VERSION_PATCH': s[2].to_int(), + } + aws_sdk_transfer = dependency('aws-cpp-sdk-transfer', required : true).partial_dependency( + compile_args : false, + includes : true, + link_args : true, + links : true, + sources : true, + ) +endif + +aws_s3 = dependency('aws-cpp-sdk-s3', required : true) +if aws_s3.found() + # The AWS pkg-config adds -std=c++11. + aws_s3 = aws_s3.partial_dependency( + compile_args : false, + includes : true, + link_args : true, + links : true, + sources : true, + ) + deps += aws_s3 +endif + +configdata += { + 'ENABLE_S3': aws_s3.found().to_int(), +} + +sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19', required : true) +deps += sqlite + +sodium = dependency('libsodium', 'sodium', required : true) +deps += sodium + +curl = dependency('libcurl', 'curl', required : true) +deps += curl + +editline = dependency('libeditline', 'editline', version : '>=1.14', required : true) +deps += editline + +lowdown = dependency('lowdown', version : '>=0.9.0', required : true) +deps += lowdown + +rapidcheck = dependency('rapidcheck', required : false) +deps += rapidcheck + +gtest = dependency('gtest', required : false) +deps += gtest + +# +# Build-time tools +# +bash = find_program('bash') + +# Used to workaround https://github.com/mesonbuild/meson/issues/2320 in src/nix/meson.build. +installcmd = find_program('install') + +sandbox_shell = get_option('sandbox-shell') +# Consider it required if we're on Linux and the user explicitly specified a non-default value. +sandbox_shell_required = sandbox_shell != 'busybox' and host_machine.system() == 'linux' +# NOTE(Qyriad): package.nix puts busybox in buildInputs for Linux. +# Most builds should not require setting this. +busybox = find_program(sandbox_shell, required : sandbox_shell_required, native : false) +if not busybox.found() and host_machine.system() == 'linux' and sandbox_shell_required + warning('busybox not found and other sandbox shell was specified') + warning('a sandbox shell is recommended on Linux -- configure with -Dsandbox-shell=/path/to/shell to set') +endif +# FIXME(Qyriad): the autoconf system checks that busybox has the "standalone" feature, indicating +# that busybox sh won't run busybox applets as builtins (which would break our sandbox). + +lsof = find_program('lsof') +bison = find_program('bison') +flex = find_program('flex') + +# This is how Nix does generated headers... +# FIXME(Qyriad): do we really need to use the shell for this? +gen_header = generator( + bash, + arguments : [ + '-c', + 'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\'', + ], + capture : true, + output : '@PLAINNAME@.gen.hh', +) + +# +# Configuration +# + +run_command('ln', '-s', + meson.project_build_root() / '__nothing_link_target', + meson.project_build_root() / '__nothing_symlink', + check : true, +) +can_link_symlink = run_command('ln', + meson.project_build_root() / '__nothing_symlink', + meson.project_build_root() / '__nothing_hardlink', + check : false, +).returncode() == 0 +run_command('rm', '-f', + meson.project_build_root() / '__nothing_symlink', + meson.project_build_root() / '__nothing_hardlink', + check : true, +) +summary('can hardlink to symlink', can_link_symlink, bool_yn : true) +configdata += { 'CAN_LINK_SYMLINK': can_link_symlink.to_int() } + + +# Check for each of these functions, and create a define like `#define HAVE_LCHOWN 1`. +check_funcs = [ + 'lchown', + 'lutimes', + 'pipe2', + 'posix_fallocate', + 'statvfs', + 'strsignal', + 'sysconf', +] +foreach funcspec : check_funcs + define_name = 'HAVE_' + funcspec.underscorify().to_upper() + define_value = cxx.has_function(funcspec).to_int() + configdata += { + define_name: define_value, + } +endforeach + +# extern "C++" functions can't be checked with the normal mechanism (much less member functions), +# so we have to do this one ourselves. +has_pubsetbuf = cxx.compiles(''' + #include + using namespace std; + static char buf[1024]; + decltype(cerr.rdbuf()->pubsetbuf(buf, sizeof(buf))) _; +''') +summary('have std::basic_streambuf::pubsetbuf', has_pubsetbuf, bool_yn : true) +configdata += { + 'HAVE_PUBSETBUF': has_pubsetbuf.to_int(), +} + +config_h = configure_file( + configuration : { + 'PACKAGE_NAME': '"' + meson.project_name() + '"', + 'PACKAGE_VERSION': '"' + meson.project_version() + '"', + 'PACKAGE_TARNAME': '"' + meson.project_name() + '"', + 'PACKAGE_STRING': '"' + meson.project_name() + ' ' + meson.project_version() + '"', + 'HAVE_STRUCT_DIRENT_D_TYPE': 1, # FIXME: actually check this for solaris + 'SYSTEM': '"' + host_system + '"', + } + configdata, + output : 'config.h', +) + +install_headers(config_h, subdir : 'nix') + +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.h', + '-Wno-deprecated-declarations', + '-Wimplicit-fallthrough', + '-Werror=switch', + '-Werror=switch-enum', + language : 'cpp', +) + +add_project_link_arguments( + '-pthread', + # FIXME(Qyriad): autoconf did this only if not Darwin, Solaris, or FreeBSD + # (...so only if Linux?) + '-Wl,--no-copy-dt-needed-entries', + language : 'cpp', +) + +subdir('src') diff --git a/meson.options b/meson.options new file mode 100644 index 000000000..59412a1af --- /dev/null +++ b/meson.options @@ -0,0 +1,32 @@ +# vim: filetype=meson +option('gc', type : 'feature', + description : 'enable garbage collection in the Nix expression evaluator (requires Boehm GC)', +) +# TODO(Qyriad): is this feature maintained? +option('embedded-sandbox-shell', type : 'feature', + description : 'include the sandbox shell in the Nix bindary', +) + +option('cpuid', type : 'feature', + description : 'determine microarchitecture levels with libcpuid (only relevant on x86_64)', +) + +option('seccomp-sandboxing', type : 'feature', + description : 'build support for seccomp sandboxing (recommended unless your arch doesn\'t support libseccomp, only relevant on Linux)', +) + +option('sandbox-shell', type : 'string', value : 'busybox', + description : 'path to a statically-linked shell to use as /bin/sh in sandboxes (usually busybox)', +) + +option('store-dir', type : 'string', value : '/nix/store', + description : 'path of the Nix store', +) + +option('state-dir', type : 'string', value : '/nix/var/nix', + description : 'path to store state in for Nix', +) + +option('log-dir', type : 'string', value : '/nix/var/log', + description : 'path to store logs in for Nix', +) diff --git a/meson/cleanup-install.bash b/meson/cleanup-install.bash new file mode 100755 index 000000000..a07928b7d --- /dev/null +++ b/meson/cleanup-install.bash @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Meson will call this with an absolute path to Bash. +# The shebang is just for convenience. + +set -euo pipefail + +echo "cleanup-install: removing Meson-placed C++ sources from dest includedir" + +if [[ "${1/--help/}" != "$1" ]]; then + echo "cleanup-install: this script should only be called from the Meson build system" + exit 1 +fi + +# Ensure the includedir was passed as the first argument +# (set -u will make this fail otherwise). +includedir="$1" +# And then ensure that first argument is a directory that exists. +if ! [[ -d "$1" ]]; then + echo "cleanup-install: this script should only be called from the Meson build system" + echo "argv[1] (${1@Q}) is not a directory" + exit 2 +fi + +# If DESTDIR environment variable is set, prepend it to the include dir. +# Unfortunately, we cannot do this on the Meson side. We do have an environment variable +# `MESON_INSTALL_DESTDIR_PREFIX`, but that will not refer to the include directory if +# includedir has been set separately, which Lix's split-output derivation does. +# We also cannot simply do an inline bash conditional like "${DESTDIR:=}" or similar, +# because we need to specifically *join* DESTDIR and includedir with a slash, and *not* +# have a slash if DESTDIR isn't set at all, since $includedir could be a relative directory. +# Finally, DESTDIR is only available to us as an environment variable in these install scripts, +# not in Meson logic. +# Therefore, our best option is to have Meson pass this script the configured includedir, +# and perform this dance with it and $DESTDIR. +if [[ -n "${DESTDIR:-}" ]]; then + includedir="$DESTDIR/$includedir" +fi + +# Intentionally not using -f. +# If these files don't exist then our assumptions have been violated and we should fail. +rm -v "$includedir/nix/parser-tab.cc" "$includedir/nix/lexer-tab.cc" diff --git a/package.nix b/package.nix index 8d33759b7..cf1a6cdaf 100644 --- a/package.nix +++ b/package.nix @@ -24,10 +24,13 @@ libcpuid, libseccomp, libsodium, + lsof, lowdown, mdbook, mdbook-linkcheck, mercurial, + meson, + ninja, openssl, pkg-config, rapidcheck, @@ -47,6 +50,10 @@ # Avoid setting things that would interfere with a functioning devShell forDevShell ? false, + # FIXME(Qyriad): build Lix using Meson instead of autoconf and make. + # This flag will be removed when the migration to Meson is complete. + buildWithMeson ? false, + # Not a real argument, just the only way to approximate let-binding some # stuff for argument defaults. __forDefaults ? { @@ -86,12 +93,16 @@ ./README.md ]; - topLevelBuildFiles = fileset.unions [ + topLevelBuildFiles = fileset.unions ([ ./local.mk ./Makefile ./Makefile.config.in ./mk - ]; + ] ++ lib.optionals buildWithMeson [ + ./meson.build + ./meson.options + ./meson/cleanup-install.bash + ]); functionalTestFiles = fileset.unions [ ./tests/functional @@ -126,6 +137,11 @@ in stdenv.mkDerivation (finalAttrs: { dontBuild = false; + # FIXME(Qyriad): see if this is still needed once the migration to Meson is completed. + mesonFlags = lib.optionals (buildWithMeson && stdenv.hostPlatform.isLinux) [ + "-Dsandbox-shell=${lib.getBin busybox-sandbox-shell}/bin/busybox" + ]; + nativeBuildInputs = [ bison flex @@ -134,17 +150,21 @@ in stdenv.mkDerivation (finalAttrs: { mdbook mdbook-linkcheck autoconf-archive - autoreconfHook + ] ++ lib.optional (!buildWithMeson) autoreconfHook ++ [ pkg-config # Tests git mercurial jq + lsof ] ++ lib.optional stdenv.hostPlatform.isLinux util-linuxMinimal ++ lib.optional (!officialRelease && buildUnreleasedNotes) changelog-d ++ lib.optional internalApiDocs doxygen - ; + ++ lib.optionals buildWithMeson [ + meson + ninja + ]; buildInputs = [ curl @@ -159,7 +179,7 @@ in stdenv.mkDerivation (finalAttrs: { lowdown libsodium ] - ++ lib.optionals stdenv.isLinux [ libseccomp ] + ++ lib.optionals stdenv.hostPlatform.isLinux [ libseccomp busybox-sandbox-shell ] ++ lib.optional stdenv.hostPlatform.isx86_64 libcpuid # There have been issues building these dependencies ++ lib.optional (stdenv.hostPlatform == stdenv.buildPlatform) aws-sdk-cpp-nix @@ -177,6 +197,13 @@ in stdenv.mkDerivation (finalAttrs: { boost ]; + # Needed for Meson to find Boost. + # https://github.com/NixOS/nixpkgs/issues/86131. + env = lib.optionalAttrs (buildWithMeson || forDevShell) { + BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; + BOOST_LIBRARYDIR = "${lib.getLib boost}/lib"; + }; + preConfigure = lib.optionalString (!finalAttrs.dontBuild && !stdenv.hostPlatform.isStatic) '' # Copy libboost_context so we don't get all of Boost in our closure. # https://github.com/NixOS/nixpkgs/issues/45462 diff --git a/src/libcmd/meson.build b/src/libcmd/meson.build new file mode 100644 index 000000000..e033bb1cd --- /dev/null +++ b/src/libcmd/meson.build @@ -0,0 +1,58 @@ +libcmd_sources = files( + 'built-path.cc', + 'command-installable-value.cc', + 'command.cc', + 'common-eval-args.cc', + 'editor-for.cc', + 'installable-attr-path.cc', + 'installable-derived-path.cc', + 'installable-flake.cc', + 'installable-value.cc', + 'installables.cc', + 'legacy.cc', + 'markdown.cc', + 'repl.cc', + 'repl-interacter.cc', +) + +libcmd_headers = files( + 'built-path.hh', + 'command-installable-value.hh', + 'command.hh', + 'common-eval-args.hh', + 'editor-for.hh', + 'installable-attr-path.hh', + 'installable-derived-path.hh', + 'installable-flake.hh', + 'installable-value.hh', + 'installables.hh', + 'legacy.hh', + 'markdown.hh', + 'repl-interacter.hh', + 'repl.hh', +) + +libcmd = library( + 'nixcmd', + libcmd_sources, + dependencies : [ + liblixutil, + liblixstore, + liblixexpr, + liblixfetchers, + liblixmain, + boehm, + editline, + lowdown, + ], + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +install_headers(libcmd_headers, subdir : 'nix', preserve_path : true) + +liblixcmd = declare_dependency( + include_directories : '.', + link_with : libcmd, +) diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build new file mode 100644 index 000000000..96cdf3fc9 --- /dev/null +++ b/src/libexpr/meson.build @@ -0,0 +1,157 @@ +parser_tab = custom_target( + input : 'parser.y', + output : [ + 'parser-tab.cc', + 'parser-tab.hh', + ], + command : [ + 'bison', + '-v', + '-o', + '@OUTPUT0@', + '@INPUT@', + '-d', + ], + # NOTE(Qyriad): Meson doesn't support installing only part of a custom target, so we add + # an install script below which removes parser-tab.cc. + install : true, + install_dir : includedir / 'nix', +) + +lexer_tab = custom_target( + input : [ + 'lexer.l', + parser_tab, + ], + output : [ + 'lexer-tab.cc', + 'lexer-tab.hh', + ], + command : [ + 'flex', + '--outfile', + '@OUTPUT0@', + '--header-file=' + '@OUTPUT1@', + '@INPUT0@', + ], + # NOTE(Qyriad): Meson doesn't support installing only part of a custom target, so we add + # an install script below which removes lexer-tab.cc. + install : true, + install_dir : includedir / 'nix', +) + +# TODO(Qyriad): When the parser and lexer are rewritten this should be removed. +# NOTE(Qyriad): We do this this way instead of an inline bash or rm command +# due to subtleties in Meson. Check the comments in cleanup-install.bash for details. +meson.add_install_script( + bash, + meson.project_source_root() / 'meson/cleanup-install.bash', + '@0@'.format(includedir), +) + +imported_drv_to_derivation_gen = gen_header.process('imported-drv-to-derivation.nix') +fetchurl_gen = gen_header.process('fetchurl.nix') +derivation_gen = gen_header.process('primops/derivation.nix', preserve_path_from : meson.current_source_dir()) +call_flake_gen = gen_header.process('flake/call-flake.nix') + +libexpr_sources = files( + 'attr-path.cc', + 'attr-set.cc', + 'eval-cache.cc', + 'eval-error.cc', + 'eval-settings.cc', + 'eval.cc', + 'function-trace.cc', + 'get-drvs.cc', + 'json-to-value.cc', + 'nixexpr.cc', + 'paths.cc', + 'primops.cc', + 'print-ambiguous.cc', + 'print.cc', + 'search-path.cc', + 'value-to-json.cc', + 'value-to-xml.cc', + 'flake/config.cc', + 'flake/flake.cc', + 'flake/flakeref.cc', + 'flake/lockfile.cc', + 'primops/context.cc', + 'primops/fetchClosure.cc', + 'primops/fetchMercurial.cc', + 'primops/fetchTree.cc', + 'primops/fromTOML.cc', + 'value/context.cc', +) + +libexpr_headers = files( + 'attr-path.hh', + 'attr-set.hh', + 'eval-cache.hh', + 'eval-error.hh', + 'eval-inline.hh', + 'eval-settings.hh', + 'eval.hh', + 'flake/flake.hh', + 'flake/flakeref.hh', + 'flake/lockfile.hh', + 'function-trace.hh', + 'gc-small-vector.hh', + 'get-drvs.hh', + 'json-to-value.hh', + 'nixexpr.hh', + 'parser-state.hh', + 'pos-idx.hh', + 'pos-table.hh', + 'primops.hh', + 'print-ambiguous.hh', + 'print-options.hh', + 'print.hh', + 'repl-exit-status.hh', + 'search-path.hh', + 'symbol-table.hh', + 'value/context.hh', + 'value-to-json.hh', + 'value-to-xml.hh', + 'value.hh', +) + +libexpr = library( + 'nixexpr', + libexpr_sources, + parser_tab, + lexer_tab, + imported_drv_to_derivation_gen, + fetchurl_gen, + derivation_gen, + call_flake_gen, + dependencies : [ + liblixutil, + liblixstore, + liblixfetchers, + boehm, + boost, + ], + # for shared.hh + include_directories : '../libmain', + cpp_args : [ + # FIXME(Qyriad): can we please fix this. toml11 pls. + # Technically this only applies to fromTOML.cc, but, well + # https://github.com/mesonbuild/meson/issues/1367 + '-Wno-error=switch-enum', + ], + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +install_headers( + libexpr_headers, + subdir : 'nix', + preserve_path : true +) + +liblixexpr = declare_dependency( + include_directories : include_directories('.'), + link_with : libexpr, +) diff --git a/src/libfetchers/meson.build b/src/libfetchers/meson.build new file mode 100644 index 000000000..5eacfd5c4 --- /dev/null +++ b/src/libfetchers/meson.build @@ -0,0 +1,42 @@ +libfetchers_sources = files( + 'attrs.cc', + 'cache.cc', + 'fetch-settings.cc', + 'fetch-to-store.cc', + 'fetchers.cc', + 'git.cc', + 'github.cc', + 'indirect.cc', + 'mercurial.cc', + 'path.cc', + 'registry.cc', + 'tarball.cc', +) + +libfetchers_headers = files( + 'attrs.hh', + 'cache.hh', + 'fetch-settings.hh', + 'fetch-to-store.hh', + 'fetchers.hh', + 'registry.hh', +) + +libfetchers = library( + 'nixfetchers', + libfetchers_sources, + dependencies : [ + liblixstore, + liblixutil, + ], + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +install_headers(libfetchers_headers, subdir : 'nix', preserve_path : true) + +liblixfetchers = declare_dependency( + include_directories : include_directories('.'), + link_with : libfetchers, +) diff --git a/src/libmain/meson.build b/src/libmain/meson.build new file mode 100644 index 000000000..54326c305 --- /dev/null +++ b/src/libmain/meson.build @@ -0,0 +1,33 @@ +libmain_sources = files( + 'common-args.cc', + 'loggers.cc', + 'progress-bar.cc', + 'shared.cc', + 'stack.cc', +) + +libmain_headers = files( + 'common-args.hh', + 'loggers.hh', + 'progress-bar.hh', + 'shared.hh', +) + +libmain = library( + 'nixmain', + libmain_sources, + dependencies : [ + liblixutil, + liblixstore, + ], + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +install_headers(libmain_headers, subdir : 'nix', preserve_path : true) + +liblixmain = declare_dependency( + include_directories : include_directories('.'), + link_with : libmain, +) diff --git a/src/libstore/meson.build b/src/libstore/meson.build new file mode 100644 index 000000000..33e475f70 --- /dev/null +++ b/src/libstore/meson.build @@ -0,0 +1,188 @@ +schema_sql_gen = gen_header.process('schema.sql') +ca_specific_schema_gen = gen_header.process('ca-specific-schema.sql') + +libstore_sources = files( + 'binary-cache-store.cc', + 'build-result.cc', + 'common-protocol.cc', + 'content-address.cc', + 'crypto.cc', + 'daemon.cc', + 'derivations.cc', + 'derived-path-map.cc', + 'derived-path.cc', + 'downstream-placeholder.cc', + 'dummy-store.cc', + 'export-import.cc', + 'filetransfer.cc', + 'gc.cc', + 'globals.cc', + 'http-binary-cache-store.cc', + 'legacy-ssh-store.cc', + 'local-binary-cache-store.cc', + 'local-fs-store.cc', + 'local-store.cc', + 'lock.cc', + 'log-store.cc', + 'machines.cc', + 'make-content-addressed.cc', + 'misc.cc', + 'names.cc', + 'nar-accessor.cc', + 'nar-info-disk-cache.cc', + 'nar-info.cc', + 'optimise-store.cc', + 'outputs-spec.cc', + 'parsed-derivations.cc', + 'path-info.cc', + 'path-references.cc', + 'path-with-outputs.cc', + 'path.cc', + 'pathlocks.cc', + 'profiles.cc', + 'realisation.cc', + 'remote-fs-accessor.cc', + 'remote-store.cc', + 's3-binary-cache-store.cc', + 'serve-protocol.cc', + 'sqlite.cc', + 'ssh-store.cc', + 'ssh.cc', + 'store-api.cc', + 'uds-remote-store.cc', + 'worker-protocol.cc', + 'build/derivation-goal.cc', + 'build/drv-output-substitution-goal.cc', + 'build/entry-points.cc', + 'build/goal.cc', + 'build/hook-instance.cc', + 'build/local-derivation-goal.cc', + 'build/personality.cc', + 'build/substitution-goal.cc', + 'build/worker.cc', + 'builtins/buildenv.cc', + 'builtins/fetchurl.cc', + 'builtins/unpack-channel.cc', +) + + +libstore_headers = files( + 'binary-cache-store.hh', + 'build/derivation-goal.hh', + 'build/drv-output-substitution-goal.hh', + 'build/goal.hh', + 'build/hook-instance.hh', + 'build/local-derivation-goal.hh', + 'build/personality.hh', + 'build/substitution-goal.hh', + 'build/worker.hh', + 'build-result.hh', + 'builtins/buildenv.hh', + 'builtins.hh', + 'common-protocol-impl.hh', + 'common-protocol.hh', + 'content-address.hh', + 'crypto.hh', + 'daemon.hh', + 'derivations.hh', + 'derived-path-map.hh', + 'derived-path.hh', + 'downstream-placeholder.hh', + 'filetransfer.hh', + 'fs-accessor.hh', + 'gc-store.hh', + 'globals.hh', + 'indirect-root-store.hh', + 'length-prefixed-protocol-helper.hh', + 'local-fs-store.hh', + 'local-store.hh', + 'lock.hh', + 'log-store.hh', + 'machines.hh', + 'make-content-addressed.hh', + 'names.hh', + 'nar-accessor.hh', + 'nar-info-disk-cache.hh', + 'nar-info.hh', + 'outputs-spec.hh', + 'parsed-derivations.hh', + 'path-info.hh', + 'path-references.hh', + 'path-regex.hh', + 'path-with-outputs.hh', + 'path.hh', + 'pathlocks.hh', + 'profiles.hh', + 'realisation.hh', + 'remote-fs-accessor.hh', + 'remote-store-connection.hh', + 'remote-store.hh', + 's3-binary-cache-store.hh', + 's3.hh', + 'serve-protocol-impl.hh', + 'serve-protocol.hh', + 'sqlite.hh', + 'ssh-store-config.hh', + 'ssh.hh', + 'store-api.hh', + 'store-cast.hh', + 'uds-remote-store.hh', + 'worker-protocol-impl.hh', + 'worker-protocol.hh', +) + +# These variables (aside from LSOF) are created pseudo-dynamically, near the beginning of +# the top-level meson.build. Aside from prefix itself, each of these was +# made into an absolute path by joining it with prefix, unless it was already +# an absolute path (which is the default for store-dir, state-dir, and log-dir). +cpp_str_defines = { + 'LSOF': lsof.full_path(), + 'NIX_PREFIX': prefix, + 'NIX_STORE_DIR': store_dir, + 'NIX_DATA_DIR': datadir, + 'NIX_STATE_DIR': state_dir, + 'NIX_LOG_DIR': log_dir, + 'NIX_CONF_DIR': sysconfdir, + 'NIX_BIN_DIR': bindir, + 'NIX_MAN_DIR': mandir, +} + +cpp_args = [] + +foreach name, value : cpp_str_defines + cpp_args += [ + '-D' + name + '=' + '"' + value + '"' + ] +endforeach + +libstore = library( + 'nixstore', + schema_sql_gen, + ca_specific_schema_gen, + libstore_sources, + dependencies : [ + libarchive, + liblixutil, # Internal. + seccomp, + sqlite, + sodium, + seccomp, + curl, + openssl, + aws_sdk, + aws_s3, + aws_sdk_transfer, + ], + cpp_args : cpp_args, + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +install_headers(libstore_headers, subdir : 'nix', preserve_path : true) + +# Used by libfetchers. +liblixstore = declare_dependency( + include_directories : include_directories('.'), + link_with : libstore, +) diff --git a/src/libutil/meson.build b/src/libutil/meson.build new file mode 100644 index 000000000..084d7ed11 --- /dev/null +++ b/src/libutil/meson.build @@ -0,0 +1,112 @@ +libutil_sources = files( + 'archive.cc', + 'args.cc', + 'canon-path.cc', + 'cgroup.cc', + 'compression.cc', + 'compute-levels.cc', + 'config.cc', + 'english.cc', + 'error.cc', + 'exit.cc', + 'experimental-features.cc', + 'filesystem.cc', + 'git.cc', + 'hash.cc', + 'hilite.cc', + 'json-utils.cc', + 'logging.cc', + 'namespaces.cc', + 'position.cc', + 'references.cc', + 'serialise.cc', + 'signals.cc', + 'source-path.cc', + 'suggestions.cc', + 'tarfile.cc', + 'thread-pool.cc', + 'url.cc', + 'util.cc', + 'xml-writer.cc', +) + +libutil_headers = files( + 'abstract-setting-to-json.hh', + 'ansicolor.hh', + 'archive.hh', + 'args.hh', + 'box_ptr.hh', + 'callback.hh', + 'canon-path.hh', + 'cgroup.hh', + 'chunked-vector.hh', + 'closure.hh', + 'comparator.hh', + 'compression.hh', + 'compute-levels.hh', + 'config-impl.hh', + 'config.hh', + 'english.hh', + 'error.hh', + 'exit.hh', + 'experimental-features.hh', + 'finally.hh', + 'fmt.hh', + 'git.hh', + 'hash.hh', + 'hilite.hh', + 'input-accessor.hh', + 'json-impls.hh', + 'json-utils.hh', + 'logging.hh', + 'lru-cache.hh', + 'monitor-fd.hh', + 'namespaces.hh', + 'pool.hh', + 'position.hh', + 'ref.hh', + 'references.hh', + 'regex-combinators.hh', + 'repair-flag.hh', + 'serialise.hh', + 'signals.hh', + 'source-path.hh', + 'split.hh', + 'suggestions.hh', + 'sync.hh', + 'tarfile.hh', + 'thread-pool.hh', + 'topo-sort.hh', + 'types.hh', + 'url-parts.hh', + 'url.hh', + 'util.hh', + 'variant-wrapper.hh', + 'xml-writer.hh', +) + +libutil = library( + 'nixutil', + libutil_sources, + dependencies : [ + aws_sdk, + aws_s3, + boehm, + boost, + cpuid, + seccomp, + libarchive, + brotli, + openssl, + ], + implicit_include_directories : true, + install : true, +) + +install_headers(libutil_headers, subdir : 'nix', preserve_path : true) + +# Used by libstore and libfetchers. +liblixutil = declare_dependency( + include_directories : include_directories('.'), + link_with : libutil +) diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 000000000..f97b66252 --- /dev/null +++ b/src/meson.build @@ -0,0 +1,65 @@ +# Subcomponents: these link into artifacts themselves, and have interdependencies. + +subdir('libutil') +# Load-bearing order. libstore depends on libutil. +subdir('libstore') +# libfetchers depends on libstore +subdir('libfetchers') +# libexpr depends on all of the above +subdir('libexpr') +# libmain depends on libutil and libstore +subdir('libmain') +# libcmd depends on everything +subdir('libcmd') + + +# The rest of the subdirectories aren't separate components, +# just source files in another directory, so we process them here. + +build_remote_sources = files( + 'build-remote/build-remote.cc', +) +nix_build_sources = files( + 'nix-build/nix-build.cc', +) +nix_channel_sources = files( + 'nix-channel/nix-channel.cc', +) +unpack_channel_gen = gen_header.process('nix-channel/unpack-channel.nix') +nix_collect_garbage_sources = files( + 'nix-collect-garbage/nix-collect-garbage.cc', +) +nix_copy_closure_sources = files( + 'nix-copy-closure/nix-copy-closure.cc', +) +nix_env_buildenv_gen = gen_header.process('nix-env/buildenv.nix') +nix_env_sources = files( + 'nix-env/nix-env.cc', + 'nix-env/user-env.cc', +) +nix_instantiate_sources = files( + 'nix-instantiate/nix-instantiate.cc', +) +nix_store_sources = files( + 'nix-store/dotgraph.cc', + 'nix-store/graphml.cc', + 'nix-store/nix-store.cc', +) + +# Hurray for Meson list flattening! +nix2_commands_sources = [ + build_remote_sources, + nix_build_sources, + nix_channel_sources, + unpack_channel_gen, + nix_collect_garbage_sources, + nix_copy_closure_sources, + nix_env_buildenv_gen, + nix_env_sources, + nix_instantiate_sources, + nix_store_sources, +] + +# Finally, the nix command itself, which all of the other commands are implmented in terms of +# as a multicall binary. +subdir('nix') diff --git a/src/nix/meson.build b/src/nix/meson.build new file mode 100644 index 000000000..2585ba3c3 --- /dev/null +++ b/src/nix/meson.build @@ -0,0 +1,119 @@ +generate_manpage_gen = gen_header.process(meson.project_source_root() / 'doc/manual/generate-manpage.nix') + +utils_gen = gen_header.process(meson.project_source_root() / 'doc/manual/utils.nix') + +get_env_gen = gen_header.process('get-env.sh') + +# src/nix/profile.cc includes src/nix/profile.md, which includes "doc/files/profiles.md.gen.hh". +# Unfortunately, https://github.com/mesonbuild/meson/issues/2320. +# "docs/files" isn't a directory hierarchy that already exists somewhere in this source tree, +# and Meson refuses to create targets with specific directory paths. +# So run_command() it is. +# NOTE(Qyriad): This corresponds to the previous buildsystem's `src/nix/doc/files/%.md` rule, +# which as far as I can tell was only used for this file. +run_command( + installcmd, + '-D', + meson.project_source_root() / 'doc/manual/src/command-ref/files/profiles.md', + meson.current_build_dir() / 'doc/files/profiles.md', + check : true, +) +profiles_md_gen = gen_header.process( + meson.current_build_dir() / 'doc/files/profiles.md', + preserve_path_from : meson.current_build_dir(), +) + +nix_sources = files( + 'add-to-store.cc', + 'app.cc', + 'build.cc', + 'bundle.cc', + 'cat.cc', + 'copy.cc', + 'daemon.cc', + 'derivation-add.cc', + 'derivation-show.cc', + 'derivation.cc', + 'develop.cc', + 'diff-closures.cc', + 'doctor.cc', + 'dump-path.cc', + 'edit.cc', + 'eval.cc', + 'flake.cc', + 'fmt.cc', + 'hash.cc', + 'log.cc', + 'ls.cc', + 'main.cc', + 'make-content-addressed.cc', + 'nar.cc', + 'optimise-store.cc', + 'path-from-hash-part.cc', + 'path-info.cc', + 'ping-store.cc', + 'prefetch.cc', + 'profile.cc', + 'realisation.cc', + 'registry.cc', + 'repl.cc', + 'run.cc', + 'search.cc', + 'show-config.cc', + 'sigs.cc', + 'store-copy-log.cc', + 'store-delete.cc', + 'store-gc.cc', + 'store-repair.cc', + 'store.cc', + 'upgrade-nix.cc', + 'verify.cc', + 'why-depends.cc', +) + +nix = executable( + 'nix', + nix_sources, + generate_manpage_gen, + utils_gen, + get_env_gen, + profiles_md_gen, + nix2_commands_sources, + dependencies : [ + liblixcmd, + liblixutil, + liblixstore, + liblixexpr, + liblixfetchers, + liblixmain, + boehm, + ], + install : true, + # FIXME(Qyriad): is this right? + install_rpath : libdir, +) + +nix_symlinks = [ + 'nix-build', + 'nix-channel', + 'nix-collect-garbage', + 'nix-copy-closure', + 'nix-daemon', + 'nix-env', + 'nix-hash', + 'nix-instantiate', + 'nix-prefetch-url', + 'nix-shell', + 'nix-store', +] + +foreach linkname : nix_symlinks + install_symlink( + linkname, + # TODO(Qyriad): should these continue to be relative symlinks? + pointing_to : 'nix', + install_dir : bindir, + # The 'runtime' tag is what executables default to, which we want to emulate here. + install_tag : 'runtime' + ) +endforeach