The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
20 KiB
686 lines
20 KiB
# Porting from Autotools |
|
|
|
This page uses [AppStream-glib](https://github.com/hughsie/appstream-glib/) as an example project. AppStream-Glib contains some libraries, GObject Introspection data, tests, man pages, i18n, bash-completion with optional flags to build/not build support for some things. |
|
|
|
Meson comes with a helper script `ac_converter` that you can use to convert the basic autoconf checks for your project. |
|
|
|
## Configure.ac |
|
|
|
First let's look at `configure.ac` and write the same in `meson.build`. |
|
|
|
```autoconf |
|
AC_PREREQ(2.63) |
|
``` |
|
Meson doesn't provide the same function, so just ignore this. |
|
|
|
### Defining variables |
|
`configure.ac`: |
|
```autoconf |
|
m4_define([as_major_version], [0]) |
|
m4_define([as_minor_version], [3]) |
|
m4_define([as_micro_version], [6]) |
|
m4_define([as_version], |
|
[as_major_version.as_minor_version.as_micro_version]) |
|
``` |
|
`meson.build`: |
|
```meson |
|
|
|
as_version = meson.project_version() # set in project() below |
|
ver_arr = as_version.split('.') |
|
|
|
as_major_version = ver_arr[0] |
|
as_minor_version = ver_arr[1] |
|
as_micro_version = ver_arr[2] |
|
``` |
|
|
|
### Initializing project and setting compilers |
|
`configure.ac`: |
|
```autoconf |
|
AC_INIT([appstream-glib],[as_version]) |
|
AC_PROG_CC |
|
``` |
|
`meson.build`: |
|
```meson |
|
project('appstream-glib', 'c', version : '0.3.6') |
|
``` |
|
Note that this must be the first line of your `meson.build` file. |
|
|
|
### AC_SUBST |
|
`configure.ac`: |
|
```autoconf |
|
AC_SUBST(AS_MAJOR_VERSION) |
|
AC_SUBST(AS_MINOR_VERSION) |
|
AC_SUBST(AS_MICRO_VERSION) |
|
AC_SUBST(AS_VERSION) |
|
``` |
|
|
|
You don't need to do the same in Meson, because it does not have two different types of files (Makefile, configure). |
|
|
|
### Auto headers |
|
|
|
`configure.ac`: |
|
|
|
```autoconf |
|
AC_CONFIG_HEADERS([config.h]) |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
conf = configuration_data() |
|
# Surround the version in quotes to make it a C string |
|
conf.set_quoted('VERSION', as_version) |
|
configure_file(output : 'config.h', |
|
configuration : conf) |
|
``` |
|
|
|
Meson doesn't support autoheaders, you need to manually specify what do you want to see in header file, write `configuration_data()` object and use `configure_file()`. |
|
|
|
You can also substitute variables of type `@SOME_VAR@` with configure data. The details are on the [configuration page](Configuration.md). |
|
|
|
### Finding programs |
|
|
|
`configure.ac`: |
|
|
|
```autoconf |
|
AC_PATH_PROG(GPERF, [gperf], [no]) |
|
if test x$GPERF != xno ; then |
|
AC_DEFINE(HAVE_GPERF,[1], [Use gperf]) |
|
fi |
|
AM_CONDITIONAL(HAVE_GPERF, [test x$GPERF != xno]) |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
gperf = find_program('gperf', required : false) |
|
if gperf.found() |
|
conf.set('HAVE_GPERF', 1) |
|
endif |
|
``` |
|
|
|
### Finding pkg-config modules |
|
|
|
`configure.ac`: |
|
|
|
```autoconf |
|
PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.24) |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
soup = dependency('libsoup-2.4', version : '>= 2.24') |
|
``` |
|
|
|
### Arguments |
|
|
|
`configure.ac`: |
|
|
|
```autoconf |
|
AC_ARG_ENABLE(dep11, AS_HELP_STRING([--enable-dep11],[enable DEP-11]), |
|
enable_dep11=$enableval,enable_dep11=yes) |
|
AM_CONDITIONAL(HAVE_DEP11, test x$enable_dep11 = xyes) |
|
if test x$enable_dep11 = xyes; then |
|
AC_CHECK_HEADER(yaml.h, [], [AC_MSG_ERROR([No yaml.h])]) |
|
YAML_LIBS="-lyaml" |
|
AC_SUBST(YAML_LIBS) |
|
AC_DEFINE(AS_BUILD_DEP11,1,[Build DEP-11 code]) |
|
fi |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
if get_option('enable-dep11') |
|
yaml = dependency('yaml-0.1') |
|
conf.set('AS_BUILD_DEP11', 1) |
|
else |
|
yaml = dependency('yaml-0.1', required : false) |
|
endif |
|
``` |
|
|
|
`meson_options.txt`: |
|
|
|
```meson |
|
option('enable-dep11', type : 'boolean', value : true, description : 'enable DEP-11') |
|
``` |
|
|
|
## Makefile.am |
|
|
|
Next step is `Makefile.am`. In meson you don't need to have other file, you still use `meson.build`. |
|
|
|
### Sub directories |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
SUBDIRS = \ |
|
libappstream-glib |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
subdir('libappstream-glib') |
|
``` |
|
|
|
### *CLEANFILES, EXTRA_DIST, etc. |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
DISTCLEANFILES = \ |
|
appstream-glib-*.tar.xz |
|
|
|
MAINTAINERCLEANFILES = \ |
|
*~ \ |
|
ABOUT-NLS \ |
|
aclocal.m4 \ |
|
ChangeLog \ |
|
compile \ |
|
config.guess \ |
|
config.h.* \ |
|
config.rpath |
|
|
|
EXTRA_DIST = \ |
|
COPYING \ |
|
MAINTAINERS \ |
|
AUTHORS \ |
|
README.md \ |
|
NEWS \ |
|
autogen.sh \ |
|
config.h |
|
``` |
|
|
|
In Meson you don't need have `*CLEANFILES`, because in meson you are building in temporary directory (usually called `build`), you manually removing it. You also not need to use `EXTRA_DIST`, because you will make tarballs via `git archive` or something like this. |
|
|
|
### glib-compile-resources |
|
|
|
`Makefile.am`: |
|
```make |
|
as-resources.c: appstream-glib.gresource.xml \ |
|
as-stock-icons.txt \ |
|
as-license-ids.txt \ |
|
as-blacklist-ids.txt \ |
|
as-category-ids.txt \ |
|
as-environment-ids.txt |
|
$(AM_V_GEN) \ |
|
glib-compile-resources \ |
|
--sourcedir=$(srcdir) \ |
|
--sourcedir=$(top_builddir)/data \ |
|
--target=$@ \ |
|
--generate-source \ |
|
--c-name as \ |
|
$(srcdir)/appstream-glib.gresource.xml |
|
as-resources.h: appstream-glib.gresource.xml \ |
|
as-stock-icons.txt \ |
|
as-license-ids.txt \ |
|
as-blacklist-ids.txt \ |
|
as-category-ids.txt \ |
|
as-environment-ids.txt |
|
$(AM_V_GEN) \ |
|
glib-compile-resources \ |
|
--sourcedir=$(srcdir) \ |
|
--sourcedir=$(top_builddir)/data \ |
|
--target=$@ \ |
|
--generate-header \ |
|
--c-name as \ |
|
$(srcdir)/appstream-glib.gresource.xml |
|
|
|
BUILT_SOURCES = \ |
|
as-resources.c \ |
|
as-resources.h |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
asresources = gnome.compile_resources( |
|
'as-resources', 'appstream-glib.gresource.xml', |
|
source_dir : '.', |
|
c_name : 'as') |
|
``` |
|
|
|
### Headers |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
libappstream_glib_includedir = $(includedir)/libappstream-glib |
|
libappstream_glib_include_HEADERS = \ |
|
appstream-glib.h \ |
|
as-app.h \ |
|
as-bundle.h \ |
|
as-enums.h \ |
|
as-icon.h \ |
|
as-image.h \ |
|
as-inf.h \ |
|
as-node.h \ |
|
as-problem.h \ |
|
as-provide.h \ |
|
as-release.h \ |
|
as-screenshot.h \ |
|
as-store.h \ |
|
as-tag.h \ |
|
as-utils.h \ |
|
as-version.h |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
headers = [ |
|
'appstream-glib.h', |
|
'as-app.h', |
|
'as-bundle.h', |
|
'as-enums.h', |
|
'as-icon.h', |
|
'as-image.h', |
|
'as-inf.h', |
|
'as-node.h', |
|
'as-problem.h', |
|
'as-provide.h', |
|
'as-release.h', |
|
'as-screenshot.h', |
|
'as-store.h', |
|
'as-tag.h', |
|
'as-utils.h', |
|
'as-version.h'] |
|
install_headers(headers, subdir : 'libappstream-glib') |
|
``` |
|
|
|
### Libraries |
|
|
|
`Makefile.am`: |
|
```make |
|
lib_LTLIBRARIES = \ |
|
libappstream-glib.la |
|
libappstream_glib_la_SOURCES = \ |
|
as-app.c \ |
|
as-app-desktop.c \ |
|
as-app-inf.c \ |
|
as-app-private.h \ |
|
as-app-validate.c \ |
|
as-bundle.c \ |
|
as-bundle-private.h \ |
|
as-cleanup.h \ |
|
as-enums.c \ |
|
as-icon.c \ |
|
as-icon-private.h \ |
|
as-image.c \ |
|
as-image-private.h \ |
|
as-inf.c \ |
|
as-inf.h \ |
|
as-node.c \ |
|
as-node-private.h \ |
|
as-problem.c \ |
|
as-problem.h \ |
|
as-provide.c \ |
|
as-provide-private.h \ |
|
as-release.c \ |
|
as-release-private.h \ |
|
as-resources.c \ |
|
as-resources.h \ |
|
as-screenshot.c \ |
|
as-screenshot-private.h \ |
|
as-store.c \ |
|
as-tag.c \ |
|
as-utils.c \ |
|
as-utils-private.h \ |
|
as-version.h \ |
|
as-yaml.c \ |
|
as-yaml.h |
|
|
|
libappstream_glib_la_LIBADD = \ |
|
$(GLIB_LIBS) \ |
|
$(GDKPIXBUF_LIBS) \ |
|
$(LIBARCHIVE_LIBS) \ |
|
$(SOUP_LIBS) \ |
|
$(YAML_LIBS) |
|
|
|
libappstream_glib_la_LDFLAGS = \ |
|
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ |
|
-export-dynamic \ |
|
-no-undefined \ |
|
-export-symbols-regex '^as_.*' |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
sources = [ |
|
'as-app.c', |
|
'as-app-desktop.c', |
|
'as-app-inf.c', |
|
'as-app-private.h', |
|
'as-app-validate.c', |
|
'as-bundle.c', |
|
'as-bundle-private.h', |
|
'as-cleanup.h', |
|
'as-enums.c', |
|
'as-icon.c', |
|
'as-icon-private.h', |
|
'as-image.c', |
|
'as-image-private.h', |
|
'as-inf.c', |
|
'as-inf.h', |
|
'as-node.c', |
|
'as-node-private.h', |
|
'as-problem.c', |
|
'as-problem.h', |
|
'as-provide.c', |
|
'as-provide-private.h', |
|
'as-release.c', |
|
'as-release-private.h', |
|
asresources, |
|
'as-screenshot.c', |
|
'as-screenshot-private.h', |
|
'as-store.c', |
|
'as-tag.c', |
|
'as-utils.c', |
|
'as-utils-private.h', |
|
'as-version.h', |
|
'as-yaml.c', |
|
'as-yaml.h'] |
|
|
|
deps = [glib, gdkpixbuf, libarchive, soup, yaml] |
|
|
|
mapfile = 'appstream-glib.map' |
|
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile) |
|
asglib = shared_library( |
|
'appstream-glib', sources, |
|
soversion : lt_current, |
|
version : lt_version, |
|
dependencies : deps, |
|
include_directories : include_directories('@0@/..'.format(meson.current_build_dir())), |
|
link_args : ['-Wl,--no-undefined', vflag], |
|
link_depends : mapfile, |
|
install : true) |
|
``` |
|
|
|
`appstream-glib.map`: |
|
|
|
``` |
|
{ |
|
global: |
|
as_*; |
|
local: |
|
*; |
|
}; |
|
``` |
|
|
|
### Custom targets |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
if HAVE_GPERF |
|
as-tag-private.h: as-tag.gperf |
|
$(AM_V_GEN) gperf < $< > $@ |
|
|
|
libappstream_glib_la_SOURCES += as-tag-private.h |
|
BUILT_SOURCES += as-tag-private.h |
|
endif |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
if gperf.found() |
|
astagpriv = custom_target('gperf as-tag', |
|
output : 'as-tag-private.h', |
|
input : 'as-tag.gperf', |
|
command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) |
|
sources = sources + [astagpriv] |
|
endif |
|
``` |
|
|
|
### Global CFLAGS |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
AM_CPPFLAGS = \ |
|
-DAS_COMPILATION \ |
|
-DLOCALSTATEDIR=\""$(localstatedir)"\" \ |
|
-DG_LOG_DOMAIN=\"As\" |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
add_project_arguments('-DG_LOG_DOMAIN="As"', language : 'c') |
|
add_project_arguments('-DAS_COMPILATION', language : 'c') |
|
add_project_arguments('-DLOCALSTATEDIR="/var"', language : 'c') |
|
``` |
|
|
|
### Tests |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
check_PROGRAMS = \ |
|
as-self-test |
|
as_self_test_SOURCES = \ |
|
as-self-test.c |
|
as_self_test_LDADD = \ |
|
$(GLIB_LIBS) \ |
|
$(GDKPIXBUF_LIBS) \ |
|
$(LIBARCHIVE_LIBS) \ |
|
$(SOUP_LIBS) \ |
|
$(YAML_LIBS) \ |
|
$(lib_LTLIBRARIES) |
|
as_self_test_CFLAGS = -DTESTDATADIR=\""$(top_srcdir)/data/tests"\" |
|
|
|
TESTS = as-self-test |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
selftest = executable( |
|
'as-self-test', 'as-self-test.c', |
|
include_directories : include_directories('@0@/..'.format(meson.current_build_dir())), |
|
dependencies : deps, |
|
c_args : '-DTESTDATADIR="@0@/../data/tests"'.format(meson.current_source_dir()), |
|
link_with : asglib) |
|
test('as-self-test', selftest) |
|
``` |
|
|
|
### GObject Introspection |
|
|
|
`Makefile.am`: |
|
|
|
```make |
|
introspection_sources = \ |
|
as-app.c \ |
|
as-app-validate.c \ |
|
as-app.h \ |
|
as-bundle.c \ |
|
as-bundle.h \ |
|
as-enums.c \ |
|
as-enums.h \ |
|
as-icon.c \ |
|
as-icon.h \ |
|
as-image.c \ |
|
as-image.h \ |
|
as-inf.c \ |
|
as-inf.h \ |
|
as-node.c \ |
|
as-node.h \ |
|
as-problem.c \ |
|
as-problem.h \ |
|
as-provide.c \ |
|
as-provide.h \ |
|
as-release.c \ |
|
as-release.h \ |
|
as-screenshot.c \ |
|
as-screenshot.h \ |
|
as-store.c \ |
|
as-store.h \ |
|
as-tag.c \ |
|
as-tag.h \ |
|
as-utils.c \ |
|
as-utils.h \ |
|
as-version.h |
|
|
|
AppStreamGlib-1.0.gir: libappstream-glib.la |
|
AppStreamGlib_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 GdkPixbuf-2.0 |
|
AppStreamGlib_1_0_gir_CFLAGS = $(AM_CPPFLAGS) |
|
AppStreamGlib_1_0_gir_SCANNERFLAGS = --identifier-prefix=As \ |
|
--symbol-prefix=as_ \ |
|
--warn-all \ |
|
--add-include-path=$(srcdir) |
|
AppStreamGlib_1_0_gir_EXPORT_PACKAGES = appstream-glib |
|
AppStreamGlib_1_0_gir_LIBS = libappstream-glib.la |
|
AppStreamGlib_1_0_gir_FILES = $(introspection_sources) |
|
INTROSPECTION_GIRS += AppStreamGlib-1.0.gir |
|
|
|
girdir = $(datadir)/gir-1.0 |
|
gir_DATA = $(INTROSPECTION_GIRS) |
|
|
|
typelibdir = $(libdir)/girepository-1.0 |
|
typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) |
|
|
|
CLEANFILES += $(gir_DATA) $(typelib_DATA) |
|
``` |
|
|
|
`meson.build`: |
|
|
|
```meson |
|
introspection_sources = [ |
|
'as-app.c', |
|
'as-app-validate.c', |
|
'as-app.h', |
|
'as-bundle.c', |
|
'as-bundle.h', |
|
'as-enums.c', |
|
'as-enums.h', |
|
'as-icon.c', |
|
'as-icon.h', |
|
'as-image.c', |
|
'as-image.h', |
|
'as-inf.c', |
|
'as-inf.h', |
|
'as-node.c', |
|
'as-node.h', |
|
'as-problem.c', |
|
'as-problem.h', |
|
'as-provide.c', |
|
'as-provide.h', |
|
'as-release.c', |
|
'as-release.h', |
|
'as-screenshot.c', |
|
'as-screenshot.h', |
|
'as-store.c', |
|
'as-store.h', |
|
'as-tag.c', |
|
'as-tag.h', |
|
'as-utils.c', |
|
'as-utils.h', |
|
'as-version.h'] |
|
|
|
gnome.generate_gir(asglib, |
|
sources : introspection_sources, |
|
nsversion : '1.0', |
|
namespace : 'AppStreamGlib', |
|
symbol_prefix : 'as_', |
|
identifier_prefix : 'As', |
|
export_packages : 'appstream-glib', |
|
includes : ['GObject-2.0', 'Gio-2.0', 'GdkPixbuf-2.0'], |
|
install : true |
|
) |
|
``` |
|
|
|
### GSettings |
|
|
|
`configure.ac`: |
|
```sh |
|
GLIB_GSETTINGS |
|
``` |
|
|
|
`Makefile.am`: |
|
```make |
|
gsettings_SCHEMAS = foo.gschema.xml |
|
@GSETTINGS_RULES@ |
|
``` |
|
|
|
`meson.build`: |
|
```meson |
|
install_data('foo.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0' / 'schemas') |
|
meson.add_install_script('meson_post_install.py') |
|
``` |
|
|
|
`meson_post_install.py`: |
|
```python |
|
#!/usr/bin/env python3 |
|
|
|
import os |
|
import subprocess |
|
|
|
schemadir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') |
|
|
|
if not os.environ.get('DESTDIR'): |
|
print('Compiling gsettings schemas...') |
|
subprocess.call(['glib-compile-schemas', schemadir]) |
|
``` |
|
|
|
### gettext |
|
|
|
Note this example does not include `intltool` usage. |
|
|
|
`configure.ac`: |
|
```m4 |
|
AM_GNU_GETTEXT([external]) |
|
AM_GNU_GETTEXT_VERSION([0.19.7]) |
|
|
|
GETTEXT_PACKAGE=foo |
|
AC_SUBST(GETTEXT_PACKAGE) |
|
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [The prefix for our gettext translation domains.]) |
|
``` |
|
|
|
`po/Makevars`: |
|
```make |
|
XGETTEXT_OPTIONS = --from-code=UTF-8 --keyword=_ --keyword=N_ --keyword=C_:1c,2 --keyword=NC_:1c,2 --keyword=g_dngettext:2,3 --add-comments |
|
``` |
|
|
|
`Makefile.am`: |
|
```make |
|
%.desktop: %.desktop.in |
|
$(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@ |
|
|
|
%.appdata.xml: %.appdata.xml.in |
|
$(AM_V_GEN)$(MSGFMT) --xml --template $< -d $(top_srcdir)/po -o $@ |
|
``` |
|
|
|
`meson.build`: |
|
```meson |
|
i18n = import('i18n') |
|
|
|
gettext_package = 'foo' |
|
add_project_arguments('-DGETTEXT_PACKAGE=' + gettext_package, language: 'c') |
|
subdir('po') |
|
|
|
i18n.merge_file( |
|
input: 'foo.desktop.in', |
|
output: 'foo.desktop', |
|
type: 'desktop', |
|
po_dir: 'po', |
|
install: true, |
|
install_dir: get_option('datadir') / 'applications' |
|
) |
|
|
|
i18n.merge_file( |
|
input: 'foo.appdata.xml.in', |
|
output: 'foo.appdata.xml', |
|
po_dir: 'po', |
|
install: true, |
|
install_dir: get_option('datadir') / 'appdata' |
|
) |
|
``` |
|
|
|
`po/meson.build`: |
|
```meson |
|
i18n.gettext(gettext_package, preset: 'glib') |
|
```
|
|
|