aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Valentin Lorentz2026-03-14 19:46:40 -0500
committerGravatar Doug Freed2026-03-15 12:53:21 -0500
commitb46433ff940100ac1990798a14cd5b58bfb31062 (patch)
tree4da604b7ee3778abbe5463d7a983b57a0b0cd5f9
parentmodules: drop unnecessary link flag (diff)
downloadsolanum-dwfreed/meson-rebased.tar.gz
solanum-dwfreed/meson-rebased.tar.bz2
solanum-dwfreed/meson-rebased.zip
build: add Meson buildsystem dwfreed/meson-rebased
-rw-r--r--.github/workflows/ci.yml51
-rw-r--r--README.md24
-rw-r--r--authd/meson.build21
-rw-r--r--bandb/meson.build21
-rw-r--r--doc/meson.build6
-rw-r--r--extensions/meson.build91
-rw-r--r--help/meson.build28
-rw-r--r--include/meson.build26
-rw-r--r--ircd/meson.build94
-rw-r--r--librb/include/meson.build10
-rw-r--r--librb/librb-config.h.in76
-rw-r--r--librb/meson.build125
-rw-r--r--meson.build285
-rw-r--r--meson_options.txt49
-rw-r--r--modules/meson.build114
-rw-r--r--ssld/meson.build8
-rw-r--r--tests/meson.build62
-rw-r--r--tools/meson.build15
18 files changed, 1095 insertions, 11 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 28801b73..004965cb 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -87,3 +87,54 @@ jobs:
run: make check
- name: make install
run: make install
+
+ linux-meson:
+ name: Linux (meson)
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ # can't check Debian 11 Bullseye because Ubuntu 22.04 Jammy's Meson is too old
+ # Debian 12 Bookworm
+ - os: ubuntu-24.04
+ compiler: gcc-12
+ - os: ubuntu-24.04
+ compiler: clang-14
+ # Debian 13 Trixie
+ - os: ubuntu-24.04
+ compiler: gcc-14
+ - os: ubuntu-24.04
+ compiler: clang-19
+ # Ubuntu 22.04 Jammy's Meson is too old
+ # Ubuntu 24.04 Noble
+ - os: ubuntu-24.04
+ compiler: gcc-13
+ - os: ubuntu-24.04
+ compiler: clang-18
+ env:
+ CC: ${{ matrix.compiler }}
+ RUNNING_IN_CI: yes
+
+ steps:
+ - name: Install dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends \
+ ${CC} \
+ meson \
+ ninja-build \
+ libltdl-dev \
+ libsqlite3-dev \
+ libhyperscan-dev \
+ # EOF
+ - uses: actions/checkout@main
+ with:
+ persist-credentials: false
+ submodules: recursive
+ - name: meson setup
+ run: meson setup --buildtype debugoptimized --warnlevel 2 build/
+ - name: meson compile
+ run: meson compile -C build/
+ - name: meson test
+ run: meson test -C build/
diff --git a/README.md b/README.md
index 79669319..425f269e 100644
--- a/README.md
+++ b/README.md
@@ -37,24 +37,26 @@ These are known issues and workarounds for various platforms.
# building
```bash
-sudo apt install build-essential pkg-config automake libtool libsqlite3-dev # or equivalent for your distribution
-./autogen.sh
-./configure --prefix=/path/to/installation
-make
-make check # run tests
-make install
+sudo apt install build-essential pkg-config meson ninja-build libsqlite3-dev flex bison # or equivalent for your distribution
+meson setup build --optimization 2 --prefix=/path/to/installation
+meson compile -C build/
+meson test -C build/
+meson install -C build/
```
-See `./configure --help` for build options.
+See `meson configure build/` for build options.
# feature specific requirements
* For SSL/TLS client and server connections, one of:
- * OpenSSL 1.1.0 or newer (`--enable-openssl`)
- * LibreSSL (`--enable-openssl`)
- * mbedTLS (`--enable-mbedtls`)
- * GnuTLS (`--enable-gnutls`)
+ * OpenSSL 1.1.0 or newer (`-Dopenssl=enabled`)
+ * LibreSSL (`-Dopenssl=enabled`)
+ * mbedTLS (`-Dmbedtls=enabled`)
+ * GnuTLS (`-Dgnutls=enabled`)
+
+ If multiple TLS libraries are available, the build system will prefer mbedTLS > OpenSSL > GnuTLS.
+ Use `=enabled` instead of `=auto` to force a specific library.
* For certificate-based oper CHALLENGE, OpenSSL 1.1.0 or newer.
(Using CHALLENGE is not recommended for new deployments, so if you want to use a different TLS library,
diff --git a/authd/meson.build b/authd/meson.build
new file mode 100644
index 00000000..1cb75820
--- /dev/null
+++ b/authd/meson.build
@@ -0,0 +1,21 @@
+authd_sources = files(
+ 'authd.c',
+ 'dns.c',
+ 'notice.c',
+ 'provider.c',
+ 'res.c',
+ 'reslib.c',
+ 'providers/dnsbl.c',
+ 'providers/ident.c',
+ 'providers/opm.c',
+ 'providers/rdns.c',
+)
+
+authd = executable('authd',
+ authd_sources,
+ dependencies: [librb_dep],
+ include_directories: include_directories('../include'),
+ install: true,
+ install_dir: pkglibexecdir,
+ install_rpath: rpath,
+)
diff --git a/bandb/meson.build b/bandb/meson.build
new file mode 100644
index 00000000..7ffc6ff5
--- /dev/null
+++ b/bandb/meson.build
@@ -0,0 +1,21 @@
+bandb_common_sources = files(
+ 'rsdb_sqlite3.c',
+ 'rsdb_snprintf.c',
+)
+
+bandb = executable('bandb',
+ ['bandb.c'] + bandb_common_sources,
+ dependencies: [librb_dep, sqlite3_dep],
+ include_directories: include_directories('../include'),
+ install: true,
+ install_dir: pkglibexecdir,
+ install_rpath: rpath,
+)
+
+bantool = executable('solanum-bantool',
+ ['bantool.c'] + bandb_common_sources,
+ dependencies: [librb_dep, sqlite3_dep],
+ include_directories: include_directories('../include'),
+ install: true,
+ install_rpath: rpath,
+)
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 00000000..11b485eb
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,6 @@
+install_data(
+ 'ircd.conf.example',
+ 'reference.conf',
+ 'ircd.motd',
+ install_dir: confdir
+)
diff --git a/extensions/meson.build b/extensions/meson.build
new file mode 100644
index 00000000..2b5304fb
--- /dev/null
+++ b/extensions/meson.build
@@ -0,0 +1,91 @@
+extension_modules = [
+ 'cap_oper',
+ 'cap_realhost',
+ 'chantype_dummy',
+ 'chm_adminonly',
+ 'chm_operonly',
+ 'chm_insecure',
+ 'chm_nonotice',
+ 'chm_operpeace',
+ 'chm_regmsg',
+ 'chm_sslonly',
+ 'createauthonly',
+ 'createoperonly',
+ 'drain',
+ 'extb_account',
+ 'extb_canjoin',
+ 'extb_channel',
+ 'extb_guest',
+ 'extb_hostmask',
+ 'extb_oper',
+ 'extb_server',
+ 'extb_ssl',
+ 'extb_realname',
+ 'extb_usermode',
+ 'extb_extgecos',
+ 'extb_combi',
+ 'force_user_invis',
+ 'helpops',
+ 'hide_uncommon_channels',
+ 'hurt',
+ 'identify_msg',
+ 'invex_regonly',
+ 'invite_notify',
+ 'ip_cloaking',
+ 'ip_cloaking_old',
+ 'ip_cloaking_3.0',
+ 'ip_cloaking_4.0',
+ 'm_adminwall',
+ 'm_echotags',
+ 'm_extendchans',
+ 'm_findforwards',
+ 'm_identify',
+ 'm_locops',
+ 'm_mkpasswd',
+ 'm_ojoin',
+ 'm_okick',
+ 'm_omode',
+ 'm_opme',
+ 'm_remove',
+ 'm_sendbans',
+ 'm_shedding',
+ 'm_webirc',
+ 'no_kill_services',
+ 'no_locops',
+ 'no_oper_invis',
+ 'override',
+ 'override_kick_immunity',
+ 'restrict-unauthenticated',
+ 'sasl_usercloak',
+ 'sno_channelcreate',
+ 'sno_farconnect',
+ 'sno_globalnickchange',
+ 'sno_globaloper',
+ 'tag_message_id',
+ 'tag_typing',
+ 'umode_hide_idle_time',
+ 'umode_noctcp',
+ 'example_module',
+]
+
+foreach mod : extension_modules
+ shared_module(mod,
+ mod + '.c',
+ name_prefix: '',
+ name_suffix: 'so',
+ dependencies: [libircd_dep, librb_dep, global_include_dep],
+ install: true,
+ install_dir: moduledir / 'extensions'
+ )
+endforeach
+
+if have_hyperscan
+ shared_module('filter',
+ 'filter.c',
+ name_prefix: '',
+ name_suffix: 'so',
+ dependencies: [libircd_dep, librb_dep, global_include_dep, hyperscan_dep],
+ install: true,
+ install_dir: moduledir / 'extensions'
+ )
+endif
diff --git a/help/meson.build b/help/meson.build
new file mode 100644
index 00000000..c34930ed
--- /dev/null
+++ b/help/meson.build
@@ -0,0 +1,28 @@
+# Generate help index files
+meson.add_install_script(files('make_index.SH'), meson.current_source_dir(), helpdir)
+
+# Symlinks from users -> opers for shared help topics
+user_symlinks = [
+ 'topic', 'accept', 'cmode', 'admin', 'names', 'links', 'away', 'whowas',
+ 'version', 'kick', 'who', 'invite', 'quit', 'join', 'list', 'nick',
+ 'oper', 'part', 'time', 'credits', 'motd', 'userhost', 'users', 'whois',
+ 'ison', 'lusers', 'user', 'help', 'pass', 'error', 'challenge', 'knock',
+ 'ping', 'pong', 'map', 'trace', 'chantrace', 'extban', 'monitor', 'batch'
+]
+
+install_subdir('users',
+ install_dir: helpdir,
+ exclude_files: ['index.tmp'] + user_symlinks
+)
+
+install_subdir('opers',
+ install_dir: helpdir,
+ exclude_files: ['index.tmp']
+)
+
+foreach link : user_symlinks
+ install_symlink(link,
+ pointing_to: '../opers/' + link,
+ install_dir: helpdir / 'users'
+ )
+endforeach
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 00000000..bd841645
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,26 @@
+setup_h = configure_file(
+ output: 'setup.h',
+ configuration: conf_data,
+ install: false
+)
+
+serno_h = vcs_tag(
+ command: ['git', 'rev-list', '-1', '--no-commit-header', '--date=format:%Y%m%d', '--format=%cd-%h', 'HEAD'],
+ input: 'serno.h.in',
+ output: 'serno.h',
+ replace_string: '@SERNO@',
+ fallback: 'unknown',
+)
+
+datecode_h = vcs_tag(
+ command: ['git', 'rev-list', '-1', '--no-commit-header', '--format=%ct', 'HEAD'],
+ input: 'datecode.h.in',
+ output: 'datecode.h',
+ replace_string: '@DATECODE@',
+ fallback: '0',
+)
+
+global_include_dep = declare_dependency(
+ sources: [setup_h, serno_h, datecode_h],
+ include_directories: include_directories('.'),
+)
diff --git a/ircd/meson.build b/ircd/meson.build
new file mode 100644
index 00000000..fd92ea43
--- /dev/null
+++ b/ircd/meson.build
@@ -0,0 +1,94 @@
+ircd_parser = custom_target('ircd_parser',
+ input: 'ircd_parser.y',
+ output: ['ircd_parser.c', 'ircd_parser.h'],
+ command: [bison, '-d', '@INPUT@', '--output=@OUTPUT0@', '--defines=@OUTPUT1@']
+)
+
+ircd_lexer = custom_target('ircd_lexer',
+ input: 'ircd_lexer.l',
+ output: 'ircd_lexer.c',
+ command: [flex, '-o', '@OUTPUT@', '@INPUT@']
+)
+
+credits_result = run_command('sed', 's/^$/ /;s/.*/ "&",/', meson.project_source_root() / 'CREDITS', check: true)
+ircd_version_conf = configuration_data()
+ircd_version_conf.set('GENERATION', '0')
+ircd_version_conf.set('CREATION', '__DATE__ at __TIME__')
+ircd_version_conf.set('CREDITS', credits_result.stdout())
+ircd_version_conf.set('PACKAGE', meson.project_name())
+ircd_version = configure_file(
+ input: 'version.c.in',
+ output: 'version.c',
+ configuration: ircd_version_conf
+)
+
+libircd_sources = files(
+ 'authproc.c',
+ 'bandbi.c',
+ 'batch.c',
+ 'cache.c',
+ 'capability.c',
+ 'channel.c',
+ 'chmode.c',
+ 'class.c',
+ 'client.c',
+ 'client_tags.c',
+ 'dns.c',
+ 'extban.c',
+ 'getopt.c',
+ 'hash.c',
+ 'hook.c',
+ 'hostmask.c',
+ 'ircd.c',
+ 'ircd_signal.c',
+ 'listener.c',
+ 'logger.c',
+ 'match.c',
+ 'modules.c',
+ 'monitor.c',
+ 'msgbuf.c',
+ 'newconf.c',
+ 'operhash.c',
+ 'packet.c',
+ 'parse.c',
+ 'privilege.c',
+ 'ratelimit.c',
+ 'reject.c',
+ 'restart.c',
+ 's_conf.c',
+ 's_newconf.c',
+ 's_serv.c',
+ 's_user.c',
+ 'scache.c',
+ 'send.c',
+ 'snomask.c',
+ 'sslproc.c',
+ 'substitution.c',
+ 'supported.c',
+ 'tgchange.c',
+ 'whowas.c',
+)
+
+libircd_inc = include_directories('../include')
+
+libircd = shared_library('ircd',
+ [libircd_sources, ircd_parser, ircd_lexer, ircd_version, serno_h],
+ dependencies: [librb_dep, ltdl_dep],
+ include_directories: libircd_inc,
+ install: true,
+ install_rpath: rpath,
+)
+
+libircd_dep = declare_dependency(
+ link_with: libircd,
+ include_directories: libircd_inc,
+ dependencies: [librb_dep, ltdl_dep]
+)
+
+solanum = executable('solanum',
+ 'main.c',
+ dependencies: [libircd_dep],
+ export_dynamic: true,
+ install: true,
+ install_rpath: rpath,
+)
diff --git a/librb/include/meson.build b/librb/include/meson.build
new file mode 100644
index 00000000..65e1d869
--- /dev/null
+++ b/librb/include/meson.build
@@ -0,0 +1,10 @@
+# Create a copy of serno.h in librb's include directory for version.c
+librb_include_dir = meson.current_build_dir() / 'include'
+
+# replace with fs.copyfile if we bump the minimal Meson version to 1.64
+librb_serno_h = custom_target('librb_serno.h',
+ input: serno_h,
+ output: 'serno_librb.h',
+ command: ['sh', '-c', 'cp $0 $1', '@INPUT@', '@OUTPUT@'],
+ depends: serno_h
+)
diff --git a/librb/librb-config.h.in b/librb/librb-config.h.in
new file mode 100644
index 00000000..645645dc
--- /dev/null
+++ b/librb/librb-config.h.in
@@ -0,0 +1,76 @@
+/*
+ * librb-config.h: librb config file
+ * Generated from librb-config.h.in by meson
+ */
+
+#ifndef __LIBRB_CONFIG_H
+#define __LIBRB_CONFIG_H
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#mesondefine HAVE_SYS_POLL_H
+#mesondefine HAVE_SYS_EPOLL_H
+#mesondefine HAVE_SYS_DEVPOLL_H
+#mesondefine HAVE_SYS_EVENT_H
+#mesondefine HAVE_PORT_H
+#mesondefine HAVE_SYS_SIGNALFD_H
+#mesondefine HAVE_SYS_TIMERFD_H
+#mesondefine HAVE_GETEXECNAME
+#mesondefine HAVE_STRLCPY
+#mesondefine HAVE_STRLCAT
+#mesondefine HAVE_STRCASESTR
+#mesondefine HAVE_SIGNALFD
+#mesondefine HAVE_KEVENT
+#mesondefine HAVE_PORT_CREATE
+#mesondefine HAVE_EPOLL_CTL
+#mesondefine HAVE_ARC4RANDOM
+#mesondefine HAVE_TIMERFD_CREATE
+#mesondefine HAVE_DLINFO
+#mesondefine HAVE_NANOSLEEP
+#mesondefine HAVE_TIMER_CREATE
+#mesondefine HAVE_DEVPOLL
+#mesondefine SOCKADDR_IN_HAS_LEN
+
+#mesondefine HAVE_OPENSSL
+#mesondefine HAVE_MBEDTLS
+#mesondefine HAVE_GNUTLS
+
+#mesondefine HAVE_CRYPT_H
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+typedef socklen_t rb_socklen_t;
+
+/* Define RB_SOCKADDR_HAS_SA_LEN if sockaddr has sa_len member */
+#ifdef SOCKADDR_IN_HAS_LEN
+#define RB_SOCKADDR_HAS_SA_LEN 1
+#endif
+
+/* Indirect definition for consistency with librb/acinclude.m4, but we could make Meson define
+ * USE_TIMERFD_CREATE directly */
+#ifdef HAVE_SYS_TIMERFD_H
+#ifdef HAVE_TIMERFD_CREATE
+#define USE_TIMERFD_CREATE
+#endif
+#endif
+
+/* Use system sockaddr_storage */
+#define rb_sockaddr_storage sockaddr_storage
+
+#endif /* __LIBRB_CONFIG_H */
diff --git a/librb/meson.build b/librb/meson.build
new file mode 100644
index 00000000..f6bdee9d
--- /dev/null
+++ b/librb/meson.build
@@ -0,0 +1,125 @@
+fs = import('fs')
+dl_dep = cc.find_library('dl', required: false)
+
+librb_sources = files(
+ 'src/unix.c',
+ 'src/crypt.c',
+ 'src/balloc.c',
+ 'src/commio.c',
+ 'src/mbedtls.c',
+ 'src/openssl.c',
+ 'src/gnutls.c',
+ 'src/nossl.c',
+ 'src/event.c',
+ 'src/rb_lib.c',
+ 'src/rb_memory.c',
+ 'src/linebuf.c',
+ 'src/tools.c',
+ 'src/helper.c',
+ 'src/devpoll.c',
+ 'src/epoll.c',
+ 'src/poll.c',
+ 'src/ports.c',
+ 'src/sigio.c',
+ 'src/kqueue.c',
+ 'src/rawbuf.c',
+ 'src/patricia.c',
+ 'src/dictionary.c',
+ 'src/radixtree.c',
+ 'src/arc4random.c',
+)
+
+librb_credits_result = run_command('sed', 's/^$/ /;s/.*/ "&",/', meson.current_source_dir() / 'CREDITS', check: true)
+librb_version_conf = configuration_data()
+librb_version_conf.set('GENERATION', '0')
+librb_version_conf.set('CREDITS', librb_credits_result.stdout())
+librb_version_c = configure_file(
+ input: 'src/version.c.in',
+ output: 'version.c',
+ configuration: librb_version_conf
+)
+
+librb_conf_data = configuration_data()
+
+rt_dep = cc.find_library('rt', required: false)
+
+librb_checks = {
+ 'HAVE_CRYPT_H': cc.has_header('crypt.h'),
+ 'HAVE_SYS_POLL_H': cc.has_header('sys/poll.h'),
+ 'HAVE_SYS_EPOLL_H': cc.has_header('sys/epoll.h'),
+ 'HAVE_SYS_SELECT_H': cc.has_header('sys/select.h'),
+ 'HAVE_SYS_DEVPOLL_H': cc.has_header('sys/devpoll.h'),
+ 'HAVE_SYS_EVENT_H': cc.has_header('sys/event.h'),
+ 'HAVE_PORT_H': cc.has_header('port.h'),
+ 'HAVE_SYS_SIGNALFD_H': cc.has_header('sys/signalfd.h'),
+ 'HAVE_SYS_TIMERFD_H': cc.has_header('sys/timerfd.h'),
+ 'TIME_WITH_SYS_TIME': cc.has_header('time.h'),
+ 'HAVE_GETEXECNAME': cc.has_function('getexecname'),
+ 'HAVE_STRLCPY': cc.has_function('strlcpy'),
+ 'HAVE_STRLCAT': cc.has_function('strlcat'),
+ 'HAVE_STRCASESTR': cc.has_function('strcasestr'),
+ 'HAVE_SIGNALFD': cc.has_function('signalfd'),
+ 'HAVE_ARC4RANDOM': cc.has_function('arc4random'),
+ 'HAVE_KEVENT': cc.has_function('kevent', prefix: '#include <sys/event.h>'),
+ 'HAVE_PORT_CREATE': cc.has_function('port_create', prefix: '#include <port.h>'),
+ 'HAVE_EPOLL_CTL': cc.has_function('epoll_ctl', prefix: '#include <sys/epoll.h>'),
+ 'HAVE_TIMERFD_CREATE': cc.has_function('timerfd_create', prefix: '#include <sys/timerfd.h>'),
+ 'HAVE_DLINFO': cc.has_function('dlinfo', dependencies: dl_dep),
+ 'HAVE_NANOSLEEP': cc.has_function('nanosleep', dependencies: rt_dep),
+ 'HAVE_TIMER_CREATE': cc.has_function('timer_create', dependencies: rt_dep, prefix: '#include <time.h>'),
+ 'HAVE_DEVPOLL': fs.exists('/dev/poll'),
+ 'SOCKADDR_IN_HAS_LEN': cc.has_member('struct sockaddr', 'sa_len', prefix: '#include <sys/types.h>\n#include <sys/socket.h>'),
+}
+foreach define, found : librb_checks
+ if found
+ librb_conf_data.set(define, 1)
+ endif
+endforeach
+
+# TLS backend configuration (passed from parent)
+if have_openssl
+ librb_conf_data.set('HAVE_OPENSSL', 1)
+endif
+
+if have_mbedtls
+ librb_conf_data.set('HAVE_MBEDTLS', 1)
+endif
+
+if have_gnutls
+ librb_conf_data.set('HAVE_GNUTLS', 1)
+endif
+
+librb_dash_config_h = configure_file(
+ input: 'librb-config.h.in',
+ output: 'librb-config.h',
+ configuration: librb_conf_data,
+ install: false
+)
+
+# For compat with autotools mess
+librb_underscore_config_h = configure_file(
+ input: librb_dash_config_h,
+ output: 'librb_config.h',
+ copy: true
+)
+
+librb_deps = [socket_dep, rt_dep, sctp_dep] + tls_deps
+
+librb_inc = include_directories('include', '.', is_system: false)
+
+librb_build_inc = include_directories('.', is_system: false)
+
+subdir('include')
+
+librb = shared_library('rb',
+ [librb_sources, librb_version_c, librb_dash_config_h, librb_underscore_config_h, librb_serno_h],
+ dependencies: librb_deps,
+ include_directories: [librb_inc, librb_build_inc],
+ install: true,
+)
+
+librb_dep = declare_dependency(
+ link_with: librb,
+ include_directories: librb_inc,
+ dependencies: librb_deps
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000..1bce5085
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,285 @@
+project('solanum', 'c',
+ version: '1.0-dev',
+ default_options: ['c_std=c99', 'warning_level=0'],
+ meson_version: '>=0.62.0', # dependency('dl')
+ license: 'GPLv2'
+)
+
+cc = meson.get_compiler('c')
+
+# Required dependencies
+flex = find_program('flex', 'lex', required: true)
+bison = find_program('bison', 'yacc', 'byacc', required: true)
+socket_dep = cc.find_library('socket', required: false)
+sqlite3_dep = dependency('sqlite3', required: true)
+dl_dep = dependency('dl', required: false)
+ltdl_dep = cc.find_library('ltdl', required: true)
+crypt_dep = cc.find_library('crypt', required: false)
+if not crypt_dep.found()
+ crypt_dep = cc.find_library('descrypt', required: false)
+endif
+
+# Optional dependencies
+hyperscan_dep = dependency('libhs', version: '>=4', required: get_option('hyperscan'))
+have_hyperscan = hyperscan_dep.found()
+
+sctp_dep = cc.find_library('sctp', has_headers: ['netinet/sctp.h'], required: get_option('sctp'))
+have_sctp = sctp_dep.found()
+
+# Priority: mbedTLS > OpenSSL > GnuTLS
+tls_backend = 'none'
+tls_deps = []
+have_openssl = false
+have_mbedtls = false
+have_gnutls = false
+
+# TLS libraries
+mbedtls_lib = cc.find_library('mbedtls', required: get_option('mbedtls'))
+mbedx509_lib = cc.find_library('mbedx509', required: get_option('mbedtls'))
+mbedcrypto_lib = cc.find_library('mbedcrypto', required: get_option('mbedtls'))
+openssl_dep = dependency('openssl', version: '>=1.1.0', required: get_option('openssl'))
+gnutls_dep = dependency('gnutls', required: get_option('gnutls'))
+
+if mbedtls_lib.found() and mbedx509_lib.found() and mbedcrypto_lib.found()
+ tls_backend = 'mbedtls'
+ tls_deps = [mbedtls_lib, mbedx509_lib, mbedcrypto_lib]
+ have_mbedtls = true
+elif openssl_dep.found()
+ tls_backend = 'openssl'
+ tls_deps = [openssl_dep]
+ have_openssl = true
+elif gnutls_dep.found()
+ tls_backend = 'gnutls'
+ tls_deps = [gnutls_dep]
+ have_gnutls = true
+endif
+
+message('TLS backend: ' + tls_backend)
+
+fhs_paths = get_option('fhs_paths')
+prefix = get_option('prefix')
+
+# Convert standard Meson directories to absolute paths
+libdir = prefix / get_option('libdir')
+bindir = prefix / get_option('bindir')
+libexecdir = prefix / get_option('libexecdir')
+datadir = prefix / get_option('datadir')
+localstatedir = prefix / get_option('localstatedir')
+sysconfdir_base = prefix / get_option('sysconfdir')
+
+if fhs_paths
+ pkglibexecdir = libexecdir / meson.project_name()
+ pkgrundir = prefix / 'run' / meson.project_name()
+ pkglocalstatedir = localstatedir / 'lib' / meson.project_name()
+
+ default_logdir = localstatedir / 'log' / meson.project_name()
+ default_helpdir = datadir / meson.project_name() / 'help'
+ default_moduledir = libdir / meson.project_name() / 'modules'
+else
+ pkglibexecdir = bindir
+ pkgrundir = sysconfdir_base
+ pkglocalstatedir = localstatedir
+
+ default_logdir = prefix / 'logs'
+ default_helpdir = prefix / 'help'
+ default_moduledir = prefix / 'modules'
+endif
+
+# User-overridable options with dynamic defaults
+option_defaults = {
+ 'logdir': default_logdir,
+ 'helpdir': default_helpdir,
+ 'moduledir': default_moduledir,
+ 'confdir': sysconfdir_base,
+ 'custom_branding': meson.project_name(),
+ 'custom_version': meson.project_version(),
+}
+foreach varname, default : option_defaults
+ opt = get_option(varname)
+ set_variable(varname, opt == '' ? default : opt)
+endforeach
+
+# rundir default depends on fhs_paths and confdir
+default_rundir = fhs_paths ? prefix / 'run' : confdir
+rundir_opt = get_option('rundir')
+rundir = rundir_opt == '' ? default_rundir : rundir_opt
+
+
+conf_data = configuration_data()
+
+# Basic defines
+conf_data.set_quoted('PACKAGE_NAME', meson.project_name())
+conf_data.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+# Path defines
+conf_data.set_quoted('IRCD_PREFIX', prefix)
+conf_data.set_quoted('ETC_DIR', confdir)
+conf_data.set_quoted('LOG_DIR', logdir)
+conf_data.set_quoted('HELP_DIR', helpdir)
+conf_data.set_quoted('MODULE_DIR', moduledir)
+conf_data.set_quoted('PKGLIBEXECDIR', pkglibexecdir)
+conf_data.set_quoted('PKGLOCALSTATEDIR', pkglocalstatedir)
+conf_data.set_quoted('PKGRUNDIR', rundir)
+
+# FHS paths
+if fhs_paths
+ conf_data.set('ENABLE_FHS_PATHS', 1)
+endif
+
+# Protocol limits
+conf_data.set('NICKLEN', get_option('nicklen') + 1)
+conf_data.set('TOPICLEN', get_option('topiclen'))
+
+# Branding
+conf_data.set_quoted('BRANDING_NAME', custom_branding)
+conf_data.set_quoted('BRANDING_VERSION', custom_version)
+
+if get_option('custom_branding') != ''
+ conf_data.set('CUSTOM_BRANDING', 1)
+endif
+
+# Program prefix
+program_prefix = get_option('program_prefix')
+conf_data.set_quoted('PROGRAM_PREFIX', program_prefix)
+
+# Features
+if get_option('oper_chghost')
+ conf_data.set('ENABLE_OPER_CHGHOST', 1)
+endif
+if have_sctp
+ conf_data.set('HAVE_LIBSCTP', 1)
+endif
+if have_hyperscan
+ conf_data.set('HAVE_HYPERSCAN', 1)
+endif
+
+# TLS backend defines
+if have_openssl
+ conf_data.set('HAVE_OPENSSL', 1)
+endif
+if have_mbedtls
+ conf_data.set('HAVE_MBEDTLS', 1)
+endif
+if have_gnutls
+ conf_data.set('HAVE_GNUTLS', 1)
+endif
+
+# Performance
+if get_option('profile')
+ conf_data.set('SOLANUM_PROFILE', 1)
+endif
+
+# Heap sizes
+conf_data.set('NICKNAMEHISTORYLENGTH', 15000) # Size of the WHOWAS array.
+conf_data.set('CHANNEL_HEAP_SIZE', 8192)
+conf_data.set('BAN_HEAP_SIZE', 4096)
+conf_data.set('CLIENT_HEAP_SIZE', 8192)
+conf_data.set('LCLIENT_HEAP_SIZE', 1024)
+conf_data.set('PCLIENT_HEAP_SIZE', 256)
+conf_data.set('USER_HEAP_SIZE', 8192)
+conf_data.set('DNODE_HEAP_SIZE', 8192)
+conf_data.set('TOPIC_HEAP_SIZE', 4096)
+conf_data.set('LINEBUF_HEAP_SIZE', 2048)
+conf_data.set('MEMBER_HEAP_SIZE', 32768)
+conf_data.set('ND_HEAP_SIZE', 512)
+conf_data.set('CONFITEM_HEAP_SIZE', 256)
+conf_data.set('MONITOR_HEAP_SIZE', 1024)
+conf_data.set('FD_HEAP_SIZE', 1024)
+conf_data.set('AWAY_HEAP_SIZE', 512)
+
+# System checks
+system_checks = {
+ 'HAVE_CRYPT_H': cc.has_header('crypt.h'),
+ 'HAVE_SYS_PARAM_H': cc.has_header('sys/param.h'),
+ 'HAVE_SYS_SYSLOG_H': cc.has_header('sys/syslog.h'),
+ 'HAVE_SYS_EPOLL_H': cc.has_header('sys/epoll.h'),
+ 'HAVE_MACHINE_ENDIAN_H': cc.has_header('machine/endian.h'),
+ 'HAVE_STRLCAT': cc.has_function('strlcat'),
+ 'HAVE_STRLCPY': cc.has_function('strlcpy'),
+}
+foreach define, found : system_checks
+ if found
+ conf_data.set(define, 1)
+ endif
+endforeach
+
+if not cc.has_header('stdarg.h')
+ error('stdarg.h is required')
+endif
+
+conf_data.set_quoted('PATH_DEVNULL', '/dev/null')
+
+if cc.has_type('uintptr_t', prefix: '#include <stdint.h>')
+ conf_data.set('HAVE_UINTPTR_T', 1)
+endif
+
+# For compat with autotools. See https://www.gnu.org/software/libtool/manual/html_node/Autoconf-macros.html#index-LT_005fSYS_005fMODULE_005fEXT
+# We only support Linux, though
+conf_data.set_quoted('LT_MODULE_EXT', '.so')
+
+
+c_args = []
+link_args = []
+
+if get_option('profile')
+ if cc.has_argument('-pg')
+ c_args += ['-pg']
+ link_args += ['-pg']
+ endif
+endif
+
+rpath = prefix / get_option('libdir')
+
+add_project_arguments(c_args, language: 'c')
+add_project_arguments('-D_GNU_SOURCE', language: 'c')
+
+subdir('include')
+subdir('librb')
+subdir('ircd')
+subdir('ssld')
+subdir('authd')
+subdir('bandb')
+subdir('tools')
+subdir('modules')
+subdir('extensions')
+subdir('help')
+subdir('doc')
+
+subdir('tests')
+
+install_emptydir(logdir)
+install_emptydir(pkglocalstatedir) # needed for FHS paths
+
+summary({
+ 'prefix': prefix,
+ 'confdir': confdir,
+ 'logdir': logdir,
+ 'helpdir': helpdir,
+ 'moduledir': moduledir,
+ 'pkglocalstatedir': pkglocalstatedir,
+ 'FHS paths': fhs_paths,
+}, section: 'Directories')
+
+summary({
+ 'TLS backend': tls_backend,
+ 'SCTP': have_sctp,
+ 'Hyperscan': have_hyperscan,
+ 'OPER CHGHOST': get_option('oper_chghost'),
+}, section: 'Features')
+
+summary({
+ 'Assertions': get_option('b_ndebug'),
+ 'Profile': get_option('profile'),
+ 'Warnings': get_option('warning_level'),
+}, section: 'Debug Options')
+
+summary({
+ 'Nickname length': get_option('nicklen'),
+ 'Topic length': get_option('topiclen'),
+}, section: 'Protocol Limits')
+
+summary({
+ 'Branding name': custom_branding,
+ 'Branding version': custom_version,
+ 'Program prefix': program_prefix,
+}, section: 'Branding')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000..6954ed90
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,49 @@
+# Directories
+option('fhs_paths', type: 'boolean', value: false,
+ description: 'Use FHS-compliant directory structure')
+option('confdir', type: 'string', value: '',
+ description: 'Directory for configuration files')
+option('logdir', type: 'string', value: '',
+ description: 'Directory for log files')
+option('helpdir', type: 'string', value: '',
+ description: 'Directory for help files')
+option('moduledir', type: 'string', value: '',
+ description: 'Directory for modules')
+option('rundir', type: 'string', value: '',
+ description: 'Directory for PID file')
+
+# TLS
+option('openssl', type: 'feature', value: 'auto',
+ description: 'Enable OpenSSL support')
+option('mbedtls', type: 'feature', value: 'auto',
+ description: 'Enable mbedTLS support')
+option('gnutls', type: 'feature', value: 'auto',
+ description: 'Enable GnuTLS support')
+
+# Features
+option('sctp', type: 'feature', value: 'auto',
+ description: 'Enable SCTP support')
+option('hyperscan', type: 'feature', value: 'auto',
+ description: 'Enable hyperscan regex support')
+option('oper_chghost', type: 'boolean', value: false,
+ description: 'Enable CHGHOST command for operators')
+
+# Debug
+option('profile', type: 'boolean', value: false,
+ description: 'Enable profiling support')
+
+# IRC protocol
+option('nicklen', type: 'integer', value: 31, min: 9, max: 50,
+ description: 'Maximum nickname length')
+option('topiclen', type: 'integer', value: 390, min: 1,
+ description: 'Maximum topic length')
+
+# Branding
+option('custom_branding', type: 'string', value: '',
+ description: 'Custom branding name')
+option('custom_version', type: 'string', value: '',
+ description: 'Custom version string')
+
+# Misc
+option('program_prefix', type: 'string', value: '',
+ description: 'Prefix for installed programs')
diff --git a/modules/meson.build b/modules/meson.build
new file mode 100644
index 00000000..c86233ae
--- /dev/null
+++ b/modules/meson.build
@@ -0,0 +1,114 @@
+autoload_modules = [
+ 'cap_account_tag',
+ 'cap_server_time',
+ 'chm_nocolour',
+ 'chm_noctcp',
+ 'um_callerid',
+ 'um_regonlymsg',
+ 'm_accept',
+ 'm_admin',
+ 'm_alias',
+ 'm_away',
+ 'm_batch',
+ 'm_cap',
+ 'm_capab',
+ 'm_certfp',
+ 'm_challenge',
+ 'm_chghost',
+ 'm_close',
+ 'm_connect',
+ 'm_dline',
+ 'm_encap',
+ 'm_etrace',
+ 'm_grant',
+ 'm_help',
+ 'm_info',
+ 'm_invite',
+ 'm_ison',
+ 'm_kline',
+ 'm_knock',
+ 'm_links',
+ 'm_list',
+ 'm_lusers',
+ 'm_map',
+ 'm_monitor',
+ 'm_motd',
+ 'm_names',
+ 'm_oper',
+ 'm_operspy',
+ 'm_pass',
+ 'm_ping',
+ 'm_pong',
+ 'm_post',
+ 'm_privs',
+ 'm_rehash',
+ 'm_restart',
+ 'm_resv',
+ 'm_sasl',
+ 'm_scan',
+ 'm_services',
+ 'm_set',
+ 'm_signon',
+ 'm_snote',
+ 'm_starttls',
+ 'm_stats',
+ 'm_svinfo',
+ 'm_tb',
+ 'm_testline',
+ 'm_testmask',
+ 'm_tginfo',
+ 'm_time',
+ 'm_topic',
+ 'm_trace',
+ 'm_unreject',
+ 'm_user',
+ 'm_userhost',
+ 'm_users',
+ 'm_version',
+ 'm_wallops',
+ 'm_who',
+ 'm_whois',
+ 'm_whowas',
+ 'm_xline',
+ 'sno_routing',
+]
+
+foreach mod : autoload_modules
+ shared_module(mod,
+ mod + '.c',
+ name_prefix: '',
+ name_suffix: 'so',
+ dependencies: [libircd_dep, librb_dep, global_include_dep],
+ install: true,
+ install_dir: moduledir / 'autoload'
+ )
+endforeach
+
+core_modules = [
+ 'm_ban',
+ 'm_die',
+ 'm_error',
+ 'm_join',
+ 'm_kick',
+ 'm_kill',
+ 'm_message',
+ 'm_mode',
+ 'm_modules',
+ 'm_nick',
+ 'm_part',
+ 'm_quit',
+ 'm_server',
+ 'm_squit',
+ 'm_identified',
+]
+
+foreach mod : core_modules
+ shared_module(mod,
+ 'core' / mod + '.c',
+ name_prefix: '',
+ name_suffix: 'so',
+ dependencies: [libircd_dep, librb_dep, global_include_dep],
+ install: true,
+ install_dir: moduledir
+ )
+endforeach
diff --git a/ssld/meson.build b/ssld/meson.build
new file mode 100644
index 00000000..736237a5
--- /dev/null
+++ b/ssld/meson.build
@@ -0,0 +1,8 @@
+ssld = executable('ssld',
+ 'ssld.c',
+ dependencies: [librb_dep],
+ include_directories: include_directories('../include'),
+ install: true,
+ install_dir: pkglibexecdir,
+ install_rpath: rpath,
+)
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 00000000..214eec77
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,62 @@
+tap_sources = files(
+ 'tap/basic.c',
+ 'tap/float.c',
+)
+
+tap_lib = static_library('tap',
+ tap_sources,
+ include_directories: [include_directories('tap'), include_directories('..')]
+)
+
+test_util_sources = files(
+ 'ircd_util.c',
+ 'client_util.c',
+)
+
+test_utils = static_library('test_utils',
+ [test_util_sources, serno_h],
+ dependencies: [libircd_dep, librb_dep],
+ include_directories: [include_directories('..')]
+)
+
+test_programs = {
+ 'chmode1': 'chmode1.c',
+ 'match1': 'match1.c',
+ 'misc': 'misc.c',
+ 'msgbuf_parse1': 'msgbuf_parse1.c',
+ 'msgbuf_unparse1': 'msgbuf_unparse1.c',
+ 'hostmask1': 'hostmask1.c',
+ 'privilege1': 'privilege1.c',
+ 'rb_dictionary1': 'rb_dictionary1.c',
+ 'rb_snprintf_append1': 'rb_snprintf_append1.c',
+ 'rb_snprintf_try_append1': 'rb_snprintf_try_append1.c',
+ 'sasl_abort1': 'sasl_abort1.c',
+ 'send1': 'send1.c',
+ 'send_multiline1': 'send_multiline1.c',
+ 'serv_connect1': 'serv_connect1.c',
+ 'substitution1': 'substitution1.c',
+}
+
+foreach test_name, test_source : test_programs
+ test_exe = executable(test_name,
+ test_source,
+ dependencies: [libircd_dep, librb_dep, dl_dep],
+ link_with: [test_utils, tap_lib],
+ include_directories: [include_directories('..')],
+ build_by_default: true
+ )
+
+ test(test_name, test_exe)
+endforeach
+
+runtests = executable('runtests',
+ 'runtests.c',
+ c_args: [
+ '-DC_TAP_SOURCE="' + meson.current_source_dir() + '"',
+ '-DC_TAP_BUILD="' + meson.current_build_dir() + '"',
+ ],
+ link_with: [tap_lib],
+ include_directories: [include_directories('tap'), include_directories('..')],
+ build_by_default: true,
+ install_rpath: rpath,
+)
diff --git a/tools/meson.build b/tools/meson.build
new file mode 100644
index 00000000..d7bd0b37
--- /dev/null
+++ b/tools/meson.build
@@ -0,0 +1,15 @@
+tools_inc = include_directories('../include')
+
+tools = {
+ 'mkpasswd': [librb_dep, crypt_dep],
+ 'mkfingerprint': [librb_dep],
+}
+foreach name, deps : tools
+ executable('solanum-' + name,
+ name + '.c',
+ dependencies: deps,
+ include_directories: tools_inc,
+ install: true,
+ install_rpath: rpath,
+ )
+endforeach