diff --git a/meson.build b/meson.build new file mode 100644 index 000000000..d28e78739 --- /dev/null +++ b/meson.build @@ -0,0 +1,222 @@ +project('lix', 'cpp', + version : run_command('bash', '-c', 'echo -n $(cat ./.version)$VERSION_SUFFIX', check : true).stdout().strip(), + default_options : [ + 'cpp_std=c++20', + 'warning_level=1', + 'debug=true', + 'optimization=2', + ], +) + +cxx = meson.get_compiler('cpp') + +host_system = host_machine.cpu_family() + '-' + host_machine.system() +message('canonical Nix system name:', host_system) + +all_sources = { } +all_deps = { } + +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 + +sqlite = dependency('sqlite3', 'sqlite', version : '>=3.6.19', required : true) +deps += sqlite + +sodium = dependency('sodium', 'libsodium', 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 + +# +# Build-time tools +# +bash = find_program('bash') +lsof = find_program('lsof') + +# 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 +# + +# FIXME(Qyriad): at least do this in the build directory +run_command('ln', '-s', 'bla', 'tmp_link', check : true) +can_link_symlink = run_command('ln', 'tmp_link', 'tmp_link2', check : false).returncode() == 0 +run_command('rm', '-f', 'tmp_link', 'tmp_link2', check : true) +message('possible to create a link to a symlink:', can_link_symlink) +configdata += { 'CAN_LINK_SYMLINK': can_link_symlink.to_int() } + +check_headers = [ + # I can't use dictionaries here as they can only contain identifier-strings. + ['aws/s3/S3Client.h', aws_s3] +] + +foreach headerspec : check_headers + key = headerspec[0] + value = headerspec[1] + define_name = 'HAVE_' + key.underscorify().to_upper() + define_value = cxx.check_header(key, dependencies : value).to_int() + configdata += { define_name: define_value } +endforeach + +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 + +has_pubsetbuf = cxx.compiles(''' + #include + using namespace std; + static char buf[1024]; + decltype(cerr.rdbuf()->pubsetbuf(buf, sizeof(buf))) _; +''') +message('have function "\x1b[1mstd::basic_streambuf::pubsetbuf\x1b[0m" :', has_pubsetbuf) +configdata += { + 'HAVE_PUBSETBUF': has_pubsetbuf.to_int(), +} + +configdata += { + 'ENABLE_S3': aws_s3.found().to_int(), +} + +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', +) + +add_project_arguments( + # TODO(Qyriad): Yes this is how the autoconf+Make system did it. + # I would love to remove this. + '-include', 'config.h', + # TODO(Qyriad): would love to remove these + '-Wno-deprecated-declarations', + '-Wno-unused-parameter', + '-Wno-missing-field-initializers', + '-Wno-deprecated-copy', + '-pthread', + #'-fPIC', + language : 'cpp', +) + +# FIXME(Qyriad): only if not Darwin, Solaris, or FreeBSD +# (...so only if Linux?) +add_project_link_arguments( + '-Wl,--no-copy-dt-needed-entries', + language : 'cpp', +) + +subdir('src') diff --git a/meson.options b/meson.options new file mode 100644 index 000000000..393e59733 --- /dev/null +++ b/meson.options @@ -0,0 +1,24 @@ +# 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('store-dir', type : 'string', value : '/nix/store', + description : 'path of the Nix store', +) + +option('sandbox-shell', type : 'string', + description : 'path to a statically-linked shell to use as /bin/sh in sandboxes (usually busybox)', +) diff --git a/package.nix b/package.nix index 8d33759b7..ca14ae049 100644 --- a/package.nix +++ b/package.nix @@ -9,6 +9,7 @@ nlohmann_json, bison, changelog-d, + cmake, boost, brotli, bzip2, @@ -24,10 +25,13 @@ libcpuid, libseccomp, libsodium, + lsof, lowdown, mdbook, mdbook-linkcheck, mercurial, + meson, + ninja, openssl, pkg-config, rapidcheck, @@ -125,6 +129,12 @@ in stdenv.mkDerivation (finalAttrs: { ++ lib.optionals (!finalAttrs.dontBuild) [ "dev" "doc" ]; dontBuild = false; + # FIXME(Qyriad): see if this is still needed once the migration to Meson is completed. + dontUseCmakeConfigure = true; + dontUseMesonConfigure = true; + dontUseNinjaBuild = true; + dontUseNinjaCheck = true; + dontUseNinjaInstall = true; nativeBuildInputs = [ bison @@ -141,6 +151,10 @@ in stdenv.mkDerivation (finalAttrs: { git mercurial jq + cmake + meson + ninja + lsof ] ++ lib.optional stdenv.hostPlatform.isLinux util-linuxMinimal ++ lib.optional (!officialRelease && buildUnreleasedNotes) changelog-d ++ lib.optional internalApiDocs doxygen @@ -177,6 +191,11 @@ in stdenv.mkDerivation (finalAttrs: { boost ]; + # Needed for Meson to find Boost. + # https://github.com/NixOS/nixpkgs/issues/86131. + env.BOOST_INCLUDEDIR = "${lib.getDev boost}/include"; + env.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..26430826c --- /dev/null +++ b/src/libcmd/meson.build @@ -0,0 +1,36 @@ +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 = library( + 'nixcmd', + libcmd_sources, + dependencies : [ + liblixutil, + liblixstore, + liblixexpr, + liblixfetchers, + liblixmain, + boehm, + editline, + lowdown, + ], +) + +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..30ee66b38 --- /dev/null +++ b/src/libexpr/meson.build @@ -0,0 +1,100 @@ +bison = find_program('bison') +flex = find_program('flex') + +parser_tab = custom_target( + input : 'parser.y', + output : [ + 'parser-tab.cc', + 'parser-tab.hh', + ], + command : [ + 'bison', + '-v', + '-o', + '@OUTPUT0@', + '@INPUT@', + '-d', + ], +) + +lexer_tab = custom_target( + input : [ + 'lexer.l', + parser_tab, + ], + output : [ + 'lexer-tab.cc', + 'lexer-tab.hh', + ], + command : [ + 'flex', + '--outfile', + '@OUTPUT0@', + '--header-file=' + '@OUTPUT1@', + '@INPUT0@', + ], +) + +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', +) + +all_sources += { + 'libexpr': libexpr_sources +} + +libexpr = library( + 'nixexpr', + libexpr_sources, + parser_tab, + lexer_tab, + dependencies : [ + liblixutil, + liblixstore, + liblixfetchers, + boehm, + boost, + ], + include_directories : '../libmain', +) + +liblixexpr = declare_dependency( + include_directories : include_directories('.'), + link_with : libexpr, +) + +liblixexpr = declare_dependency( + include_directories : include_directories('.'), + link_with : libexpr, +) + +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..3f82ef61f --- /dev/null +++ b/src/libfetchers/meson.build @@ -0,0 +1,28 @@ +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 = library( + 'nixfetchers', + libfetchers_sources, + dependencies : [ + liblixstore, + liblixutil, + ], +) + +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..7c354ea48 --- /dev/null +++ b/src/libmain/meson.build @@ -0,0 +1,21 @@ +libmain_sources = files( + 'common-args.cc', + 'loggers.cc', + 'progress-bar.cc', + 'shared.cc', + 'stack.cc', +) + +libmain = library( + 'nixmain', + libmain_sources, + dependencies : [ + liblixutil, + liblixstore, + ], +) + +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..d5ef3815a --- /dev/null +++ b/src/libstore/meson.build @@ -0,0 +1,123 @@ +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', +) + +all_sources += { + 'libstore': libstore_sources, +} + +prefix = get_option('prefix') + +cpp_str_defines = { + 'LSOF': lsof.full_path(), + 'NIX_PREFIX': get_option('prefix'), + 'NIX_STORE_DIR': get_option('store-dir'), + 'NIX_DATA_DIR': get_option('prefix') / 'share', # FIXME: make separately-configurable + #'NIX_STATE_DIR': get_option('prefix') / 'nix', # FIXME: same + 'NIX_LOG_DIR': get_option('prefix') / 'log' / 'nix', # FIXME: same + 'NIX_CONF_DIR': get_option('prefix') / 'etc', # FIXME: same + 'NIX_BIN_DIR': get_option('prefix') / 'bin', # FIXME: same + 'NIX_MAN_DIR': get_option('prefix') / 'share' / 'man', # FIXME: same +} + +cpp_str_defines += { + 'NIX_STATE_DIR': '/nix/var/nix', +} + +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, +) + +# 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..9a4df2447 --- /dev/null +++ b/src/libutil/meson.build @@ -0,0 +1,58 @@ +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', +) + +all_sources += { + 'libutil': libutil_sources, +} + +libutil = library( + 'nixutil', + libutil_sources, + dependencies : [ + aws_sdk, + aws_s3, + boehm, + boost, + cpuid, + seccomp, + libarchive, + brotli, + openssl, + ], + implicit_include_directories : 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-env/meson.build b/src/nix-env/meson.build new file mode 100644 index 000000000..f9676a8ca --- /dev/null +++ b/src/nix-env/meson.build @@ -0,0 +1,4 @@ +nix_env_sources = files( + 'nix-env.cc', + 'user-env.cc' +) diff --git a/src/nix/meson.build b/src/nix/meson.build new file mode 100644 index 000000000..f1ddeb3db --- /dev/null +++ b/src/nix/meson.build @@ -0,0 +1,68 @@ +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') + +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, + nix2_commands_sources, + dependencies : [ + liblixcmd, + liblixutil, + liblixstore, + liblixexpr, + liblixfetchers, + liblixmain, + boehm, + ], +)