From fbfa1f13e556e66bc95dea4c73e6d3292ed0754f Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Wed, 4 Feb 2026 22:50:40 +0100 Subject: [PATCH 01/16] Add meson build system --- .gitignore | 1 - meson.build | 835 ++++++++++++++++++++++++++++++++++++++++++++ meson_options.txt | 89 +++++ src/gitversion.h.in | 6 + 4 files changed, 930 insertions(+), 1 deletion(-) create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 src/gitversion.h.in diff --git a/.gitignore b/.gitignore index 37a7838b..39e9b5a5 100644 --- a/.gitignore +++ b/.gitignore @@ -40,7 +40,6 @@ src/config.h src/config.h.in src/config.h.in~ src/gitversion.h -src/gitversion.h.in src/stamp-h1 src/plugins/profapi.lo diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..84c57097 --- /dev/null +++ b/meson.build @@ -0,0 +1,835 @@ +project('profanity', 'c', + version: '0.15.1', + license: 'GPL-3.0-or-later', + meson_version: '>= 0.56.0', + default_options: [ + 'c_std=gnu99', + 'warning_level=2', + ] +) + +# 'development' or 'release' +package_status = 'development' + +# Determine platform +host_system = host_machine.system() +platform = 'unknown' + +if host_system == 'freebsd' + platform = 'freebsd' +elif host_system == 'netbsd' + platform = 'netbsd' +elif host_system == 'openbsd' + platform = 'openbsd' +elif host_system == 'darwin' + platform = 'osx' +elif host_system == 'cygwin' + platform = 'cygwin' +else + platform = 'nix' +endif + +# Configuration data +conf_data = configuration_data() +conf_data.set_quoted('PACKAGE_NAME', meson.project_name()) +conf_data.set_quoted('PACKAGE_VERSION', meson.project_version()) +conf_data.set_quoted('PACKAGE_BUGREPORT', 'jubalh@iodoru.org') +conf_data.set_quoted('PACKAGE_URL', 'https://profanity-im.github.io/') +conf_data.set_quoted('PACKAGE_STATUS', package_status) + +if platform == 'cygwin' + conf_data.set('PLATFORM_CYGWIN', 1) +endif + +if platform == 'osx' + conf_data.set('PLATFORM_OSX', 1) +endif + +# Get git version if in development +if package_status == 'development' + git = find_program('git', required: false) + if git.found() + conf_data.set('HAVE_GIT_VERSION', 1) + endif +endif + +# Compiler setup +cc = meson.get_compiler('c') + +# Common compiler flags +add_project_arguments('-Wno-deprecated-declarations', language: 'c') + +if get_option('buildtype') == 'debug' or package_status == 'development' + add_project_arguments('-Wunused', language: 'c') +endif + +if platform == 'osx' + add_project_arguments('-Qunused-arguments', language: 'c') + + # Check for homebrew paths on Apple Silicon + if run_command('test', '-d', '/opt/homebrew/include', check: false).returncode() == 0 + add_project_arguments('-I/opt/homebrew/include', language: 'c') + add_project_link_arguments('-L/opt/homebrew/lib', language: 'c') + endif +endif + +# Required dependencies +glib_dep = dependency('glib-2.0', version: '>= 2.62.0') +gio_dep = dependency('gio-2.0') +curl_dep = dependency('libcurl', version: '>= 7.62.0') +sqlite_dep = dependency('sqlite3', version: '>= 3.22.0') +thread_dep = dependency('threads') +math_dep = cc.find_library('m', required: true) +libstrophe_dep = dependency('libstrophe', version: '>= 0.12.3') + +# Check if libstrophe works +if not cc.links(''' + #include + int main() { + xmpp_initialize(); + return 0; + } + ''', dependencies: libstrophe_dep) + error('libstrophe is broken') +endif + +# Check for XMPP_CERT_PUBKEY_FINGERPRINT_SHA256 support +if cc.links(''' + #include + int main() { + xmpp_tlscert_get_string(NULL, XMPP_CERT_PUBKEY_FINGERPRINT_SHA256); + return 1; + } + ''', dependencies: libstrophe_dep) + conf_data.set('HAVE_XMPP_CERT_PUBKEY_FINGERPRINT_SHA256', 1) +endif + +# Curses/ncurses library +ncursesw_dep = dependency('ncursesw', required: false) +ncurses_dep = dependency('ncurses', required: false) + +if ncursesw_dep.found() + curses_dep = ncursesw_dep + curses_name = 'ncursesw' +elif ncurses_dep.found() + curses_dep = ncurses_dep + curses_name = 'ncurses' +else + curses_dep = cc.find_library('ncursesw', required: false) + if curses_dep.found() + curses_name = 'ncursesw' + else + curses_dep = cc.find_library('ncurses', required: false) + if curses_dep.found() + curses_name = 'ncurses' + else + curses_dep = cc.find_library('curses', required: true) + curses_name = 'curses' + endif + endif +endif + +# Check for wide character support +if not cc.links(''' + void wget_wch(void); + int main() { + wget_wch(); + return 0; + } + ''', dependencies: curses_dep) + error('ncurses does not support wide characters') +endif + +# Check for ncurses headers +if cc.has_header('ncursesw/ncurses.h') + conf_data.set('HAVE_NCURSESW_NCURSES_H', 1) +endif +if cc.has_header('ncurses.h') + conf_data.set('HAVE_NCURSES_H', 1) +endif +if cc.has_header('curses.h') + conf_data.set('HAVE_CURSES_H', 1) +endif + +# Readline: +# we need to declare the variable before +# using it in the conditional branch. +# Later the required is set correctly. +readline_dep = dependency('', required: false) + +if platform == 'osx' + brew = find_program('brew', required: false, dirs: ['/opt/homebrew/bin', '/usr/local/bin']) + + if brew.found() + readline_prefix_cmd = run_command(brew, '--prefix', 'readline', check: false) + if readline_prefix_cmd.returncode() == 0 + readline_prefix = readline_prefix_cmd.stdout().strip() + else + readline_prefix = '/usr/local' + endif + else + if run_command('test', '-f', '/opt/local/lib/libreadline.dylib', check: false).returncode() == 0 + readline_prefix = '/opt/local' + else + readline_prefix = '/usr/local' + endif + endif + + readline_dep = cc.find_library('readline', + dirs: [readline_prefix / 'lib'], + required: true) + add_project_arguments('-I' + readline_prefix / 'include', language: 'c') +elif platform == 'openbsd' + if run_command('test', '-d', '/usr/local/include/ereadline', check: false).returncode() == 0 + readline_dep = cc.find_library('ereadline', + dirs: ['/usr/local/lib'], + required: true) + add_project_arguments('-I/usr/local/include/ereadline', language: 'c') + else + readline_dep = cc.find_library('readline', required: true) + endif +else + readline_dep = cc.find_library('readline', required: true) +endif + +# Optional dependencies: +# Notifications +libnotify_dep = dependency('', required: false) +have_osxnotify = false + +if get_option('notifications').enabled() or get_option('notifications').auto() + if platform == 'osx' + terminal_notifier = find_program('terminal-notifier', required: get_option('notifications')) + if terminal_notifier.found() + have_osxnotify = true + conf_data.set('HAVE_OSXNOTIFY', 1) + endif + elif platform == 'nix' or platform == 'freebsd' + libnotify_dep = dependency('libnotify', required: get_option('notifications')) + if libnotify_dep.found() + conf_data.set('HAVE_LIBNOTIFY', 1) + endif + endif +endif + +# GTK (for icons and clipboard) +gtk_dep = dependency('', required: false) +gtk_version = 'none' + +if get_option('icons-and-clipboard').enabled() or get_option('icons-and-clipboard').auto() + gtk_dep = dependency('gtk+-3.0', version: '>= 3.24.0', required: false) + if gtk_dep.found() + conf_data.set('HAVE_GTK', 1) + gtk_version = gtk_dep.version() + else + gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.10', + required: get_option('icons-and-clipboard')) + if gtk_dep.found() + conf_data.set('HAVE_GTK', 1) + gtk_version = gtk_dep.version() + endif + endif +endif + +# XScreenSaver +xscrnsaver_dep = dependency('', required: false) + +if get_option('xscreensaver').enabled() or get_option('xscreensaver').auto() + xss_dep = dependency('xscrnsaver', required: false) + x11_dep = dependency('x11', required: false) + + if xss_dep.found() and x11_dep.found() + xscrnsaver_dep = [xss_dep, x11_dep] + conf_data.set('HAVE_LIBXSS', 1) + elif get_option('xscreensaver').enabled() + error('xscreensaver support requested but xscrnsaver or x11 not found') + endif +endif + +# Python plugins +python_dep = dependency('', required: false) +build_python_api = false + +if not get_option('plugins').disabled() and not get_option('python-plugins').disabled() + if platform == 'osx' + # Handle Python framework on macOS + python_framework = get_option('python_framework') + if python_framework == '' + python_framework = '/Library/Frameworks/Python.framework' + endif + endif + + python_dep = dependency('python-embed', required: false) + if not python_dep.found() + python_dep = dependency('python3-embed', required: false) + if python_dep.found() + conf_data.set('PY_IS_PYTHON3', 1) + endif + endif + + if python_dep.found() + build_python_api = true + conf_data.set('HAVE_PYTHON', 1) + elif get_option('python-plugins').enabled() + error('Python plugins enabled but Python not found') + endif +endif + +# C plugins +dl_dep = dependency('', required: false) +build_c_api = false + +if platform != 'cygwin' + if not get_option('plugins').disabled() and not get_option('c-plugins').disabled() + if platform == 'openbsd' or platform == 'freebsd' or platform == 'netbsd' + build_c_api = true + conf_data.set('HAVE_C', 1) + else + dl_dep = cc.find_library('dl', required: get_option('c-plugins')) + if dl_dep.found() + build_c_api = true + conf_data.set('HAVE_C', 1) + endif + endif + endif +endif + +# PGP support +gpgme_dep = dependency('', required: false) +build_pgp = false + +if not get_option('pgp').disabled() + gpgme_dep = cc.find_library('gpgme', required: false) + + if gpgme_dep.found() + gpgme_config = find_program('gpgme-config', required: false) + if gpgme_config.found() + gpgme_cflags = run_command(gpgme_config, '--cflags', check: true).stdout().strip() + gpgme_libs = run_command(gpgme_config, '--libs', check: true).stdout().strip() + add_project_arguments(gpgme_cflags.split(), language: 'c') + endif + + build_pgp = true + conf_data.set('HAVE_LIBGPGME', 1) + elif get_option('pgp').enabled() + error('PGP support enabled but libgpgme not found') + endif +endif + +# OTR support +libotr_dep = dependency('', required: false) +build_otr = false + +if not get_option('otr').disabled() + libotr_dep = dependency('libotr', version: '>= 4.0', required: get_option('otr')) + if libotr_dep.found() + build_otr = true + conf_data.set('HAVE_LIBOTR', 1) + endif +endif + +# GDK Pixbuf (for avatar scaling) +gdk_pixbuf_dep = dependency('', required: false) + +if not get_option('gdk-pixbuf').disabled() + gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.4', + required: get_option('gdk-pixbuf')) + if gdk_pixbuf_dep.found() + conf_data.set('HAVE_PIXBUF', 1) + endif +endif + +# OMEMO support +libsignal_dep = dependency('', required: false) +gcrypt_dep = dependency('', required: false) +build_omemo = false + +if not get_option('omemo').disabled() + libsignal_dep = dependency('libsignal-protocol-c', version: '>= 2.3.2', required: false) + + if libsignal_dep.found() + gcrypt_dep = dependency('libgcrypt', version: '>= 1.7.0', required: false) + + if gcrypt_dep.found() + build_omemo = true + conf_data.set('HAVE_OMEMO', 1) + elif get_option('omemo').enabled() + error('OMEMO support enabled but libgcrypt >= 1.7.0 not found') + endif + elif get_option('omemo').enabled() + error('OMEMO support enabled but libsignal-protocol-c >= 2.3.2 not found') + endif +endif + +# QR code support (for OMEMO) +qrencode_dep = dependency('', required: false) + +if not get_option('omemo-qrcode').disabled() + qrencode_dep = dependency('libqrencode', required: get_option('omemo-qrcode')) + if qrencode_dep.found() + conf_data.set('HAVE_QRENCODE', 1) + endif +endif + +# Set installation paths +themes_path = get_option('themes_path') +if themes_path == '' + themes_path = get_option('datadir') / meson.project_name() / 'themes' +endif + +icons_path = get_option('datadir') / meson.project_name() / 'icons' +global_python_plugins_path = get_option('datadir') / meson.project_name() / 'plugins' +global_c_plugins_path = get_option('libdir') / meson.project_name() / 'plugins' + +conf_data.set_quoted('THEMES_PATH', get_option('prefix') / themes_path) +conf_data.set_quoted('ICONS_PATH', get_option('prefix') / icons_path) +conf_data.set_quoted('GLOBAL_PYTHON_PLUGINS_PATH', get_option('prefix') / global_python_plugins_path) +conf_data.set_quoted('GLOBAL_C_PLUGINS_PATH', get_option('prefix') / global_c_plugins_path) + +# Check for required functions +foreach func : ['atexit', 'memset', 'strdup', 'strstr'] + if cc.has_function(func) + conf_data.set('HAVE_' + func.to_upper(), 1) + endif +endforeach + +# Generate config.h +config_h = configure_file( + output: 'config.h', + configuration: conf_data, + install: false, +) + +# Make config.h available by adding build directory to include path +config_h_inc = include_directories('.') + +# Build dependencies list +profanity_deps = [ + glib_dep, + gio_dep, + curl_dep, + sqlite_dep, + thread_dep, + math_dep, + libstrophe_dep, + curses_dep, + readline_dep, +] + +if libnotify_dep.found() + profanity_deps += libnotify_dep +endif + +if gtk_dep.found() + profanity_deps += gtk_dep +endif + +if xscrnsaver_dep.found() + profanity_deps += xscrnsaver_dep +endif + +if python_dep.found() + profanity_deps += python_dep +endif + +if dl_dep.found() + profanity_deps += dl_dep +endif + +if gpgme_dep.found() + profanity_deps += gpgme_dep +endif + +if libotr_dep.found() + profanity_deps += libotr_dep +endif + +if gdk_pixbuf_dep.found() + profanity_deps += gdk_pixbuf_dep +endif + +if libsignal_dep.found() and gcrypt_dep.found() + profanity_deps += [libsignal_dep, gcrypt_dep] +endif + +if qrencode_dep.found() + profanity_deps += qrencode_dep +endif + +# Include directories +inc = include_directories('.', 'src') + +# Core source files +core_sources = files( + 'src/xmpp/contact.c', + 'src/log.c', + 'src/common.c', + 'src/chatlog.c', + 'src/database.c', + 'src/profanity.c', + 'src/xmpp/chat_session.c', + 'src/xmpp/muc.c', + 'src/xmpp/jid.c', + 'src/xmpp/chat_state.c', + 'src/xmpp/resource.c', + 'src/xmpp/roster_list.c', + 'src/xmpp/capabilities.c', + 'src/xmpp/session.c', + 'src/xmpp/connection.c', + 'src/xmpp/iq.c', + 'src/xmpp/message.c', + 'src/xmpp/presence.c', + 'src/xmpp/stanza.c', + 'src/xmpp/roster.c', + 'src/xmpp/bookmark.c', + 'src/xmpp/blocking.c', + 'src/xmpp/form.c', + 'src/xmpp/avatar.c', + 'src/xmpp/ox.c', + 'src/xmpp/vcard.c', + 'src/event/common.c', + 'src/event/server_events.c', + 'src/event/client_events.c', + 'src/ui/window.c', + 'src/ui/core.c', + 'src/ui/titlebar.c', + 'src/ui/statusbar.c', + 'src/ui/inputwin.c', + 'src/ui/screen.c', + 'src/ui/console.c', + 'src/ui/notifier.c', + 'src/ui/window_list.c', + 'src/ui/rosterwin.c', + 'src/ui/occupantswin.c', + 'src/ui/buffer.c', + 'src/ui/chatwin.c', + 'src/ui/mucwin.c', + 'src/ui/privwin.c', + 'src/ui/confwin.c', + 'src/ui/xmlwin.c', + 'src/ui/vcardwin.c', + 'src/command/cmd_defs.c', + 'src/command/cmd_funcs.c', + 'src/command/cmd_ac.c', + 'src/tools/parser.c', + 'src/tools/http_common.c', + 'src/tools/http_upload.c', + 'src/tools/http_download.c', + 'src/tools/plugin_download.c', + 'src/tools/bookmark_ignore.c', + 'src/tools/autocomplete.c', + 'src/tools/clipboard.c', + 'src/tools/editor.c', + 'src/config/files.c', + 'src/config/conflists.c', + 'src/config/accounts.c', + 'src/config/tlscerts.c', + 'src/config/account.c', + 'src/config/preferences.c', + 'src/config/theme.c', + 'src/config/color.c', + 'src/config/scripts.c', + 'src/config/cafile.c', + 'src/plugins/plugins.c', + 'src/plugins/api.c', + 'src/plugins/callbacks.c', + 'src/plugins/autocompleters.c', + 'src/plugins/themes.c', + 'src/plugins/settings.c', + 'src/plugins/disco.c', +) + +# Python plugin sources +python_sources = files( + 'src/plugins/python_plugins.c', + 'src/plugins/python_api.c', +) + +# C plugin sources +c_sources = files( + 'src/plugins/c_plugins.c', + 'src/plugins/c_api.c', +) + +# PGP sources +pgp_sources = files( + 'src/pgp/gpg.c', + 'src/pgp/ox.c', +) + +# OTR sources +otr_sources = files( + 'src/otr/otrlibv4.c', + 'src/otr/otr.c', +) + +# OMEMO sources +omemo_sources = files( + 'src/omemo/omemo.c', + 'src/omemo/crypto.c', + 'src/omemo/store.c', + 'src/xmpp/omemo.c', + 'src/tools/aesgcm_download.c', +) + +# Build the final source list +profanity_sources = core_sources + +# Add tray support only when GTK is available +# The calls to tray functions in profanity.c are already conditional on HAVE_GTK +if gtk_dep.found() + profanity_sources += files('src/ui/tray.c') +endif + +if build_python_api + profanity_sources += python_sources +endif + +if build_c_api + profanity_sources += c_sources +endif + +if build_pgp + profanity_sources += pgp_sources +endif + +if build_otr + profanity_sources += otr_sources +endif + +if build_omemo + profanity_sources += omemo_sources +endif + +# Main source file +main_source = files('src/main.c') + +# Generate git version header if in development +if package_status == 'development' + git_branch = run_command('git', 'rev-parse', '--symbolic-full-name', '--abbrev-ref', 'HEAD', + check: false).stdout().strip() + git_revision = run_command('git', 'log', '--pretty=format:%h', '-n', '1', + check: false).stdout().strip() + + git_version_conf = configuration_data() + git_version_conf.set('PROF_GIT_BRANCH', '"' + git_branch + '"') + git_version_conf.set('PROF_GIT_REVISION', '"' + git_revision + '"') + + configure_file( + input: 'src/gitversion.h.in', + output: 'gitversion.h', + configuration: git_version_conf, + install: false, + ) +endif + +# Build the executable +profanity_exe = executable( + 'profanity', + profanity_sources + main_source + [config_h], + dependencies: profanity_deps, + include_directories: inc, + install: true, + export_dynamic: true, +) + +# Build libprofanity shared library for C plugins +if build_c_api + libprofanity = shared_library( + 'profanity', + 'src/plugins/profapi.c', + dependencies: profanity_deps, + include_directories: inc, + install: true, + version: '0.0.0', + ) + + # Install profapi.h header + install_headers('src/plugins/profapi.h') +endif + +# Install themes if enabled +if get_option('install_themes') + install_subdir('themes', + install_dir: get_option('datadir') / meson.project_name(), + strip_directory: false, + ) +endif + +# Install icons +install_subdir('icons', + install_dir: get_option('datadir') / meson.project_name(), + strip_directory: false, +) + +# Install man pages + man_pages = run_command('find', 'docs', '-name', 'profanity*.1', '-type', 'f', + check: true).stdout().strip().split('\n') + +if man_pages.length() > 0 and man_pages[0] != '' + install_man(man_pages) +endif + +# Install example config +install_data('profrc.example', + install_dir: get_option('datadir') / 'doc' / meson.project_name(), +) + +install_data('theme_template', + install_dir: get_option('datadir') / 'doc' / meson.project_name(), +) + +# Tests +if get_option('tests') + cmocka_dep = dependency('cmocka', required: false) + if cmocka_dep.found() + # Unit test sources + unittest_sources = files( + 'src/xmpp/contact.c', + 'src/common.c', + 'src/profanity.c', + 'src/xmpp/chat_session.c', + 'src/xmpp/muc.c', + 'src/xmpp/jid.c', + 'src/xmpp/resource.c', + 'src/xmpp/chat_state.c', + 'src/xmpp/roster_list.c', + 'src/xmpp/form.c', + 'src/command/cmd_defs.c', + 'src/command/cmd_funcs.c', + 'src/command/cmd_ac.c', + 'src/tools/parser.c', + 'src/tools/autocomplete.c', + 'src/tools/clipboard.c', + 'src/tools/editor.c', + 'src/tools/bookmark_ignore.c', + 'src/config/account.c', + 'src/config/files.c', + 'src/config/tlscerts.c', + 'src/config/preferences.c', + 'src/config/theme.c', + 'src/config/color.c', + 'src/config/scripts.c', + 'src/config/conflists.c', + 'src/plugins/plugins.c', + 'src/plugins/api.c', + 'src/plugins/callbacks.c', + 'src/plugins/autocompleters.c', + 'src/plugins/themes.c', + 'src/plugins/settings.c', + 'src/plugins/disco.c', + 'src/ui/window_list.c', + 'src/event/common.c', + 'src/event/server_events.c', + 'src/event/client_events.c', + 'src/ui/tray.c', + 'tests/unittests/xmpp/stub_vcard.c', + 'tests/unittests/xmpp/stub_avatar.c', + 'tests/unittests/xmpp/stub_ox.c', + 'tests/unittests/xmpp/stub_xmpp.c', + 'tests/unittests/xmpp/stub_message.c', + 'tests/unittests/ui/stub_ui.c', + 'tests/unittests/ui/stub_vcardwin.c', + 'tests/unittests/log/stub_log.c', + 'tests/unittests/chatlog/stub_chatlog.c', + 'tests/unittests/database/stub_database.c', + 'tests/unittests/config/stub_accounts.c', + 'tests/unittests/config/stub_cafile.c', + 'tests/unittests/tools/stub_http_upload.c', + 'tests/unittests/tools/stub_http_download.c', + 'tests/unittests/tools/stub_aesgcm_download.c', + 'tests/unittests/tools/stub_plugin_download.c', + 'tests/unittests/helpers.c', + 'tests/unittests/test_form.c', + 'tests/unittests/test_common.c', + 'tests/unittests/test_autocomplete.c', + 'tests/unittests/test_jid.c', + 'tests/unittests/test_parser.c', + 'tests/unittests/test_roster_list.c', + 'tests/unittests/test_chat_session.c', + 'tests/unittests/test_contact.c', + 'tests/unittests/test_preferences.c', + 'tests/unittests/test_server_events.c', + 'tests/unittests/test_muc.c', + 'tests/unittests/test_cmd_presence.c', + 'tests/unittests/test_cmd_alias.c', + 'tests/unittests/test_cmd_connect.c', + 'tests/unittests/test_cmd_rooms.c', + 'tests/unittests/test_cmd_account.c', + 'tests/unittests/test_cmd_sub.c', + 'tests/unittests/test_cmd_bookmark.c', + 'tests/unittests/test_cmd_otr.c', + 'tests/unittests/test_cmd_pgp.c', + 'tests/unittests/test_cmd_join.c', + 'tests/unittests/test_cmd_roster.c', + 'tests/unittests/test_cmd_disconnect.c', + 'tests/unittests/test_callbacks.c', + 'tests/unittests/test_plugins_disco.c', + 'tests/unittests/unittests.c', + ) + + if build_python_api + unittest_sources += python_sources + endif + + if build_c_api + unittest_sources += c_sources + endif + + if build_pgp + unittest_sources += files( + 'tests/unittests/pgp/stub_gpg.c', + 'tests/unittests/pgp/stub_ox.c', + ) + endif + + if build_otr + unittest_sources += files( + 'tests/unittests/otr/stub_otr.c', + ) + endif + + if build_omemo + unittest_sources += files( + 'tests/unittests/omemo/stub_omemo.c', + ) + endif + + # Build unit tests + unittests = executable( + 'unittests', + unittest_sources, + dependencies: profanity_deps + [cmocka_dep], + include_directories: [inc, include_directories('tests')], + build_by_default: false, + ) + + test('unit tests', unittests) + else + warning('cmocka not found, tests will not be built') + endif +endif + +summary({ + 'Platform': platform, + 'Package status': package_status, + 'GTK version': gtk_version, + 'Install themes': get_option('install_themes'), + 'Themes path': themes_path, + 'Icons path': icons_path, + 'Global Python plugins path': global_python_plugins_path, + 'Global C plugins path': global_c_plugins_path, +}, section: 'Directories') + +summary({ + 'Notifications': libnotify_dep.found() or have_osxnotify, + 'Python plugins': build_python_api, + 'C plugins': build_c_api, + 'OTR': build_otr, + 'PGP': build_pgp, + 'OMEMO': build_omemo, + 'XScreenSaver': xscrnsaver_dep.found(), + 'GTK': gtk_dep.found(), + 'GDK Pixbuf': gdk_pixbuf_dep.found(), + 'QR Code': qrencode_dep.found(), +}, section: 'Features') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..dfbf84bf --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,89 @@ +option('notifications', + type: 'feature', + value: 'auto', + description: 'Enable desktop notifications' +) + +option('python-plugins', + type: 'feature', + value: 'auto', + description: 'Enable Python plugins' +) + +option('c-plugins', + type: 'feature', + value: 'auto', + description: 'Enable C plugins' +) + +option('plugins', + type: 'feature', + value: 'auto', + description: 'Enable plugins (both Python and C)' +) + +option('otr', + type: 'feature', + value: 'auto', + description: 'Enable OTR encryption' +) + +option('pgp', + type: 'feature', + value: 'auto', + description: 'Enable PGP' +) + +option('omemo', + type: 'feature', + value: 'auto', + description: 'Enable OMEMO encryption' +) + +option('xscreensaver', + type: 'feature', + value: 'auto', + description: 'Use libXScrnSaver to determine idle time' +) + +option('install_themes', + type: 'boolean', + value: true, + description: 'Install themes' +) + +option('themes_path', + type: 'string', + value: '', + description: 'Custom path for themes installation (empty for default)' +) + +option('icons-and-clipboard', + type: 'feature', + value: 'auto', + description: 'Enable GTK tray icons and clipboard paste support' +) + +option('gdk-pixbuf', + type: 'feature', + value: 'auto', + description: 'Enable GDK Pixbuf support to scale avatars before uploading' +) + +option('omemo-qrcode', + type: 'feature', + value: 'auto', + description: 'Enable ability to display OMEMO QR code' +) + +option('python_framework', + type: 'string', + value: '', + description: 'Set base directory for Python Framework (macOS only)' +) + +option('tests', + type: 'boolean', + value: false, + description: 'Build tests' +) diff --git a/src/gitversion.h.in b/src/gitversion.h.in new file mode 100644 index 00000000..812644ba --- /dev/null +++ b/src/gitversion.h.in @@ -0,0 +1,6 @@ +#ifndef PROF_GIT_BRANCH +#define PROF_GIT_BRANCH @PROF_GIT_BRANCH@ +#endif +#ifndef PROF_GIT_REVISION +#define PROF_GIT_REVISION @PROF_GIT_REVISION@ +#endif From 3f76676e9ad39ab7ec9df128367a759dadf79672 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 09:21:23 +0100 Subject: [PATCH 02/16] build: use default meson buildtype In autotools we had `package_status` which we set to either `release` or `development`. When converting from autotools to meson we used that mechanism as well. But actually meson has a default way of handling this with the option `buildtype`. The following values are possible: debug, debugoptimized, release, plain So our `package_status = development` will now be `if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized'`. Probably we could also use `if get_option('buildtype') == 'release'. But like this the `plain` will be really plain. Usage: ``` meson setup build --buildtype=debug meson compile -C build ``` --- meson.build | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 84c57097..7ca5431e 100644 --- a/meson.build +++ b/meson.build @@ -8,9 +8,6 @@ project('profanity', 'c', ] ) -# 'development' or 'release' -package_status = 'development' - # Determine platform host_system = host_machine.system() platform = 'unknown' @@ -35,7 +32,14 @@ conf_data.set_quoted('PACKAGE_NAME', meson.project_name()) conf_data.set_quoted('PACKAGE_VERSION', meson.project_version()) conf_data.set_quoted('PACKAGE_BUGREPORT', 'jubalh@iodoru.org') conf_data.set_quoted('PACKAGE_URL', 'https://profanity-im.github.io/') -conf_data.set_quoted('PACKAGE_STATUS', package_status) + +# possible options from meson: +# debug, debugoptimized, release, plain +if get_option('buildtype') == 'release' + conf_data.set_quoted('PACKAGE_STATUS', 'release') +else + conf_data.set_quoted('PACKAGE_STATUS', 'development') +endif if platform == 'cygwin' conf_data.set('PLATFORM_CYGWIN', 1) @@ -46,7 +50,7 @@ if platform == 'osx' endif # Get git version if in development -if package_status == 'development' +if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' git = find_program('git', required: false) if git.found() conf_data.set('HAVE_GIT_VERSION', 1) @@ -59,7 +63,7 @@ cc = meson.get_compiler('c') # Common compiler flags add_project_arguments('-Wno-deprecated-declarations', language: 'c') -if get_option('buildtype') == 'debug' or package_status == 'development' +if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' add_project_arguments('-Wunused', language: 'c') endif @@ -605,7 +609,7 @@ endif main_source = files('src/main.c') # Generate git version header if in development -if package_status == 'development' +if get_option('buildtype') == 'release' or get_option('buildtype') == 'debugoptimized' git_branch = run_command('git', 'rev-parse', '--symbolic-full-name', '--abbrev-ref', 'HEAD', check: false).stdout().strip() git_revision = run_command('git', 'log', '--pretty=format:%h', '-n', '1', @@ -812,7 +816,7 @@ endif summary({ 'Platform': platform, - 'Package status': package_status, + 'Package status': get_option('buildtype'), 'GTK version': gtk_version, 'Install themes': get_option('install_themes'), 'Themes path': themes_path, From 87c4b7ec53306f0ebb03ce17463285947d84c370 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 09:33:13 +0100 Subject: [PATCH 03/16] build: readd compiler flags that got lost in conversion --- meson.build | 3 +++ 1 file changed, 3 insertions(+) diff --git a/meson.build b/meson.build index 7ca5431e..7e107579 100644 --- a/meson.build +++ b/meson.build @@ -64,7 +64,10 @@ cc = meson.get_compiler('c') add_project_arguments('-Wno-deprecated-declarations', language: 'c') if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' + add_project_arguments('-ggdb3', language: 'c') add_project_arguments('-Wunused', language: 'c') + #Disabled for now due so we can build + #add_project_arguments('-Werror', language: 'c') endif if platform == 'osx' From 49ef85a58d8ce2b51abaa9e603b0dbc0ba7ec01d Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 11:58:11 +0100 Subject: [PATCH 04/16] build: introduce variable to check for xscreensaver `.found()` does not work on lists. And since this feature needs several deps it is a list. --- meson.build | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 7e107579..bd9c32fd 100644 --- a/meson.build +++ b/meson.build @@ -239,7 +239,9 @@ if get_option('icons-and-clipboard').enabled() or get_option('icons-and-clipboar endif # XScreenSaver -xscrnsaver_dep = dependency('', required: false) +# We use this variable because .found() will later not work on a list +xscrnsaver_found = false +xscrnsaver_dep = [] if get_option('xscreensaver').enabled() or get_option('xscreensaver').auto() xss_dep = dependency('xscrnsaver', required: false) @@ -247,6 +249,7 @@ if get_option('xscreensaver').enabled() or get_option('xscreensaver').auto() if xss_dep.found() and x11_dep.found() xscrnsaver_dep = [xss_dep, x11_dep] + xscrnsaver_found = true # Set our tracker to true conf_data.set('HAVE_LIBXSS', 1) elif get_option('xscreensaver').enabled() error('xscreensaver support requested but xscrnsaver or x11 not found') @@ -431,7 +434,7 @@ if gtk_dep.found() profanity_deps += gtk_dep endif -if xscrnsaver_dep.found() +if xscrnsaver_found profanity_deps += xscrnsaver_dep endif @@ -835,7 +838,7 @@ summary({ 'OTR': build_otr, 'PGP': build_pgp, 'OMEMO': build_omemo, - 'XScreenSaver': xscrnsaver_dep.found(), + 'XScreenSaver': xscrnsaver_found, 'GTK': gtk_dep.found(), 'GDK Pixbuf': gdk_pixbuf_dep.found(), 'QR Code': qrencode_dep.found(), From 32ca4a2e30ac8d64d26566a86716f4702e08839a Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:02:17 +0100 Subject: [PATCH 05/16] build: add -Wno-unused-parameter --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index bd9c32fd..56e9ad33 100644 --- a/meson.build +++ b/meson.build @@ -62,6 +62,7 @@ cc = meson.get_compiler('c') # Common compiler flags add_project_arguments('-Wno-deprecated-declarations', language: 'c') +add_project_arguments('-Wno-unused-parameter', language: 'c') if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' add_project_arguments('-ggdb3', language: 'c') From e29c41845275f519f788b855d6858ee0bb915ff6 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:03:26 +0100 Subject: [PATCH 06/16] build: simplify platform detection --- meson.build | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/meson.build b/meson.build index 56e9ad33..ad40ff48 100644 --- a/meson.build +++ b/meson.build @@ -10,21 +10,14 @@ project('profanity', 'c', # Determine platform host_system = host_machine.system() -platform = 'unknown' - -if host_system == 'freebsd' - platform = 'freebsd' -elif host_system == 'netbsd' - platform = 'netbsd' -elif host_system == 'openbsd' - platform = 'openbsd' -elif host_system == 'darwin' - platform = 'osx' -elif host_system == 'cygwin' - platform = 'cygwin' -else - platform = 'nix' -endif +platform_map = { + 'freebsd': 'freebsd', + 'netbsd': 'netbsd', + 'openbsd': 'openbsd', + 'darwin': 'osx', + 'cygwin': 'cygwin', +} +platform = platform_map.get(host_system, 'nix') # Configuration data conf_data = configuration_data() From 275afd40d5c33a693627a06fd5beb7aa63b76cb9 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:10:52 +0100 Subject: [PATCH 07/16] build: remove specific libstrophe build check For autotools this was added in: 75bb00368f4f8c0a3e5a7da8aa347f86f07fc53a Regarding: https://github.com/profanity-im/profanity/issues/1334 I think libstrophe is rather common now and should be treated like all the other dependencies anyways. So I'll remove this from the meson files at least. Since my goal is to have a cleaner build system. --- meson.build | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/meson.build b/meson.build index ad40ff48..c598972d 100644 --- a/meson.build +++ b/meson.build @@ -83,17 +83,6 @@ thread_dep = dependency('threads') math_dep = cc.find_library('m', required: true) libstrophe_dep = dependency('libstrophe', version: '>= 0.12.3') -# Check if libstrophe works -if not cc.links(''' - #include - int main() { - xmpp_initialize(); - return 0; - } - ''', dependencies: libstrophe_dep) - error('libstrophe is broken') -endif - # Check for XMPP_CERT_PUBKEY_FINGERPRINT_SHA256 support if cc.links(''' #include From d8211584f6b1dc8ddc121cca0c97bddc36d49d01 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:28:59 +0100 Subject: [PATCH 08/16] build: only check for ncurses{w} In out autotools build we check for all kinds of curses and their support for wide character. Let's focus on more modern systems until someone complains. --- meson.build | 63 +++++++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 43 deletions(-) diff --git a/meson.build b/meson.build index c598972d..67d61a62 100644 --- a/meson.build +++ b/meson.build @@ -94,52 +94,29 @@ if cc.links(''' conf_data.set('HAVE_XMPP_CERT_PUBKEY_FINGERPRINT_SHA256', 1) endif -# Curses/ncurses library -ncursesw_dep = dependency('ncursesw', required: false) -ncurses_dep = dependency('ncurses', required: false) - -if ncursesw_dep.found() - curses_dep = ncursesw_dep - curses_name = 'ncursesw' -elif ncurses_dep.found() - curses_dep = ncurses_dep - curses_name = 'ncurses' -else - curses_dep = cc.find_library('ncursesw', required: false) - if curses_dep.found() - curses_name = 'ncursesw' - else - curses_dep = cc.find_library('ncurses', required: false) - if curses_dep.found() - curses_name = 'ncurses' - else - curses_dep = cc.find_library('curses', required: true) - curses_name = 'curses' - endif +# ncurses +curses_dep = disabler() +foreach lib : ['ncursesw', 'ncurses'] + d = dependency(lib, required: false) + if not d.found() + d = cc.find_library(lib, required: false) endif + + if d.found() + curses_dep = d + break + endif +endforeach +if not curses_dep.found() + error('ncursesw/ncurses library not found') endif -# Check for wide character support -if not cc.links(''' - void wget_wch(void); - int main() { - wget_wch(); - return 0; - } - ''', dependencies: curses_dep) - error('ncurses does not support wide characters') -endif - -# Check for ncurses headers -if cc.has_header('ncursesw/ncurses.h') - conf_data.set('HAVE_NCURSESW_NCURSES_H', 1) -endif -if cc.has_header('ncurses.h') - conf_data.set('HAVE_NCURSES_H', 1) -endif -if cc.has_header('curses.h') - conf_data.set('HAVE_CURSES_H', 1) -endif +# Check for ncursesw/ncurses.h, Arch linux uses ncurses.h for ncursesw +foreach h : ['ncursesw/ncurses.h', 'ncurses.h'] + if cc.has_header(h) + conf_data.set('HAVE_@0@'.format(h.underscorify().to_upper()), 1) + endif +endforeach # Readline: # we need to declare the variable before From af0dfcce70a2a435fe37701450d050cf53b0c702 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:32:27 +0100 Subject: [PATCH 09/16] build: fixup release/debug mistake --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 67d61a62..473803ec 100644 --- a/meson.build +++ b/meson.build @@ -575,7 +575,7 @@ endif main_source = files('src/main.c') # Generate git version header if in development -if get_option('buildtype') == 'release' or get_option('buildtype') == 'debugoptimized' +if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' git_branch = run_command('git', 'rev-parse', '--symbolic-full-name', '--abbrev-ref', 'HEAD', check: false).stdout().strip() git_revision = run_command('git', 'log', '--pretty=format:%h', '-n', '1', From 886080dc9b3791684ee56c473b275cc7314e0531 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 13:35:55 +0100 Subject: [PATCH 10/16] build: simplify readline detection --- meson.build | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/meson.build b/meson.build index 473803ec..52bd4e98 100644 --- a/meson.build +++ b/meson.build @@ -122,40 +122,25 @@ endforeach # we need to declare the variable before # using it in the conditional branch. # Later the required is set correctly. -readline_dep = dependency('', required: false) +readline_dep = dependency('readline', required: false) -if platform == 'osx' - brew = find_program('brew', required: false, dirs: ['/opt/homebrew/bin', '/usr/local/bin']) - - if brew.found() - readline_prefix_cmd = run_command(brew, '--prefix', 'readline', check: false) - if readline_prefix_cmd.returncode() == 0 - readline_prefix = readline_prefix_cmd.stdout().strip() - else - readline_prefix = '/usr/local' - endif - else - if run_command('test', '-f', '/opt/local/lib/libreadline.dylib', check: false).returncode() == 0 - readline_prefix = '/opt/local' - else - readline_prefix = '/usr/local' +if not readline_dep.found() + if platform == 'osx' + # brew prefix + brew = find_program('brew', required: false) + if brew.found() + prefix = run_command(brew, '--prefix', 'readline', check: false).stdout().strip() + readline_dep = cc.find_library('readline', dirs: [prefix / 'lib'], required: true) + add_project_arguments('-I' + prefix / 'include', language: 'c') endif + elif platform == 'openbsd' + # ereadline alias + readline_dep = cc.find_library('ereadline', dirs: ['/usr/local/lib'], required: false) endif - - readline_dep = cc.find_library('readline', - dirs: [readline_prefix / 'lib'], - required: true) - add_project_arguments('-I' + readline_prefix / 'include', language: 'c') -elif platform == 'openbsd' - if run_command('test', '-d', '/usr/local/include/ereadline', check: false).returncode() == 0 - readline_dep = cc.find_library('ereadline', - dirs: ['/usr/local/lib'], - required: true) - add_project_arguments('-I/usr/local/include/ereadline', language: 'c') - else - readline_dep = cc.find_library('readline', required: true) - endif -else +endif + +# regular +if not readline_dep.found() readline_dep = cc.find_library('readline', required: true) endif From d91ff7eb20ca03966e50710fb8c314ecacc49b6b Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 14:19:10 +0100 Subject: [PATCH 11/16] build: features need to be enabled For meson we dont just check for the presence of a dependency and then auto enable it. Users must enable features explicit. This helps with having deterministic results. Also remove the general `plugins` switch which was used to enable/disable both python and c plugins. Users can just use those switches. --- meson.build | 157 +++++++++++++++++----------------------------- meson_options.txt | 82 ++++++++++++------------ 2 files changed, 98 insertions(+), 141 deletions(-) diff --git a/meson.build b/meson.build index 52bd4e98..77a6b8c5 100644 --- a/meson.build +++ b/meson.build @@ -149,18 +149,16 @@ endif libnotify_dep = dependency('', required: false) have_osxnotify = false -if get_option('notifications').enabled() or get_option('notifications').auto() +if get_option('notifications').enabled() if platform == 'osx' - terminal_notifier = find_program('terminal-notifier', required: get_option('notifications')) - if terminal_notifier.found() - have_osxnotify = true - conf_data.set('HAVE_OSXNOTIFY', 1) - endif + terminal_notifier = find_program('terminal-notifier', required: true) + have_osxnotify = true + conf_data.set('HAVE_OSXNOTIFY', 1) elif platform == 'nix' or platform == 'freebsd' - libnotify_dep = dependency('libnotify', required: get_option('notifications')) - if libnotify_dep.found() - conf_data.set('HAVE_LIBNOTIFY', 1) - endif + libnotify_dep = dependency('libnotify', required: true) + conf_data.set('HAVE_LIBNOTIFY', 1) + else + error('Notifications not supported on this platform') endif endif @@ -168,18 +166,15 @@ endif gtk_dep = dependency('', required: false) gtk_version = 'none' -if get_option('icons-and-clipboard').enabled() or get_option('icons-and-clipboard').auto() +if get_option('icons-and-clipboard').enabled() gtk_dep = dependency('gtk+-3.0', version: '>= 3.24.0', required: false) if gtk_dep.found() conf_data.set('HAVE_GTK', 1) gtk_version = gtk_dep.version() else - gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.10', - required: get_option('icons-and-clipboard')) - if gtk_dep.found() - conf_data.set('HAVE_GTK', 1) - gtk_version = gtk_dep.version() - endif + gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.10', required: true) + conf_data.set('HAVE_GTK', 1) + gtk_version = gtk_dep.version() endif endif @@ -188,24 +183,19 @@ endif xscrnsaver_found = false xscrnsaver_dep = [] -if get_option('xscreensaver').enabled() or get_option('xscreensaver').auto() - xss_dep = dependency('xscrnsaver', required: false) - x11_dep = dependency('x11', required: false) - - if xss_dep.found() and x11_dep.found() - xscrnsaver_dep = [xss_dep, x11_dep] - xscrnsaver_found = true # Set our tracker to true - conf_data.set('HAVE_LIBXSS', 1) - elif get_option('xscreensaver').enabled() - error('xscreensaver support requested but xscrnsaver or x11 not found') - endif +if get_option('xscreensaver').enabled() + xss_dep = dependency('xscrnsaver', required: true) + x11_dep = dependency('x11', required: true) + xscrnsaver_dep = [xss_dep, x11_dep] + xscrnsaver_found = true + conf_data.set('HAVE_LIBXSS', 1) endif # Python plugins python_dep = dependency('', required: false) build_python_api = false -if not get_option('plugins').disabled() and not get_option('python-plugins').disabled() +if get_option('python-plugins').enabled() if platform == 'osx' # Handle Python framework on macOS python_framework = get_option('python_framework') @@ -216,36 +206,30 @@ if not get_option('plugins').disabled() and not get_option('python-plugins').dis python_dep = dependency('python-embed', required: false) if not python_dep.found() - python_dep = dependency('python3-embed', required: false) - if python_dep.found() - conf_data.set('PY_IS_PYTHON3', 1) - endif + python_dep = dependency('python3-embed', required: true) + conf_data.set('PY_IS_PYTHON3', 1) endif - if python_dep.found() - build_python_api = true - conf_data.set('HAVE_PYTHON', 1) - elif get_option('python-plugins').enabled() - error('Python plugins enabled but Python not found') - endif + build_python_api = true + conf_data.set('HAVE_PYTHON', 1) endif # C plugins dl_dep = dependency('', required: false) build_c_api = false -if platform != 'cygwin' - if not get_option('plugins').disabled() and not get_option('c-plugins').disabled() - if platform == 'openbsd' or platform == 'freebsd' or platform == 'netbsd' - build_c_api = true - conf_data.set('HAVE_C', 1) - else - dl_dep = cc.find_library('dl', required: get_option('c-plugins')) - if dl_dep.found() - build_c_api = true - conf_data.set('HAVE_C', 1) - endif - endif +if get_option('c-plugins').enabled() + if platform == 'cygwin' + error('C plugins are not supported on Cygwin') + endif + + if platform == 'openbsd' or platform == 'freebsd' or platform == 'netbsd' + build_c_api = true + conf_data.set('HAVE_C', 1) + else + dl_dep = cc.find_library('dl', required: true) + build_c_api = true + conf_data.set('HAVE_C', 1) endif endif @@ -253,45 +237,34 @@ endif gpgme_dep = dependency('', required: false) build_pgp = false -if not get_option('pgp').disabled() - gpgme_dep = cc.find_library('gpgme', required: false) +if get_option('pgp').enabled() + gpgme_dep = cc.find_library('gpgme', required: true) - if gpgme_dep.found() - gpgme_config = find_program('gpgme-config', required: false) - if gpgme_config.found() - gpgme_cflags = run_command(gpgme_config, '--cflags', check: true).stdout().strip() - gpgme_libs = run_command(gpgme_config, '--libs', check: true).stdout().strip() - add_project_arguments(gpgme_cflags.split(), language: 'c') - endif - - build_pgp = true - conf_data.set('HAVE_LIBGPGME', 1) - elif get_option('pgp').enabled() - error('PGP support enabled but libgpgme not found') - endif + gpgme_config = find_program('gpgme-config', required: true) + gpgme_cflags = run_command(gpgme_config, '--cflags', check: true).stdout().strip() + gpgme_libs = run_command(gpgme_config, '--libs', check: true).stdout().strip() + add_project_arguments(gpgme_cflags.split(), language: 'c') + + build_pgp = true + conf_data.set('HAVE_LIBGPGME', 1) endif # OTR support libotr_dep = dependency('', required: false) build_otr = false -if not get_option('otr').disabled() - libotr_dep = dependency('libotr', version: '>= 4.0', required: get_option('otr')) - if libotr_dep.found() - build_otr = true - conf_data.set('HAVE_LIBOTR', 1) - endif +if get_option('otr').enabled() + libotr_dep = dependency('libotr', version: '>= 4.0', required: true) + build_otr = true + conf_data.set('HAVE_LIBOTR', 1) endif # GDK Pixbuf (for avatar scaling) gdk_pixbuf_dep = dependency('', required: false) -if not get_option('gdk-pixbuf').disabled() - gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.4', - required: get_option('gdk-pixbuf')) - if gdk_pixbuf_dep.found() - conf_data.set('HAVE_PIXBUF', 1) - endif +if get_option('gdk-pixbuf').enabled() + gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.4', required: true) + conf_data.set('HAVE_PIXBUF', 1) endif # OMEMO support @@ -299,31 +272,19 @@ libsignal_dep = dependency('', required: false) gcrypt_dep = dependency('', required: false) build_omemo = false -if not get_option('omemo').disabled() - libsignal_dep = dependency('libsignal-protocol-c', version: '>= 2.3.2', required: false) - - if libsignal_dep.found() - gcrypt_dep = dependency('libgcrypt', version: '>= 1.7.0', required: false) - - if gcrypt_dep.found() - build_omemo = true - conf_data.set('HAVE_OMEMO', 1) - elif get_option('omemo').enabled() - error('OMEMO support enabled but libgcrypt >= 1.7.0 not found') - endif - elif get_option('omemo').enabled() - error('OMEMO support enabled but libsignal-protocol-c >= 2.3.2 not found') - endif +if get_option('omemo').enabled() + libsignal_dep = dependency('libsignal-protocol-c', version: '>= 2.3.2', required: true) + gcrypt_dep = dependency('libgcrypt', version: '>= 1.7.0', required: true) + build_omemo = true + conf_data.set('HAVE_OMEMO', 1) endif # QR code support (for OMEMO) qrencode_dep = dependency('', required: false) -if not get_option('omemo-qrcode').disabled() - qrencode_dep = dependency('libqrencode', required: get_option('omemo-qrcode')) - if qrencode_dep.found() - conf_data.set('HAVE_QRENCODE', 1) - endif +if get_option('omemo-qrcode').enabled() + qrencode_dep = dependency('libqrencode', required: true) + conf_data.set('HAVE_QRENCODE', 1) endif # Set installation paths diff --git a/meson_options.txt b/meson_options.txt index dfbf84bf..11ba0d2d 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,51 +1,77 @@ +# Features: option('notifications', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable desktop notifications' ) option('python-plugins', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable Python plugins' ) option('c-plugins', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable C plugins' ) -option('plugins', - type: 'feature', - value: 'auto', - description: 'Enable plugins (both Python and C)' -) - option('otr', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable OTR encryption' ) option('pgp', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable PGP' ) option('omemo', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Enable OMEMO encryption' ) option('xscreensaver', type: 'feature', - value: 'auto', + value: 'disabled', description: 'Use libXScrnSaver to determine idle time' ) +option('icons-and-clipboard', + type: 'feature', + value: 'disabled', + description: 'Enable GTK tray icons and clipboard paste support' +) + +option('gdk-pixbuf', + type: 'feature', + value: 'disabled', + description: 'Enable GDK Pixbuf support to scale avatars before uploading' +) + +option('omemo-qrcode', + type: 'feature', + value: 'disabled', + description: 'Enable ability to display OMEMO QR code' +) + +# Other: +option('python_framework', + type: 'string', + value: '', + description: 'Set base directory for Python Framework (macOS only)' +) + +option('tests', + type: 'boolean', + value: false, + description: 'Build tests' +) + option('install_themes', type: 'boolean', value: true, @@ -57,33 +83,3 @@ option('themes_path', value: '', description: 'Custom path for themes installation (empty for default)' ) - -option('icons-and-clipboard', - type: 'feature', - value: 'auto', - description: 'Enable GTK tray icons and clipboard paste support' -) - -option('gdk-pixbuf', - type: 'feature', - value: 'auto', - description: 'Enable GDK Pixbuf support to scale avatars before uploading' -) - -option('omemo-qrcode', - type: 'feature', - value: 'auto', - description: 'Enable ability to display OMEMO QR code' -) - -option('python_framework', - type: 'string', - value: '', - description: 'Set base directory for Python Framework (macOS only)' -) - -option('tests', - type: 'boolean', - value: false, - description: 'Build tests' -) From 75579c6bf60a7c6f813a46ba5392c6a87ba2bcc0 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 14:31:28 +0100 Subject: [PATCH 12/16] build: simplify adding dependencies We don't actually need to check whether they were found. Meson will just ignore the empty ones. --- meson.build | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/meson.build b/meson.build index 77a6b8c5..28f9bde8 100644 --- a/meson.build +++ b/meson.build @@ -330,48 +330,19 @@ profanity_deps = [ libstrophe_dep, curses_dep, readline_dep, + libnotify_dep, + gtk_dep, + xscrnsaver_dep, + python_dep, + dl_dep, + gpgme_dep, + libotr_dep, + gdk_pixbuf_dep, + libsignal_dep, + gcrypt_dep, + qrencode_dep ] -if libnotify_dep.found() - profanity_deps += libnotify_dep -endif - -if gtk_dep.found() - profanity_deps += gtk_dep -endif - -if xscrnsaver_found - profanity_deps += xscrnsaver_dep -endif - -if python_dep.found() - profanity_deps += python_dep -endif - -if dl_dep.found() - profanity_deps += dl_dep -endif - -if gpgme_dep.found() - profanity_deps += gpgme_dep -endif - -if libotr_dep.found() - profanity_deps += libotr_dep -endif - -if gdk_pixbuf_dep.found() - profanity_deps += gdk_pixbuf_dep -endif - -if libsignal_dep.found() and gcrypt_dep.found() - profanity_deps += [libsignal_dep, gcrypt_dep] -endif - -if qrencode_dep.found() - profanity_deps += qrencode_dep -endif - # Include directories inc = include_directories('.', 'src') From 01c9a51c707807c73900a43eacbb68d0e954c24b Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 14:36:28 +0100 Subject: [PATCH 13/16] build: only support gtk3 for icon and clipboard gtk2 is pretty old now. Let's just focus on gtk3. --- meson.build | 7 ------- 1 file changed, 7 deletions(-) diff --git a/meson.build b/meson.build index 28f9bde8..148c278e 100644 --- a/meson.build +++ b/meson.build @@ -164,17 +164,11 @@ endif # GTK (for icons and clipboard) gtk_dep = dependency('', required: false) -gtk_version = 'none' if get_option('icons-and-clipboard').enabled() gtk_dep = dependency('gtk+-3.0', version: '>= 3.24.0', required: false) if gtk_dep.found() conf_data.set('HAVE_GTK', 1) - gtk_version = gtk_dep.version() - else - gtk_dep = dependency('gtk+-2.0', version: '>= 2.24.10', required: true) - conf_data.set('HAVE_GTK', 1) - gtk_version = gtk_dep.version() endif endif @@ -700,7 +694,6 @@ endif summary({ 'Platform': platform, 'Package status': get_option('buildtype'), - 'GTK version': gtk_version, 'Install themes': get_option('install_themes'), 'Themes path': themes_path, 'Icons path': icons_path, From f6eced0ad09ce44680b82cd27382fe0b9b057d30 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 15:01:51 +0100 Subject: [PATCH 14/16] build: simplify build configuration and remove redundancy Use disabler() for optional dependencies. Extract repeated build type checks into is_debug/is_release variables. Consolidate compiler flags into single add_project_arguments() calls. Simplify dependency list building (Meson auto-ignores disabled deps). Streamline platform checks using 'in' operator. Remove redundant variables (xscrnsaver_found, gtk_version, config_h_inc). Simplify ncurses and header detection with clearer fallback chains. Consolidate install_data() calls for files in same directory. --- meson.build | 352 ++++++++++++++++++++++++---------------------------- 1 file changed, 165 insertions(+), 187 deletions(-) diff --git a/meson.build b/meson.build index 148c278e..5920f6cd 100644 --- a/meson.build +++ b/meson.build @@ -26,13 +26,13 @@ conf_data.set_quoted('PACKAGE_VERSION', meson.project_version()) conf_data.set_quoted('PACKAGE_BUGREPORT', 'jubalh@iodoru.org') conf_data.set_quoted('PACKAGE_URL', 'https://profanity-im.github.io/') -# possible options from meson: +# Possible options from meson: # debug, debugoptimized, release, plain -if get_option('buildtype') == 'release' - conf_data.set_quoted('PACKAGE_STATUS', 'release') -else - conf_data.set_quoted('PACKAGE_STATUS', 'development') -endif +# Build type configuration +is_release = get_option('buildtype') == 'release' +is_debug = get_option('buildtype') in ['debug', 'debugoptimized'] + +conf_data.set_quoted('PACKAGE_STATUS', is_release ? 'release' : 'development') if platform == 'cygwin' conf_data.set('PLATFORM_CYGWIN', 1) @@ -43,7 +43,7 @@ if platform == 'osx' endif # Get git version if in development -if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' +if is_debug git = find_program('git', required: false) if git.found() conf_data.set('HAVE_GIT_VERSION', 1) @@ -54,14 +54,16 @@ endif cc = meson.get_compiler('c') # Common compiler flags -add_project_arguments('-Wno-deprecated-declarations', language: 'c') -add_project_arguments('-Wno-unused-parameter', language: 'c') +add_project_arguments([ + '-Wno-deprecated-declarations', + '-Wno-unused-parameter', +], language: 'c') -if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' - add_project_arguments('-ggdb3', language: 'c') - add_project_arguments('-Wunused', language: 'c') - #Disabled for now due so we can build - #add_project_arguments('-Werror', language: 'c') +if is_debug + add_project_arguments([ + '-ggdb3', + '-Wunused', + ], language: 'c') endif if platform == 'osx' @@ -80,7 +82,7 @@ gio_dep = dependency('gio-2.0') curl_dep = dependency('libcurl', version: '>= 7.62.0') sqlite_dep = dependency('sqlite3', version: '>= 3.22.0') thread_dep = dependency('threads') -math_dep = cc.find_library('m', required: true) +math_dep = cc.find_library('m') libstrophe_dep = dependency('libstrophe', version: '>= 0.12.3') # Check for XMPP_CERT_PUBKEY_FINGERPRINT_SHA256 support @@ -95,66 +97,72 @@ if cc.links(''' endif # ncurses -curses_dep = disabler() -foreach lib : ['ncursesw', 'ncurses'] - d = dependency(lib, required: false) - if not d.found() - d = cc.find_library(lib, required: false) - endif - - if d.found() - curses_dep = d - break - endif -endforeach +curses_dep = dependency('ncursesw', required: false) if not curses_dep.found() - error('ncursesw/ncurses library not found') + curses_dep = dependency('ncurses', required: false) +endif +if not curses_dep.found() + curses_dep = cc.find_library('ncursesw', required: false) +endif +if not curses_dep.found() + curses_dep = cc.find_library('ncurses', required: true) endif -# Check for ncursesw/ncurses.h, Arch linux uses ncurses.h for ncursesw -foreach h : ['ncursesw/ncurses.h', 'ncurses.h'] - if cc.has_header(h) - conf_data.set('HAVE_@0@'.format(h.underscorify().to_upper()), 1) - endif -endforeach +# Check for ncursesw/ncurses.h, Arch Linux uses ncurses.h for ncursesw +if cc.has_header('ncursesw/ncurses.h') + conf_data.set('HAVE_NCURSESW_NCURSES_H', 1) +elif cc.has_header('ncurses.h') + conf_data.set('HAVE_NCURSES_H', 1) +endif -# Readline: -# we need to declare the variable before -# using it in the conditional branch. -# Later the required is set correctly. +# Readline readline_dep = dependency('readline', required: false) -if not readline_dep.found() - if platform == 'osx' - # brew prefix - brew = find_program('brew', required: false) - if brew.found() - prefix = run_command(brew, '--prefix', 'readline', check: false).stdout().strip() - readline_dep = cc.find_library('readline', dirs: [prefix / 'lib'], required: true) - add_project_arguments('-I' + prefix / 'include', language: 'c') - endif - elif platform == 'openbsd' - # ereadline alias - readline_dep = cc.find_library('ereadline', dirs: ['/usr/local/lib'], required: false) +if not readline_dep.found() and platform == 'osx' + brew = find_program('brew', required: false) + if brew.found() + prefix = run_command(brew, '--prefix', 'readline', check: false).stdout().strip() + readline_dep = cc.find_library('readline', dirs: [prefix / 'lib'], required: true) + add_project_arguments('-I' + prefix / 'include', language: 'c') endif endif -# regular +if not readline_dep.found() and platform == 'openbsd' + readline_dep = cc.find_library('ereadline', dirs: ['/usr/local/lib'], required: false) +endif + if not readline_dep.found() readline_dep = cc.find_library('readline', required: true) endif -# Optional dependencies: -# Notifications -libnotify_dep = dependency('', required: false) +# Optional dependencies have_osxnotify = false +libnotify_dep = disabler() +gtk_dep = disabler() +xscrnsaver_dep = [] +python_dep = disabler() +dl_dep = disabler() +gpgme_dep = disabler() +libotr_dep = disabler() +gdk_pixbuf_dep = disabler() +libsignal_dep = disabler() +gcrypt_dep = disabler() +qrencode_dep = disabler() +# Build flags +build_python_api = false +build_c_api = false +build_pgp = false +build_otr = false +build_omemo = false + +# Notifications if get_option('notifications').enabled() if platform == 'osx' terminal_notifier = find_program('terminal-notifier', required: true) have_osxnotify = true conf_data.set('HAVE_OSXNOTIFY', 1) - elif platform == 'nix' or platform == 'freebsd' + elif platform in ['nix', 'freebsd'] libnotify_dep = dependency('libnotify', required: true) conf_data.set('HAVE_LIBNOTIFY', 1) else @@ -163,44 +171,26 @@ if get_option('notifications').enabled() endif # GTK (for icons and clipboard) -gtk_dep = dependency('', required: false) - if get_option('icons-and-clipboard').enabled() - gtk_dep = dependency('gtk+-3.0', version: '>= 3.24.0', required: false) - if gtk_dep.found() - conf_data.set('HAVE_GTK', 1) - endif + gtk_dep = dependency('gtk+-3.0', version: '>= 3.24.0', required: true) + conf_data.set('HAVE_GTK', 1) endif # XScreenSaver -# We use this variable because .found() will later not work on a list -xscrnsaver_found = false -xscrnsaver_dep = [] - if get_option('xscreensaver').enabled() - xss_dep = dependency('xscrnsaver', required: true) - x11_dep = dependency('x11', required: true) - xscrnsaver_dep = [xss_dep, x11_dep] - xscrnsaver_found = true + xscrnsaver_dep = [ + dependency('xscrnsaver', required: true), + dependency('x11', required: true) + ] conf_data.set('HAVE_LIBXSS', 1) endif # Python plugins -python_dep = dependency('', required: false) -build_python_api = false - if get_option('python-plugins').enabled() - if platform == 'osx' - # Handle Python framework on macOS - python_framework = get_option('python_framework') - if python_framework == '' - python_framework = '/Library/Frameworks/Python.framework' - endif - endif - - python_dep = dependency('python-embed', required: false) + python_dep = dependency('python3-embed', required: false) if not python_dep.found() - python_dep = dependency('python3-embed', required: true) + python_dep = dependency('python-embed', required: true) + else conf_data.set('PY_IS_PYTHON3', 1) endif @@ -209,34 +199,24 @@ if get_option('python-plugins').enabled() endif # C plugins -dl_dep = dependency('', required: false) -build_c_api = false - if get_option('c-plugins').enabled() if platform == 'cygwin' error('C plugins are not supported on Cygwin') endif - if platform == 'openbsd' or platform == 'freebsd' or platform == 'netbsd' - build_c_api = true - conf_data.set('HAVE_C', 1) - else + if platform not in ['openbsd', 'freebsd', 'netbsd'] dl_dep = cc.find_library('dl', required: true) - build_c_api = true - conf_data.set('HAVE_C', 1) endif + + build_c_api = true + conf_data.set('HAVE_C', 1) endif # PGP support -gpgme_dep = dependency('', required: false) -build_pgp = false - if get_option('pgp').enabled() gpgme_dep = cc.find_library('gpgme', required: true) - gpgme_config = find_program('gpgme-config', required: true) gpgme_cflags = run_command(gpgme_config, '--cflags', check: true).stdout().strip() - gpgme_libs = run_command(gpgme_config, '--libs', check: true).stdout().strip() add_project_arguments(gpgme_cflags.split(), language: 'c') build_pgp = true @@ -244,9 +224,6 @@ if get_option('pgp').enabled() endif # OTR support -libotr_dep = dependency('', required: false) -build_otr = false - if get_option('otr').enabled() libotr_dep = dependency('libotr', version: '>= 4.0', required: true) build_otr = true @@ -254,18 +231,12 @@ if get_option('otr').enabled() endif # GDK Pixbuf (for avatar scaling) -gdk_pixbuf_dep = dependency('', required: false) - if get_option('gdk-pixbuf').enabled() gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.4', required: true) conf_data.set('HAVE_PIXBUF', 1) endif # OMEMO support -libsignal_dep = dependency('', required: false) -gcrypt_dep = dependency('', required: false) -build_omemo = false - if get_option('omemo').enabled() libsignal_dep = dependency('libsignal-protocol-c', version: '>= 2.3.2', required: true) gcrypt_dep = dependency('libgcrypt', version: '>= 1.7.0', required: true) @@ -274,8 +245,6 @@ if get_option('omemo').enabled() endif # QR code support (for OMEMO) -qrencode_dep = dependency('', required: false) - if get_option('omemo-qrcode').enabled() qrencode_dep = dependency('libqrencode', required: true) conf_data.set('HAVE_QRENCODE', 1) @@ -307,12 +276,8 @@ endforeach config_h = configure_file( output: 'config.h', configuration: conf_data, - install: false, ) -# Make config.h available by adding build directory to include path -config_h_inc = include_directories('.') - # Build dependencies list profanity_deps = [ glib_dep, @@ -324,19 +289,53 @@ profanity_deps = [ libstrophe_dep, curses_dep, readline_dep, - libnotify_dep, - gtk_dep, - xscrnsaver_dep, - python_dep, - dl_dep, - gpgme_dep, - libotr_dep, - gdk_pixbuf_dep, - libsignal_dep, - gcrypt_dep, - qrencode_dep ] +# Add optional dependencies only if found +if libnotify_dep.found() + profanity_deps += libnotify_dep +endif + +if gtk_dep.found() + profanity_deps += gtk_dep +endif + +if xscrnsaver_dep.length() > 0 + profanity_deps += xscrnsaver_dep +endif + +if python_dep.found() + profanity_deps += python_dep +endif + +if dl_dep.found() + profanity_deps += dl_dep +endif + +if gpgme_dep.found() + profanity_deps += gpgme_dep +endif + +if libotr_dep.found() + profanity_deps += libotr_dep +endif + +if gdk_pixbuf_dep.found() + profanity_deps += gdk_pixbuf_dep +endif + +if libsignal_dep.found() + profanity_deps += libsignal_dep +endif + +if gcrypt_dep.found() + profanity_deps += gcrypt_dep +endif + +if qrencode_dep.found() + profanity_deps += qrencode_dep +endif + # Include directories inc = include_directories('.', 'src') @@ -420,73 +419,54 @@ core_sources = files( 'src/plugins/disco.c', ) -# Python plugin sources -python_sources = files( - 'src/plugins/python_plugins.c', - 'src/plugins/python_api.c', -) - -# C plugin sources -c_sources = files( - 'src/plugins/c_plugins.c', - 'src/plugins/c_api.c', -) - -# PGP sources -pgp_sources = files( - 'src/pgp/gpg.c', - 'src/pgp/ox.c', -) - -# OTR sources -otr_sources = files( - 'src/otr/otrlibv4.c', - 'src/otr/otr.c', -) - -# OMEMO sources -omemo_sources = files( - 'src/omemo/omemo.c', - 'src/omemo/crypto.c', - 'src/omemo/store.c', - 'src/xmpp/omemo.c', - 'src/tools/aesgcm_download.c', -) - # Build the final source list profanity_sources = core_sources -# Add tray support only when GTK is available -# The calls to tray functions in profanity.c are already conditional on HAVE_GTK +# Add conditional sources if gtk_dep.found() profanity_sources += files('src/ui/tray.c') endif if build_python_api - profanity_sources += python_sources + profanity_sources += files( + 'src/plugins/python_plugins.c', + 'src/plugins/python_api.c', + ) endif if build_c_api - profanity_sources += c_sources + profanity_sources += files( + 'src/plugins/c_plugins.c', + 'src/plugins/c_api.c', + ) endif if build_pgp - profanity_sources += pgp_sources + profanity_sources += files( + 'src/pgp/gpg.c', + 'src/pgp/ox.c', + ) endif if build_otr - profanity_sources += otr_sources + profanity_sources += files( + 'src/otr/otrlibv4.c', + 'src/otr/otr.c', + ) endif if build_omemo - profanity_sources += omemo_sources + profanity_sources += files( + 'src/omemo/omemo.c', + 'src/omemo/crypto.c', + 'src/omemo/store.c', + 'src/xmpp/omemo.c', + 'src/tools/aesgcm_download.c', + ) endif -# Main source file -main_source = files('src/main.c') - # Generate git version header if in development -if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimized' +if is_debug git_branch = run_command('git', 'rev-parse', '--symbolic-full-name', '--abbrev-ref', 'HEAD', check: false).stdout().strip() git_revision = run_command('git', 'log', '--pretty=format:%h', '-n', '1', @@ -500,14 +480,15 @@ if get_option('buildtype') == 'debug' or get_option('buildtype') == 'debugoptimi input: 'src/gitversion.h.in', output: 'gitversion.h', configuration: git_version_conf, - install: false, ) endif # Build the executable profanity_exe = executable( 'profanity', - profanity_sources + main_source + [config_h], + profanity_sources, + files('src/main.c'), + config_h, dependencies: profanity_deps, include_directories: inc, install: true, @@ -525,7 +506,6 @@ if build_c_api version: '0.0.0', ) - # Install profapi.h header install_headers('src/plugins/profapi.h') endif @@ -544,19 +524,17 @@ install_subdir('icons', ) # Install man pages - man_pages = run_command('find', 'docs', '-name', 'profanity*.1', '-type', 'f', +man_pages = run_command('find', 'docs', '-name', 'profanity*.1', '-type', 'f', check: true).stdout().strip().split('\n') if man_pages.length() > 0 and man_pages[0] != '' install_man(man_pages) endif -# Install example config -install_data('profrc.example', - install_dir: get_option('datadir') / 'doc' / meson.project_name(), -) - -install_data('theme_template', +# Install example config and theme template +install_data( + 'profrc.example', + 'theme_template', install_dir: get_option('datadir') / 'doc' / meson.project_name(), ) @@ -564,7 +542,6 @@ install_data('theme_template', if get_option('tests') cmocka_dep = dependency('cmocka', required: false) if cmocka_dep.found() - # Unit test sources unittest_sources = files( 'src/xmpp/contact.c', 'src/common.c', @@ -650,11 +627,17 @@ if get_option('tests') ) if build_python_api - unittest_sources += python_sources + unittest_sources += files( + 'src/plugins/python_plugins.c', + 'src/plugins/python_api.c', + ) endif if build_c_api - unittest_sources += c_sources + unittest_sources += files( + 'src/plugins/c_plugins.c', + 'src/plugins/c_api.c', + ) endif if build_pgp @@ -665,18 +648,13 @@ if get_option('tests') endif if build_otr - unittest_sources += files( - 'tests/unittests/otr/stub_otr.c', - ) + unittest_sources += files('tests/unittests/otr/stub_otr.c') endif if build_omemo - unittest_sources += files( - 'tests/unittests/omemo/stub_omemo.c', - ) + unittest_sources += files('tests/unittests/omemo/stub_omemo.c') endif - # Build unit tests unittests = executable( 'unittests', unittest_sources, @@ -708,7 +686,7 @@ summary({ 'OTR': build_otr, 'PGP': build_pgp, 'OMEMO': build_omemo, - 'XScreenSaver': xscrnsaver_found, + 'XScreenSaver': xscrnsaver_dep.length() > 0, 'GTK': gtk_dep.found(), 'GDK Pixbuf': gdk_pixbuf_dep.found(), 'QR Code': qrencode_dep.found(), From 57d18d44c8d6c5c89627ccba119152ac5dcc9d76 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 15:33:44 +0100 Subject: [PATCH 15/16] build: only check for gpgme via pkg-config Most likely we don't need to check for gpgme-config on most modern systems. --- meson.build | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 5920f6cd..fef3652b 100644 --- a/meson.build +++ b/meson.build @@ -214,10 +214,7 @@ endif # PGP support if get_option('pgp').enabled() - gpgme_dep = cc.find_library('gpgme', required: true) - gpgme_config = find_program('gpgme-config', required: true) - gpgme_cflags = run_command(gpgme_config, '--cflags', check: true).stdout().strip() - add_project_arguments(gpgme_cflags.split(), language: 'c') + gpgme_dep = dependency('gpgme', required: false) build_pgp = true conf_data.set('HAVE_LIBGPGME', 1) From 4223105746f03de5ef2c00f8f3118b696f7cf011 Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 5 Feb 2026 15:36:54 +0100 Subject: [PATCH 16/16] ci: add ci job for building with meson This probably could be nicer. But since we will drop one in the future it's not really a priority to make this pretty. --- .github/workflows/main.yml | 15 +++++++++ Dockerfile.debian | 5 ++- ci-meson-build.sh | 65 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100755 ci-meson-build.sh diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66cf02bb..3fe07592 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,6 +26,21 @@ jobs: docker build -f Dockerfile.${{ matrix.flavor }} -t profanity . docker run profanity ./ci-build.sh + linux-meson: + runs-on: ubuntu-latest + + strategy: + matrix: + flavor: [debian] + + name: Linux-meson + steps: + - uses: actions/checkout@v2 + - name: Run tests + run: | + docker build -f Dockerfile.${{ matrix.flavor }} -t profanity . + docker run profanity ./ci-meson-build.sh + code-style: runs-on: ubuntu-22.04 name: Check coding style diff --git a/Dockerfile.debian b/Dockerfile.debian index 114aec28..f11c82ba 100644 --- a/Dockerfile.debian +++ b/Dockerfile.debian @@ -5,6 +5,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ autoconf \ autoconf-archive \ automake \ + cmake \ expect \ gcc \ git \ @@ -13,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libgcrypt-dev \ libglib2.0-dev \ libgpgme11-dev \ - libgtk2.0-dev \ + libgtk-3-dev \ libmicrohttpd-dev \ libncursesw5-dev \ libnotify-dev \ @@ -24,6 +25,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libtool \ libxss-dev \ make \ + meson \ + ninja-build \ pkg-config \ python3-dev \ python-dev-is-python3 \ diff --git a/ci-meson-build.sh b/ci-meson-build.sh new file mode 100755 index 00000000..0e9ac495 --- /dev/null +++ b/ci-meson-build.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +# Exit on error +set -e + +error_handler() +{ + ERR_CODE=$? + echo + echo "Error ${ERR_CODE} with command '${BASH_COMMAND}' on line ${BASH_LINENO[0]}. Exiting." + # Meson logs are stored in the build directory + if [ -f "build/meson-logs/testlog.txt" ]; then + echo "--- Meson Test Log ---" + cat build/meson-logs/testlog.txt + fi + exit ${ERR_CODE} +} + +trap error_handler ERR + +tests=( + "-Dnotifications=enabled -Dicons-and-clipboard=enabled -Dotr=enabled -Dpgp=enabled -Domemo=enabled -Dc-plugins=enabled -Dpython-plugins=enabled -Dxscreensaver=enabled -Domemo-qrcode=enabled -Dgdk-pixbuf=enabled" + "" + "-Dnotifications=disabled" + "-Dicons-and-clipboard=disabled" + "-Dotr=disabled" + "-Dpgp=disabled" + "-Domemo=disabled -Domemo-qrcode=disabled" + "-Dpgp=disabled -Dotr=disabled" + "-Dpgp=disabled -Dotr=disabled -Domemo=disabled" + "-Dpython-plugins=disabled" + "-Dc-plugins=disabled" + "-Dc-plugins=disabled -Dpython-plugins=disabled" + "-Dxscreensaver=disabled" + "-Dgdk-pixbuf=disabled" +) + +# Run Valgrind check (Only on Linux, on first/full feature set) +if [[ "$(uname | tr '[:upper:]' '[:lower:]')" == linux* ]]; then + echo "--> Running Valgrind check with full features" + + meson setup build_valgrind ${tests[0]} -Dtests=true + meson compile -C build_valgrind + + meson test -C build_valgrind --print-errorlogs --wrap=valgrind || echo "Valgrind issues detected" + + rm -rf build_valgrind +fi + +# Iterate through all feature combinations +for features in "${tests[@]}" +do + echo "----------------------------------------------------" + echo "--> Building with: ${features}" + echo "----------------------------------------------------" + + rm -rf build_run + + meson setup build_run ${features} -Dtests=true + meson compile -C build_run + + meson test -C build_run --print-errorlogs + + ./build_run/profanity -v +done