project('pacman', 'c', version : '5.1.0', license : 'GPLv2+', default_options : [ 'c_std=gnu99', 'prefix=/usr', 'sysconfdir=/etc', 'localstatedir=/var', ], meson_version : '>= 0.51') libalpm_version = '11.0.1' cc = meson.get_compiler('c') # commandline options PREFIX = get_option('prefix') DATAROOTDIR = join_paths(PREFIX, get_option('datarootdir')) SYSCONFDIR = join_paths(PREFIX, get_option('sysconfdir')) LOCALSTATEDIR = join_paths(PREFIX, get_option('localstatedir')) LOCALEDIR = join_paths(PREFIX, get_option('localedir')) ROOTDIR = get_option('root-dir') BINDIR = join_paths(PREFIX, get_option('bindir')) MANDIR = join_paths(PREFIX, get_option('mandir')) BUILDSCRIPT = get_option('buildscript') LIBMAKEPKGDIR = join_paths(PREFIX, DATAROOTDIR, 'makepkg') PKGDATADIR = join_paths(PREFIX, DATAROOTDIR, meson.project_name()) PYTHON = import('python').find_installation('python3') M4 = find_program('m4') SED = find_program('sed') DU = find_program('du') LDCONFIG = get_option('ldconfig') MESON_MAKE_SYMLINK = join_paths(meson.source_root(), 'build-aux/meson-make-symlink.sh') MESON_INSTALL_SCRIPT = join_paths(meson.source_root(), 'build-aux/meson-install-script.sh') BASH = find_program('bash4', 'bash') if BASH.found() bash_version = run_command(BASH, '-c', 'IFS=.; echo "${BASH_VERSINFO[*]:0:3}"').stdout() have_bash = bash_version.version_compare('>= 4.4.0') endif if not have_bash error('bash >= 4.4.0 is required for pacman scripts.') endif bashcompletion = dependency('bash-completion', required : false) if bashcompletion.found() BASHCOMPDIR = bashcompletion.get_pkgconfig_variable('completionsdir') else BASHCOMPDIR = join_paths(DATAROOTDIR, 'bash-completion/completions') endif if get_option('use-git-version') PACKAGE_VERSION = run_command( find_program('git'), 'describe', '--abbrev=4', '--dirty').stdout().strip().strip('v') else PACKAGE_VERSION = meson.project_version() endif conf = configuration_data() conf.set('_GNU_SOURCE', true) conf.set_quoted('PACKAGE', meson.project_name()) conf.set_quoted('PACKAGE_VERSION', PACKAGE_VERSION) conf.set_quoted('LOCALEDIR', LOCALEDIR) conf.set_quoted('SCRIPTLET_SHELL', get_option('scriptlet-shell')) conf.set_quoted('LDCONFIG', LDCONFIG) conf.set_quoted('LIB_VERSION', meson.project_version()) conf.set_quoted('SYSHOOKDIR', join_paths(DATAROOTDIR, 'libalpm/hooks/')) conf.set_quoted('CONFFILE', join_paths(SYSCONFDIR, 'pacman.conf')) conf.set_quoted('DBPATH', join_paths(LOCALSTATEDIR, 'lib/pacman/')) conf.set_quoted('GPGDIR', join_paths(SYSCONFDIR, 'pacman.d/gnupg/')) conf.set_quoted('LOGFILE', join_paths(LOCALSTATEDIR, 'log/pacman.log')) conf.set_quoted('CACHEDIR', join_paths(LOCALSTATEDIR, 'cache/pacman/pkg/')) conf.set_quoted('HOOKDIR', join_paths(SYSCONFDIR, 'pacman.d/hooks/')) conf.set_quoted('ROOTDIR', ROOTDIR) if get_option('i18n') if not cc.has_function('ngettext') error('ngettext not found but NLS support requested') endif conf.set('ENABLE_NLS', 1) endif # dependencies libarchive = dependency('libarchive', version : '>=3.0.0', static : get_option('buildstatic')) libcurl = dependency('libcurl', version : '>=7.32.0', required : get_option('curl'), static : get_option('buildstatic')) conf.set('HAVE_LIBCURL', libcurl.found()) want_gpgme = get_option('gpgme') gpgme = dependency('gpgme', required : false, static : get_option('buildstatic')) # gpgme recently began providing a pkg-config file. Create a fake dependency # object if it cannot be found, by manually searching for libs. if not want_gpgme.disabled() and not gpgme.found() gpgme_config = find_program('gpgme-config', required : want_gpgme) if gpgme_config.found() gpgme_version = run_command(gpgme_config, '--version').stdout().strip() needed_gpgme_version = '>=1.3.0' if gpgme_version.version_compare(needed_gpgme_version) gpgme_libs = [ cc.find_library('gpgme', dirs : [get_option('gpgme-libdir')]), cc.find_library('gpg-error', dirs : [get_option('gpgme-libdir')]), cc.find_library('assuan', dirs : [get_option('gpgme-libdir')]), ] gpgme = declare_dependency(dependencies : gpgme_libs) endif endif endif conf.set('HAVE_LIBGPGME', gpgme.found()) if want_gpgme.enabled() and not conf.get('HAVE_LIBGPGME') error('gpgme @0@ is needed for GPG signature support'.format(needed_gpgme_version)) endif want_crypto = get_option('crypto') if want_crypto == 'openssl' libcrypto = dependency('libcrypto', static : get_option('buildstatic'), not_found_message : 'openssl support requested but not found') crypto_provider = libcrypto conf.set10('HAVE_LIBSSL', true) elif want_crypto == 'nettle' libnettle = dependency('nettle', static : get_option('buildstatic'), not_found_message : 'nettle support requested but not found') crypto_provider = libnettle conf.set10('HAVE_LIBNETTLE', true) else error('unhandled crypto value @0@'.format(want_crypto)) endif foreach header : [ 'mntent.h', 'sys/mnttab.h', 'sys/mount.h', 'sys/param.h', 'sys/statvfs.h', 'sys/types.h', 'sys/ucred.h', 'termios.h', ] if cc.has_header(header) conf.set('HAVE_' + header.underscorify().to_upper(), true) endif endforeach foreach sym : [ 'dup2', 'fork', 'getcwd', 'getmntent', 'getmntinfo', 'gettimeofday', 'memmove', 'memset', 'mkdir', 'realpath', 'regcomp', 'rmdir', 'setenv', 'setlocale', 'strcasecmp', 'strchr', 'strcspn', 'strdup', 'strerror', 'strndup', 'strnlen', 'strnlen', 'strrchr', 'strsep', 'strsep', 'strstr', 'strtol', 'swprintf', 'tcflush', 'tcflush', 'uname', 'wcwidth', ] have = cc.has_function(sym, args : '-D_GNU_SOURCE') conf.set10('HAVE_' + sym.to_upper(), have) endforeach foreach member : [ ['struct stat', 'st_blksize', '''#include '''], ['struct statvfs', 'f_flag', '''#include '''], ['struct statfs', 'f_flags', '''#include #include '''], ] have = cc.has_member(member[0], member[1], prefix : member[2]) conf.set('HAVE_' + '_'.join([member[0], member[1]]).underscorify().to_upper(), have) endforeach if conf.has('HAVE_STRUCT_STATVFS_F_FLAG') conf.set('FSSTATSTYPE', 'struct statvfs') elif conf.has('HAVE_STRUCT_STATFS_F_FLAGS') conf.set('FSSTATSTYPE', 'struct statfs') endif if get_option('buildtype').startswith('debug') extra_cflags = [ '-Wcast-align', '-Wclobbered', '-Wempty-body', '-Wfloat-equal', '-Wformat-nonliteral', '-Wformat-security', '-Wignored-qualifiers', '-Wimplicit-fallthrough', '-Winit-self', '-Wlogical-op', '-Wmissing-declarations', '-Wmissing-field-initializers', '-Wmissing-parameter-type', '-Wmissing-prototypes', '-Wold-style-declaration', '-Woverride-init', '-Wpointer-arith', '-Wredundant-decls', '-Wshadow', '-Wsign-compare', '-Wstrict-aliasing', '-Wstrict-overflow=5', '-Wstrict-prototypes', '-Wtype-limits', '-Wuninitialized', '-Wunused-but-set-parameter', '-Wunused-parameter', '-Wwrite-strings', ] add_project_arguments(cc.get_supported_arguments(extra_cflags), language : 'c') conf.set('PACMAN_DEBUG', 1) endif config_h = configure_file( output : 'config.h', configuration : conf) add_project_arguments('-include', 'config.h', language : 'c') default_sedinplaceflags = ' --follow-symlinks -i' inodecmd = 'stat -c \'%i %n\'' strip_binaries = '--strip-all' strip_shared = '--strip-unneeded' strip_static = '--strip-debug' os = host_machine.system() if os.startswith('darwin') inodecmd = '/usr/bin/stat -f \'%i %n\'' default_sedinplaceflags = ' -i \'\'' strip_binaries = '' strip_shared = '-s' strip_static = '-s' elif os.contains('bsd') or os == 'dragonfly' inodecmd = 'stat -f \'%i %n\'' default_sedinplaceflags = ' -i \'\'' endif sedinplaceflags = get_option('sedinplaceflags') if sedinplaceflags == 'auto' sedinplaceflags = default_sedinplaceflags endif chost = run_command(cc, '-dumpmachine').stdout().strip() carch = chost.split('-')[0] # annoyingly, we have to maintain two sets of configuration_data which is # largely identical, but which distinguishes between quoting needs. substs = configuration_data() substs.set('SED', SED.path()) substs.set('M4', M4.path()) substs.set('CARCH', carch) substs.set('CHOST', chost) substs.set('PKGEXT', get_option('pkg-ext')) substs.set('SRCEXT', get_option('src-ext')) substs.set('ROOTDIR', ROOTDIR) substs.set('LOCALEDIR', LOCALEDIR) substs.set('sysconfdir', SYSCONFDIR) substs.set('localstatedir', LOCALSTATEDIR) substs.set('PKGDATADIR', PKGDATADIR) substs.set('PREFIX', PREFIX) substs.set('BASH', BASH.path()) substs.set('PACKAGE_VERSION', PACKAGE_VERSION) substs.set('PACKAGE_NAME', meson.project_name()) substs.set('BUILDSCRIPT', BUILDSCRIPT) substs.set('TEMPLATE_DIR', get_option('makepkg-template-dir')) substs.set('DEBUGSUFFIX', get_option('debug-suffix')) substs.set('INODECMD', inodecmd) substs.set('SEDINPLACEFLAGS', sedinplaceflags) substs.set('SEDPATH', SED.path()) substs.set('LIBMAKEPKGDIR', LIBMAKEPKGDIR) substs.set('STRIP_BINARIES', strip_binaries) substs.set('STRIP_SHARED', strip_shared) substs.set('STRIP_STATIC', strip_static) subdir('lib/libalpm') subdir('src/common') subdir('src/pacman') subdir('src/util') subdir('scripts') # Internationalization if get_option('i18n') i18n = import('i18n') subdir('lib/libalpm/po') subdir('src/pacman/po') subdir('scripts/po') endif want_doc = get_option('doc') ASCIIDOC = find_program('asciidoc', required : want_doc) A2X = find_program('a2x', required : want_doc) build_doc = A2X.found() and not want_doc.disabled() if build_doc subdir('doc') endif includes = include_directories('src/common', 'lib/libalpm') libcommon = static_library( 'common', libcommon_sources, include_directories : includes, install : false) libalpm_a = static_library( 'alpm', libalpm_sources, include_directories : includes, dependencies : [crypto_provider, libarchive, libcurl, gpgme], link_with : [libcommon], install : true) if get_option('default_library') != 'static' libalpm = library( 'alpm', version : libalpm_version, link_whole: [libalpm_a], install : true) else libalpm = libalpm_a endif install_headers( 'lib/libalpm/alpm.h', 'lib/libalpm/alpm_list.h') # TODO: libs.private seem quite wrong here pkgconfig = import('pkgconfig') pkgconfig.generate( libalpm, name : 'libalpm', description : 'Arch Linux package management library', version : libalpm_version, url : 'http://www.archlinux.org/pacman/') pacman_bin = executable( 'pacman', pacman_sources, include_directories : includes, link_with : [libalpm, libcommon], dependencies : [libarchive], install : true, ) executable( 'pacman-conf', pacman_conf_sources, include_directories : includes, link_with : [libalpm], dependencies : [libarchive], install : true, ) executable( 'testpkg', testpkg_sources, include_directories : includes, link_with : [libalpm], dependencies : [libarchive], install : true, ) executable( 'vercmp', vercmp_sources, include_directories : includes, link_with : [libalpm_a], install : true, ) configure_file( input : 'etc/makepkg.conf.in', output : 'makepkg.conf', configuration : substs, install_dir : SYSCONFDIR) configure_file( input : 'etc/pacman.conf.in', output : 'pacman.conf', configuration : substs, install_dir : SYSCONFDIR) install_data( 'proto/PKGBUILD-split.proto', 'proto/PKGBUILD-vcs.proto', 'proto/PKGBUILD.proto', 'proto/proto.install', install_dir : join_paths(DATAROOTDIR, 'pacman')) foreach path : [ join_paths(LOCALSTATEDIR, 'lib/pacman/'), join_paths(LOCALSTATEDIR, 'cache/pacman/pkg/'), join_paths(DATAROOTDIR, 'makepkg-template/'), join_paths(DATAROOTDIR, 'libalpm/hooks/'), ] meson.add_install_script('sh', '-c', 'mkdir -p "$DESTDIR/@0@"'.format(path)) endforeach TEST_ENV = environment() TEST_ENV.set('PMTEST_SCRIPTLIB_DIR', join_paths(meson.source_root(), 'scripts/library/')) TEST_ENV.set('PMTEST_LIBMAKEPKG_DIR', join_paths(meson.build_root(), 'scripts/libmakepkg/')) TEST_ENV.set('PMTEST_UTIL_DIR', meson.build_root() + '/') TEST_ENV.set('PMTEST_SCRIPT_DIR', join_paths(meson.build_root(), 'scripts/')) subdir('test/pacman') subdir('test/scripts') subdir('test/util') message('\n '.join([ '@0@ @1@'.format(meson.project_name(), meson.project_version()), 'Build information:', ' prefix : @0@'.format(PREFIX), ' sysconfdir : @0@'.format(SYSCONFDIR), ' conf file : @0@'.format(join_paths(SYSCONFDIR, 'pacman.conf')), ' localstatedir : @0@'.format(LOCALSTATEDIR), ' database dir : @0@'.format(join_paths(LOCALSTATEDIR, 'lib/pacman/')), ' cache dir : @0@'.format(join_paths(LOCALSTATEDIR, 'cache/pacman/pkg/')), ' compiler : @0@ @1@'.format(cc.get_id(), cc.version()), '', ' Architecture : @0@'.format(carch), ' Host Type : @0@'.format(chost), ' File inode command : @0@'.format(inodecmd), ' In-place sed command : @0@ @1@'.format(SED.path(), sedinplaceflags), ' libalpm version : @0@'.format(libalpm_version), ' pacman version : @0@'.format(PACKAGE_VERSION), '', 'Directory and file information:', ' root working directory : @0@'.format(ROOTDIR), ' package extension : @0@'.format(get_option('pkg-ext')), ' source pkg extension : @0@'.format(get_option('src-ext')), ' build script name : @0@'.format(BUILDSCRIPT), ' template directory : @0@'.format(get_option('makepkg-template-dir')), '', 'Compilation options:', ' i18n support : @0@'.format(get_option('i18n')), ' Build docs : @0@'.format(build_doc), ' debug build : @0@'.format(get_option('buildtype') == 'debug'), ' Use libcurl : @0@'.format(conf.get('HAVE_LIBCURL')), ' Use GPGME : @0@'.format(conf.get('HAVE_LIBGPGME')), ' Use OpenSSL : @0@'.format(conf.has('HAVE_LIBSSL') and conf.get('HAVE_LIBSSL') == 1), ' Use nettle : @0@'.format(conf.has('HAVE_LIBNETTLE') and conf.get('HAVE_LIBNETTLE') == 1), '', ]))