aboutsummaryrefslogtreecommitdiffstats
path: root/meson/docs/markdown/Porting-from-autotools.md
diff options
context:
space:
mode:
Diffstat (limited to 'meson/docs/markdown/Porting-from-autotools.md')
-rw-r--r--meson/docs/markdown/Porting-from-autotools.md700
1 files changed, 700 insertions, 0 deletions
diff --git a/meson/docs/markdown/Porting-from-autotools.md b/meson/docs/markdown/Porting-from-autotools.md
new file mode 100644
index 000000000..34e1bbd3a
--- /dev/null
+++ b/meson/docs/markdown/Porting-from-autotools.md
@@ -0,0 +1,700 @@
+# 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')
+```