[gtkmm/kjellahl/meson-build-3-24] Add support for building gtkmm with Meson



commit deebd5c11383f7c66e4647c0ef30a195589eb5d5
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Mon May 11 16:04:37 2020 +0200

    Add support for building gtkmm with Meson
    
    gtkmm-3.0 can be built with either Autotools or Meson.
    New files have been copied from glibmm-2.4 and atkmm-1.6 and modified.
    
    See MR !24

 .gitignore                       |   6 +
 MSVC_NMake/gdkmm/meson.build     |  17 ++
 MSVC_NMake/gendef/meson.build    |   9 +
 MSVC_NMake/gtkmm/meson.build     |  17 ++
 Makefile.am                      |  20 ++
 demos/gtk-demo/meson.build       |  54 ++++
 docs/reference/meson.build       | 174 ++++++++++++
 gdk/gdkmm/meson.build            | 299 +++++++++++++++++++++
 gdk/gdkmmconfig.h.meson          |  21 ++
 gdk/meson.build                  |  78 ++++++
 gtk/gtkmm/meson.build            | 567 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkmmconfig.h.meson          |  43 +++
 gtk/meson.build                  |  29 ++
 meson.build                      | 432 +++++++++++++++++++++++++++++
 meson_options.txt                |  18 ++
 tests/meson.build                |  60 +++++
 tools/dummy-header.py            |  15 ++
 tools/extra_defs_gen/meson.build |  36 +++
 untracked/README                 |  40 +++
 19 files changed, 1935 insertions(+)
---
diff --git a/.gitignore b/.gitignore
index 14749489..0ed59644 100644
--- a/.gitignore
+++ b/.gitignore
@@ -594,3 +594,9 @@ tools/extra_defs_gen/generate_defs_gtk
 # win32_installer
 win32_installer/gtkmm-installer.nsi
 win32_installer/lgpl.txt
+
+# untracked/
+untracked/build_scripts/
+untracked/docs/
+untracked/gdk/
+untracked/gtk/
diff --git a/MSVC_NMake/gdkmm/meson.build b/MSVC_NMake/gdkmm/meson.build
new file mode 100644
index 00000000..91957829
--- /dev/null
+++ b/MSVC_NMake/gdkmm/meson.build
@@ -0,0 +1,17 @@
+# MSVC_NMake/gdkmm
+
+# Input: pkg_conf_data, gdkmmconfig_h
+# Output: gdkmm_rc
+
+gdkmm_rc = configure_file(
+  input: 'gdkmm.rc.in',
+  output: '@BASENAME@',
+  configuration: pkg_conf_data,
+)
+
+# Copy the generated configuration header into the MSVC project directory.
+configure_file(
+  input: gdkmmconfig_h,
+  output: 'gdkmmconfig.h',
+  copy: true,
+)
diff --git a/MSVC_NMake/gendef/meson.build b/MSVC_NMake/gendef/meson.build
new file mode 100644
index 00000000..32babb7d
--- /dev/null
+++ b/MSVC_NMake/gendef/meson.build
@@ -0,0 +1,9 @@
+# MSVC_NMake/gendef
+
+# Input: is_msvc
+# Output: gendef
+
+# Used to generate the .def file required to obtain the import .lib file
+if is_msvc
+  gendef = executable('gendef', 'gendef.cc', install: false,)
+endif
diff --git a/MSVC_NMake/gtkmm/meson.build b/MSVC_NMake/gtkmm/meson.build
new file mode 100644
index 00000000..a68c8fa8
--- /dev/null
+++ b/MSVC_NMake/gtkmm/meson.build
@@ -0,0 +1,17 @@
+# MSVC_NMake/gtkmm
+
+# Input: pkg_conf_data, gtkmmconfig_h
+# Output: gtkmm_rc
+
+gtkmm_rc = configure_file(
+  input: 'gtkmm.rc.in',
+  output: '@BASENAME@',
+  configuration: pkg_conf_data,
+)
+
+# Copy the generated configuration header into the MSVC project directory.
+configure_file(
+  input: gtkmmconfig_h,
+  output: 'gtkmmconfig.h',
+  copy: true,
+)
diff --git a/Makefile.am b/Makefile.am
index c4f9c02f..758a8327 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,5 +55,25 @@ dist_noinst_SCRIPTS = autogen.sh
 
 DISTCLEANFILES = $(filter %mmconfig.h,$(msvc_files)) win32_installer/lgpl.txt
 
+# Distribute files needed when building gtkmm with Meson.
+EXTRA_DIST = \
+  meson.build \
+  meson_options.txt \
+  MSVC_NMake/gendef/meson.build \
+  MSVC_NMake/gdkmm/meson.build \
+  MSVC_NMake/gtkmm/meson.build \
+  demos/gtk-demo/meson.build \
+  docs/reference/meson.build \
+  gdk/meson.build \
+  gdk/gdkmmconfig.h.meson \
+  gdk/gdkmm/meson.build \
+  gtk/meson.build \
+  gtk/gtkmmconfig.h.meson \
+  gtk/gtkmm/meson.build \
+  tests/meson.build \
+  tools/dummy-header.py \
+  tools/extra_defs_gen/meson.build \
+  untracked/README
+
 # Optional: auto-generate the ChangeLog file from the git log on make dist
 include $(top_srcdir)/build/dist-changelog.am
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
new file mode 100644
index 00000000..b80b3069
--- /dev/null
+++ b/demos/gtk-demo/meson.build
@@ -0,0 +1,54 @@
+# demos/gtk-demo
+
+# Input: gtkmm_dep, epoxy_dep, build_demos
+# Output: -
+
+gtkmm_demo_cc_files = [
+  'main.cc',
+  'demowindow.cc',
+  'textwidget.cc',
+  'example_appwindow.cc',
+  'example_builder.cc',
+  'example_buttonbox.cc',
+  'example_change_display.cc',
+  'example_colorsel.cc',
+  'example_dialog.cc',
+  'example_drawingarea.cc',
+  'example_flowbox.cc',
+  'example_gestures.cc',
+  'example_glarea.cc',
+  'example_headerbar.cc',
+  'example_iconbrowser.cc',
+  'example_iconview.cc',
+  'example_images.cc',
+  'example_menus.cc',
+  'example_overlay.cc',
+  'example_panes.cc',
+  'example_pixbufs.cc',
+  'example_shortcuts.cc',
+  'example_sizegroup.cc',
+  'example_stack.cc',
+  'example_stacksidebar.cc',
+  'example_textview.cc',
+  'example_treeview_editable_cells.cc',
+  'example_treeview_liststore.cc',
+  'example_treeview_treestore.cc',
+]
+
+gnome = import('gnome')
+
+if epoxy_dep.found()
+  demo_resources = gnome.compile_resources('demo-resources',
+    'demo.gresource.xml',
+    source_dir: meson.current_source_dir(),
+    install: false,
+  )
+
+  executable('gtkmm-demo',
+    gtkmm_demo_cc_files, demo_resources,
+    dependencies: [gtkmm_dep, epoxy_dep],
+    gui_app: true,
+    build_by_default: build_demos,
+    install: false,
+  )
+endif
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
new file mode 100644
index 00000000..979798f6
--- /dev/null
+++ b/docs/reference/meson.build
@@ -0,0 +1,174 @@
+# docs/reference
+
+# Input: built_files_root, project_source_root, gdkmm_pcname, gtkmm_pcname,
+#        perl, gdkmm_hg_ccg_basenames, gtkmm_hg_ccg_basenames,
+#        gdkmm_extra_h_files, gtkmm_extra_h_files, gdkmm_built_h_file_targets,
+#        gtkmm_built_h_file_targets, install_datadir, python3, doc_reference_py,
+#        build_documentation
+# Output: install_docdir, install_devhelpdir
+
+tag_file_modules = [
+  'mm-common-libstdc++',
+  'sigc++-2.0',
+  'glibmm-2.4',
+  'cairomm-1.0',
+  'pangomm-1.4',
+  'atkmm-1.6',
+]
+doxygen_tagfiles = ''
+docinstall_flags = []
+foreach module : tag_file_modules
+  depmod = dependency(module, required: false)
+  if depmod.found()
+    doxytagfile = depmod.get_pkgconfig_variable('doxytagfile')
+    htmlrefpub = depmod.get_pkgconfig_variable('htmlrefpub', default: '')
+    htmlrefdir = depmod.get_pkgconfig_variable('htmlrefdir', default: '')
+    if htmlrefpub == ''
+      htmlrefpub = htmlrefdir
+    elif htmlrefdir == ''
+      htmlrefdir = htmlrefpub
+    endif
+    doxygen_tagfiles += ' "' + doxytagfile + '=' + htmlrefpub + '"'
+    if not htmlrefdir.endswith('/')
+      htmlrefdir += '/'
+    endif
+    docinstall_flags += ['-l', doxytagfile.split('/')[-1] + '@' + htmlrefdir]
+  endif
+endforeach
+
+book_name = gtkmm_pcname
+book_title = meson.project_name() + ' Reference Manual'
+
+# Configuration data for Doxyfile.
+doc_conf_data = configuration_data()
+doc_conf_data.set('configure_input',
+  'docs/reference/Doxyfile. Generated from Doxyfile.in by meson.configure_file().')
+doc_conf_data.set('PACKAGE_NAME', meson.project_name())
+doc_conf_data.set('PACKAGE_VERSION', meson.project_version())
+doc_conf_data.set('abs_top_builddir', built_files_root)
+doc_conf_data.set('abs_top_srcdir', project_source_root)
+doc_conf_data.set('GTKMM_MODULE_NAME', book_name)
+doc_conf_data.set('DOXYGEN_TAGFILES', doxygen_tagfiles)
+doc_conf_data.set('PERL', perl.found() ? perl.path() : '')
+
+configure_file(
+  input: 'Doxyfile.in',
+  output: '@BASENAME@',
+  configuration: doc_conf_data,
+)
+
+# Installation directories relative to {prefix}.
+install_docdir = install_datadir / 'doc' / book_name
+install_reference_docdir = install_docdir / 'reference'
+install_image_docdir = install_docdir / 'images'
+install_devhelpdir = install_datadir / 'devhelp' / 'books' / book_name
+
+if not build_documentation
+  # Documentation shall not be built or installed.
+  # Return to the calling meson.build file.
+  subdir_done()
+endif
+
+# Built input .h files to Doxygen.
+built_h_files = []
+foreach file : gdkmm_hg_ccg_basenames
+  built_h_files += built_files_root / 'gdk' / 'gdkmm' / file + '.h'
+endforeach
+foreach file : gtkmm_hg_ccg_basenames
+  built_h_files += built_files_root / 'gtk' / 'gtkmm' / file + '.h'
+endforeach
+
+# Hand-coded input .h files to Doxygen.
+src_h_files = []
+foreach file : gdkmm_extra_h_files
+  if file != 'wrap_init.h'
+    src_h_files += project_source_root / 'gdk' / 'gdkmm' / file
+  endif
+endforeach
+foreach file : gtkmm_extra_h_files
+  if file != 'wrap_init.h'
+    src_h_files += project_source_root / 'gtk' / 'gtkmm' / file
+  endif
+endforeach
+src_h_files += project_source_root / 'gdk' / 'gdkmm.h'
+src_h_files += project_source_root / 'gtk' / 'gtkmm.h'
+
+doctool_dir = project_source_root / 'untracked' / 'docs' # MMDOCTOOLDIR
+doctool_dist_dir = 'untracked' / 'docs' # Relative to MESON_DIST_ROOT
+
+doc_h_files = src_h_files
+if gdkmm_built_h_file_targets.length() + gtkmm_built_h_file_targets.length() > 0
+  # .h files have been generated from .hg files (maintainer mode).
+  # Use built_h_file_targets instead of built_h_files here, or else Meson won't
+  # know that Doxygen must not be executed until the .h files have been built.
+  doc_h_files += gdkmm_built_h_file_targets + gtkmm_built_h_file_targets
+else
+  # All .h files are stored in the source tree (not maintainer mode).
+  doc_h_files += built_h_files
+endif
+
+# Can't use @INPUT@ in the command. It requires absolute file paths.
+# Paths in built_h_file_targets are relative to project_build_root.
+tag_file = custom_target('html_and_tag',
+  input: doc_h_files,
+  output: book_name + '.tag',
+  command: [
+    python3, doc_reference_py, 'doxygen',
+    doctool_dir,
+    '@OUTPUT@',
+    src_h_files,
+    built_h_files,
+  ],
+  build_by_default: build_documentation,
+  install: true,
+  install_dir: install_reference_docdir,
+)
+
+devhelp_file = custom_target('devhelp',
+  input: tag_file,
+  output: book_name + '.devhelp2',
+  command: [
+    python3, doc_reference_py, 'devhelp',
+    doctool_dir,
+    '@INPUT@',
+    '@OUTPUT@',
+    book_name,
+    book_title,
+  ],
+  build_by_default: build_documentation,
+)
+
+# Install Devhelp file and html files.
+meson.add_install_script(
+  python3.path(), doc_reference_py, 'install_doc',
+  doctool_dir,
+  devhelp_file.full_path(),
+  install_devhelpdir,
+  install_reference_docdir / 'html',
+  docinstall_flags
+)
+
+# Install images.
+image_basefiles = [
+  'gtkmm_logo.gif',
+  'top.gif',
+]
+image_files = []
+foreach file : image_basefiles
+  image_files += '..' / 'images' / file
+endforeach
+
+install_data(image_files, install_dir: install_image_docdir)
+
+if not meson.is_subproject()
+  # Distribute built files and files copied by mm-common-get.
+  # (add_dist_script() is not allowed in a subproject)
+  meson.add_dist_script(
+    python3.path(), doc_reference_py, 'dist_doc',
+    doctool_dir,
+    doctool_dist_dir,
+    meson.current_build_dir(),
+    tag_file.full_path(),
+    devhelp_file.full_path(),
+  )
+endif
diff --git a/gdk/gdkmm/meson.build b/gdk/gdkmm/meson.build
new file mode 100644
index 00000000..8fe5e9aa
--- /dev/null
+++ b/gdk/gdkmm/meson.build
@@ -0,0 +1,299 @@
+# gdk/gdkmm
+
+# Input: gdkmm_build_dep, gdkmm_pcname, maintainer_mode, project_source_root,
+#        generate_binding_py, m4_files, gtkmm_libversion, install_includedir,
+#        python3, gdkmm_rc, dummy_header_py, gmmproc_dir, build_shared_libs_directly,
+#        build_deprecated_api, gmmproc_extra_m4_dirs, is_host_windows
+# Output: gdkmm_hg_ccg_basenames, gdkmm_extra_h_files, built_files_root,
+#         gdkmm_built_h_file_targets, gdkmm_used_built_h_file_targets, gdkmm_dep
+
+gdkmm_defs_basefiles = [
+  'gdk.defs',
+  'gdk_enums.defs',
+  'gdk_extra.defs',
+  'gdk_extra_objects.defs',
+  'gdk_methods.defs',
+  'gdk_pixbuf_enums.defs',
+  'gdk_pixbuf_methods.defs',
+  'gdk_signals.defs',
+  'gdk_docs.xml',
+  'gdk_docs_override.xml',
+]
+
+gdkmm_defs_files = []
+foreach file : gdkmm_defs_basefiles
+  gdkmm_defs_files += '..' / 'src' / file
+endforeach
+
+# Generated from pairs of .hg and .ccg files.
+gdkmm_any_hg_ccg_basenames = [
+  'applaunchcontext',
+  'cursor',
+  'device',
+  'devicemanager',
+  'display',
+  'displaymanager',
+  'dragcontext',
+  'drawingcontext',
+  'event',
+  'frameclock',
+  'frametimings',
+  'glcontext',
+  'monitor',
+  'pixbuf',
+  'pixbufanimation',
+  'pixbufanimationiter',
+  'pixbufformat',
+  'pixbufloader',
+  'rectangle',
+  'rgba',
+  'screen',
+  'seat',
+  'timecoord',
+  'types',
+  'visual',
+  'window',
+]
+
+gdkmm_deprecated_hg_ccg_basenames = [
+  'color',
+]
+
+gdkmm_extra_cc_files = [
+  'general.cc',
+]
+
+gdkmm_extra_h_files = [
+  'general.h',
+  'wrap_init.h',
+]
+
+# All .hg/.ccg files, regardless of deprecation.
+gdkmm_hg_ccg_basenames = \
+  gdkmm_any_hg_ccg_basenames + \
+  gdkmm_deprecated_hg_ccg_basenames
+
+# Used .hg/.ccg files in the present build.
+gdkmm_used_hg_ccg_basenames = gdkmm_any_hg_ccg_basenames
+if build_deprecated_api
+  gdkmm_used_hg_ccg_basenames += gdkmm_deprecated_hg_ccg_basenames
+endif
+
+install_headers('..' / 'gdkmm.h', subdir: gdkmm_pcname)
+install_headers(gdkmm_extra_h_files, subdir: gdkmm_pcname / 'gdkmm')
+
+untracked_gdkmm = 'untracked' / 'gdk' / 'gdkmm'
+src_untracked_gdkmm = project_source_root / untracked_gdkmm
+
+gdkmm_cpp_args = [ '-DGDKMM_BUILD=1' ]
+
+if is_msvc and not build_shared_libs_directly
+  gdkmm_cpp_args += '-DGDKMM_USE_GENDEF'
+endif
+
+if maintainer_mode
+
+  # Maintainer mode. Generate .h and .cc files from .hg and .ccg files in ../src.
+
+  # docs/reference/meson.build needs these.
+  built_files_root = project_build_root
+  gdkmm_built_h_file_targets = []
+
+  # Force meson+ninja to generate source files before anything is compiled.
+  # Compilation must depend on these targets.
+  gdkmm_used_built_cc_file_targets = []
+  gdkmm_used_built_h_file_targets = []
+
+  hg_files = []
+  foreach file : gdkmm_hg_ccg_basenames
+    hg_files += '..' / 'src' / file + '.hg'
+  endforeach
+
+  # Create wrap_init.cc in project_build_root/gdk/gdkmm.
+  gdkmm_used_built_cc_file_targets += custom_target('gdkmm-wrap_init.cc',
+    input: hg_files,
+    output: 'wrap_init.cc',
+    command: [
+      python3, generate_binding_py, 'generate_wrap_init',
+      gmmproc_dir,
+      '@OUTPUT@',
+      'Gdk', # namespace
+      '@INPUT@',
+    ],
+    build_by_default: maintainer_mode,
+    install: false,
+  )
+
+  # Create .h/_p.h/.cc files in project_build_root/gdk/gdkmm
+  # from .hg/.ccg files in project_source_root/gdk/src.
+  foreach file : gdkmm_hg_ccg_basenames
+    hg_file = '..' / 'src' / file + '.hg'
+    ccg_file = '..' / 'src' / file + '.ccg'
+    built_file_target = custom_target('gdkmm-' + file + '.cc',
+      input: [hg_file, ccg_file],
+      output: [file + '.stamp', file + '.cc', file + '.h'],
+      command: [
+        python3, generate_binding_py, 'gmmproc',
+        gmmproc_dir,
+        '@OUTPUT0@',
+        file,
+        meson.current_source_dir() / '..' / 'src',
+        project_source_root / 'tools' / 'm4',
+        gmmproc_extra_m4_dirs,
+      ],
+      depend_files: gdkmm_defs_files + m4_files,
+      build_by_default: maintainer_mode,
+      install: false,
+    )
+    gdkmm_built_h_file_targets += built_file_target[2]
+    if gdkmm_used_hg_ccg_basenames.contains(file)
+      gdkmm_used_built_cc_file_targets += built_file_target[1]
+      gdkmm_used_built_h_file_targets += built_file_target[2]
+    endif
+  endforeach
+
+  # Create dummy_header.h, depending on all generated headers.
+  # It's created if it does not exist, but it's never updated.
+  # It guarantees that all generated headers are built before gdkmm_library
+  # is built, at the same time avoiding unnecessary recompilations.
+  # If gdkmm_used_built_h_file_targets would be listed as sources to gdkmm_library,
+  # all generated .cc files could be recompiled if one generated .h file has
+  # been changed.
+  built_dummy_h_file_target = custom_target('gdkmm-dummy_header.h',
+    input: gdkmm_used_built_h_file_targets,
+    output: 'dummy_header.h',
+    command: [
+      python3, dummy_header_py,
+      '@OUTPUT@',
+    ],
+    build_by_default: maintainer_mode,
+    install: false,
+  )
+
+  extra_include_dirs = ['..']
+
+  gdk_gen_sources = gdkmm_used_built_cc_file_targets
+
+  built_h_cc_dir = meson.current_build_dir()
+
+else # not maintainer_mode
+
+  # Not maintainer mode. Compile built source code files in
+  # project_source_root/untracked/gdk/gdkmm.
+
+  gdkmm_used_built_h_file_targets = []
+
+  # docs/reference/meson.build needs these.
+  built_files_root = project_source_root / 'untracked'
+  gdkmm_built_h_file_targets = []
+
+  # Two cases:
+  # 1. The source code comes from a tarball, where the built files
+  #    are stored in project_source_root/untracked.
+  #    There are no built files in the build tree.
+  # 2. Files have been built in the build tree. Then maintainer_mode has
+  #    been changed from true to false. Files that are missing or not up to date
+  #    in project_source_root/untracked are copied from the build tree.
+
+  # Try to copy built source code files to the source tree.
+  run_command(
+    python3, generate_binding_py, 'copy_built_files',
+    meson.current_build_dir(),
+    src_untracked_gdkmm,
+    gdkmm_hg_ccg_basenames,
+  )
+
+  built_cc_files = [ src_untracked_gdkmm / 'wrap_init.cc' ]
+  foreach file : gdkmm_used_hg_ccg_basenames
+    built_cc_files += src_untracked_gdkmm / file + '.cc'
+  endforeach
+
+  gdk_gen_sources = built_cc_files
+  built_dummy_h_file_target = []
+
+  extra_include_dirs = [ '..', '..' / '..' / 'untracked' / 'gdk' ]
+
+  built_h_cc_dir = src_untracked_gdkmm
+
+endif
+
+extra_gdkmm_objects = []
+
+# Build the .rc file for Windows builds and link to it
+if is_host_windows
+  windows = import('windows')
+  gdkmm_res = windows.compile_resources(gdkmm_rc)
+  extra_gdkmm_objects += gdkmm_res
+endif
+
+if build_shared_libs_directly
+  gdkmm_library = library(gdkmm_pcname, extra_gdkmm_objects,
+    gdk_gen_sources, built_dummy_h_file_target, gdkmm_extra_cc_files,
+    include_directories: extra_include_dirs,
+    cpp_args: gdkmm_cpp_args,
+    version: gtkmm_libversion,
+    dependencies: gdkmm_build_dep,
+    install: true,
+  )
+else
+  # Building with headers generated from *.hg files with
+  # gmmproc < 2.64.0 on Visual Studio: We need this so
+  # that we can run gendef.exe to get the .def file
+  # needed for obtaining the .lib file for the gdkmm DLL
+  gdk_int_lib = static_library('gdkmm-int',
+    gdk_gen_sources, built_dummy_h_file_target, gdkmm_extra_cc_files,
+    include_directories: extra_include_dirs,
+    cpp_args: gdkmm_cpp_args,
+    dependencies: gdkmm_build_dep,
+    install: false,
+  )
+
+  gdkmm_def = custom_target('gdkmm.def',
+    output: 'gdkmm.def',
+    depends: gdk_int_lib,
+    command: [ gendef,
+      '@OUTPUT@',
+      '@0@-@1@.dll'.format(gdkmm_pcname, gtkmm_libversion.split('.')[0]),
+      gdk_int_lib.full_path(),
+    ],
+    install: false,
+  )
+  gdkmm_extra_link_args = ['/def:@0@'.format(gdkmm_def.full_path())]
+
+  gdkmm_library = library(gdkmm_pcname, extra_gdkmm_objects,
+    objects: gdk_int_lib.extract_all_objects(),
+    version: gtkmm_libversion,
+    dependencies: gdkmm_build_dep,
+    link_depends: gdkmm_def,
+    link_args: gdkmm_extra_link_args,
+    install: true,
+  )
+endif
+
+# Install built .h and _p.h files.
+meson.add_install_script(
+  python3.path(), generate_binding_py, 'install_built_h_files',
+  built_h_cc_dir,
+  install_includedir / gdkmm_pcname / 'gdkmm', # subdir below {prefix}
+  gdkmm_used_hg_ccg_basenames
+)
+
+if not meson.is_subproject()
+  # Distribute built files.
+  # (add_dist_script() is not allowed in a subproject)
+  meson.add_dist_script(
+    python3.path(), generate_binding_py, 'dist_built_files',
+    built_h_cc_dir,
+    untracked_gdkmm,
+    gdkmm_hg_ccg_basenames,
+  )
+endif
+
+# This is useful in the main project when gdkmm is used as a subproject.
+# It's also used when building demo programs and test programs.
+gdkmm_dep = declare_dependency(
+  sources: gdkmm_used_built_h_file_targets,
+  link_with: gdkmm_library,
+  include_directories: extra_include_dirs,
+  dependencies: gdkmm_build_dep,
+)
diff --git a/gdk/gdkmmconfig.h.meson b/gdk/gdkmmconfig.h.meson
new file mode 100644
index 00000000..a8187b3a
--- /dev/null
+++ b/gdk/gdkmmconfig.h.meson
@@ -0,0 +1,21 @@
+#ifndef _GDKMM_CONFIG_H
+#define _GDKMM_CONFIG_H
+
+#include <pangommconfig.h>
+
+/* Defined when the -Dbuild-x11-api=true configure argument was given */
+#mesondefine GDKMM_X11_BACKEND_ENABLED
+
+/* Define to omit deprecated API from gdkmm. */
+#mesondefine GDKMM_DISABLE_DEPRECATED
+
+/* Major version number of gdkmm. */
+#mesondefine GDKMM_MAJOR_VERSION
+
+/* Minor version number of gdkmm. */
+#mesondefine GDKMM_MINOR_VERSION
+
+/* Micro version number of gdkmm. */
+#mesondefine GDKMM_MICRO_VERSION
+
+#endif /* !_GDKMM_CONFIG_H */
diff --git a/gdk/meson.build b/gdk/meson.build
new file mode 100644
index 00000000..e5a23080
--- /dev/null
+++ b/gdk/meson.build
@@ -0,0 +1,78 @@
+# gdk
+
+# Input: install_prefix, install_libdir, install_datadir, install_includedir,
+#        gdkmm_pcname, gtkmm_pcname, gtkmm_api_version, gdkmm_requires,
+#        gtkmm_requires, build_deprecated_api, install_pkgconfigdir,
+#        is_os_cocoa, cpp_compiler, gtkmm_major_version, gtkmm_minor_version,
+#        gtkmm_micro_version, build_atkmm_api, build_x11_api
+# Output: pkg_conf_data, install_gdkmmconfigdir, gdkmmconfig_h
+
+pkg_conf_data = configuration_data()
+pkg_conf_data.set('prefix', install_prefix)
+pkg_conf_data.set('exec_prefix', '${prefix}')
+pkg_conf_data.set('libdir', '${exec_prefix}' / install_libdir)
+pkg_conf_data.set('datarootdir', '${prefix}' / install_datadir)
+pkg_conf_data.set('datadir', '${datarootdir}')
+pkg_conf_data.set('includedir', '${prefix}' / install_includedir)
+pkg_conf_data.set('PACKAGE_TARNAME', meson.project_name())
+pkg_conf_data.set('PACKAGE_VERSION', meson.project_version())
+pkg_conf_data.set('GDKMM_MODULE_NAME', gdkmm_pcname)
+pkg_conf_data.set('GDKMM_API_VERSION', gtkmm_api_version)
+pkg_conf_data.set('GDKMM_MODULES', gdkmm_requires)
+pkg_conf_data.set('GTKMM_MODULE_NAME', gtkmm_pcname)
+pkg_conf_data.set('GTKMM_API_VERSION', gtkmm_api_version)
+pkg_conf_data.set('GTKMM_MODULES', gtkmm_requires)
+if not build_deprecated_api
+  pkg_conf_data.set('GDKMM_DISABLE_DEPRECATED', 1)
+  pkg_conf_data.set('GTKMM_DISABLE_DEPRECATED', 1)
+endif
+if build_atkmm_api
+  pkg_conf_data.set('GTKMM_ATKMM_ENABLED', 1)
+endif
+if build_x11_api
+  pkg_conf_data.set('GDKMM_X11_BACKEND_ENABLED', 1)
+endif
+pkg_conf_data.set('GDKMM_MAJOR_VERSION', gtkmm_major_version)
+pkg_conf_data.set('GDKMM_MINOR_VERSION', gtkmm_minor_version)
+pkg_conf_data.set('GDKMM_MICRO_VERSION', gtkmm_micro_version)
+pkg_conf_data.set('GTKMM_MAJOR_VERSION', gtkmm_major_version)
+pkg_conf_data.set('GTKMM_MINOR_VERSION', gtkmm_minor_version)
+pkg_conf_data.set('GTKMM_MICRO_VERSION', gtkmm_micro_version)
+
+library_build_type = get_option('default_library')
+
+if cpp_compiler.get_argument_syntax() == 'msvc'
+  if library_build_type == 'static' or library_build_type == 'both'
+    error('Static builds are not supported by MSVC-style builds')
+  endif
+endif
+
+if library_build_type == 'static'
+  pkg_conf_data.set('GDKMM_STATIC_LIB', 1)
+  pkg_conf_data.set('GTKMM_STATIC_LIB', 1)
+endif
+
+configure_file(
+  input: 'gdkmm.pc.in',
+  output: gdkmm_pcname + '.pc',
+  configuration: pkg_conf_data,
+  install_dir: install_pkgconfigdir,
+)
+
+gdkmm_pkg_uninst_conf_data = configuration_data()
+gdkmm_pkg_uninst_conf_data.merge_from(pkg_conf_data)
+gdkmm_pkg_uninst_conf_data.set('srcdir', meson.current_source_dir())
+
+configure_file(
+  input: 'gdkmm-uninstalled.pc.in',
+  output: gdkmm_pcname + '-uninstalled.pc',
+  configuration: gdkmm_pkg_uninst_conf_data,
+)
+
+install_gdkmmconfigdir = install_libdir / gdkmm_pcname / 'include'
+gdkmmconfig_h = configure_file(
+  input: 'gdkmmconfig.h.meson',
+  output: 'gdkmmconfig.h',
+  configuration: pkg_conf_data,
+  install_dir: install_gdkmmconfigdir,
+)
diff --git a/gtk/gtkmm/meson.build b/gtk/gtkmm/meson.build
new file mode 100644
index 00000000..64f3ebec
--- /dev/null
+++ b/gtk/gtkmm/meson.build
@@ -0,0 +1,567 @@
+# gtk/gtkmm
+
+# Input: gtkmm_build_dep, gtkmm_pcname, maintainer_mode, project_source_root,
+#        generate_binding_py, m4_files, gtkmm_libversion, install_includedir,
+#        python3, gtkmm_rc, dummy_header_py, gmmproc_dir, build_shared_libs_directly,
+#        build_deprecated_api, build_x11_api, gmmproc_extra_m4_dirs, is_host_windows,
+#        gdkmm_library, gdkmm_used_built_h_file_targets
+# Output: gtkmm_hg_ccg_basenames, gtkmm_extra_h_files, built_files_root,
+#         gtkmm_built_h_file_targets, gtkmm_dep
+
+gtkmm_defs_basefiles = [
+  'gtk.defs',
+  'gtk_enums.defs',
+  'gtk_extra_objects.defs',
+  'gtk_methods.defs',
+  'gtk_signals.defs',
+  'gtk_vfuncs.defs',
+  'gtk_docs.xml',
+  'gtk_docs_override.xml',
+]
+
+gtkmm_defs_files = []
+foreach file : gtkmm_defs_basefiles
+  gtkmm_defs_files += '..' / 'src' / file
+endforeach
+
+# Generated from pairs of .hg and .ccg files.
+gtkmm_any_hg_ccg_basenames = [
+  'aboutdialog',
+  'accelgroup',
+  'accellabel',
+  'action',
+  'actionable',
+  'actionbar',
+  'activatable',
+  'adjustment',
+  'appchooser',
+  'appchooserbutton',
+  'appchooserdialog',
+  'appchooserwidget',
+  'application',
+  'applicationwindow',
+  'aspectframe',
+  'assistant',
+  'bin',
+  'border',
+  'box',
+  'buildable',
+  'builder',
+  'button',
+  'buttonbox',
+  'calendar',
+  'cellarea',
+  'cellareabox',
+  'cellareacontext',
+  'celleditable',
+  'celllayout',
+  'cellrenderer',
+  'cellrendereraccel',
+  'cellrenderercombo',
+  'cellrendererpixbuf',
+  'cellrendererprogress',
+  'cellrendererspin',
+  'cellrendererspinner',
+  'cellrenderertext',
+  'cellrenderertoggle',
+  'cellview',
+  'checkbutton',
+  'checkmenuitem',
+  'clipboard',
+  'colorbutton',
+  'colorchooser',
+  'colorchooserdialog',
+  'combobox',
+  'comboboxtext',
+  'container',
+  'cssprovider',
+  'csssection',
+  'dialog',
+  'drawingarea',
+  'editable',
+  'entry',
+  'entrycompletion',
+  'entrybuffer',
+  'enums',
+  'eventbox',
+  'eventcontroller',
+  'expander',
+  'filechooser',
+  'filechooserbutton',
+  'filechooserdialog',
+  'filechoosernative',
+  'filechooserwidget',
+  'filefilter',
+  'fixed',
+  'flowbox',
+  'flowboxchild',
+  'fontbutton',
+  'fontchooser',
+  'fontchooserdialog',
+  'fontchooserwidget',
+  'frame',
+  'gesture',
+  'gesturedrag',
+  'gesturelongpress',
+  'gesturemultipress',
+  'gesturepan',
+  'gesturerotate',
+  'gesturesingle',
+  'gestureswipe',
+  'gesturezoom',
+  'glarea',
+  'grid',
+  'headerbar',
+  'hvbox',
+  'iconinfo',
+  'icontheme',
+  'iconview',
+  'image',
+  'infobar',
+  'invisible',
+  'label',
+  'layout',
+  'levelbar',
+  'linkbutton',
+  'listbox',
+  'listboxrow',
+  'liststore',
+  'lockbutton',
+  'main',
+  'menu',
+  'menubar',
+  'menubutton',
+  'menuitem',
+  'menushell',
+  'menutoolbutton',
+  'messagedialog',
+  'misc',
+  'modelbutton',
+  'nativedialog',
+  'notebook',
+  'offscreenwindow',
+  'orientable',
+  'overlay',
+  'pagesetup',
+  'paned',
+  'papersize',
+  'placessidebar',
+  'popover',
+  'popovermenu',
+  'printcontext',
+  'printoperation',
+  'printoperationpreview',
+  'printsettings',
+  'progressbar',
+  'radiobutton',
+  'radiomenuitem',
+  'radiotoolbutton',
+  'range',
+  'recentchooser',
+  'recentchooserdialog',
+  'recentchoosermenu',
+  'recentchooserwidget',
+  'recentfilter',
+  'recentinfo',
+  'recentmanager',
+  'requisition',
+  'revealer',
+  'scale',
+  'scalebutton',
+  'scrollable',
+  'scrollbar',
+  'scrolledwindow',
+  'searchbar',
+  'searchentry',
+  'selectiondata',
+  'separator',
+  'separatormenuitem',
+  'separatortoolitem',
+  'settings',
+  'shortcutlabel',
+  'shortcutsgroup',
+  'shortcutssection',
+  'shortcutsshortcut',
+  'shortcutswindow',
+  'sizegroup',
+  'spinbutton',
+  'spinner',
+  'stack',
+  'stacksidebar',
+  'stackswitcher',
+  'statusbar',
+  'stylecontext',
+  'styleprovider',
+  'switch',
+  'targetlist',
+  'textattributes',
+  'textbuffer',
+  'textchildanchor',
+  'textiter',
+  'textmark',
+  'texttag',
+  'texttagtable',
+  'textview',
+  'togglebutton',
+  'toggletoolbutton',
+  'toolbar',
+  'toolbutton',
+  'toolitem',
+  'toolitemgroup',
+  'toolpalette',
+  'toolshell',
+  'tooltip',
+  'treedragdest',
+  'treedragsource',
+  'treeiter',
+  'treemodel',
+  'treemodelfilter',
+  'treemodelsort',
+  'treepath',
+  'treerowreference',
+  'treeselection',
+  'treesortable',
+  'treestore',
+  'treeview',
+  'treeviewcolumn',
+  'viewport',
+  'volumebutton',
+  'widget',
+  'widgetpath',
+  'window',
+  'windowgroup',
+]
+
+gtkmm_posix_hg_ccg_basenames = [
+  'pagesetupunixdialog',
+  'printer',
+  'printjob',
+  'printunixdialog',
+]
+
+gtkmm_x11_hg_ccg_basenames = [
+  'plug',
+  'socket',
+]
+
+gtkmm_deprecated_hg_ccg_basenames = [
+  'actiongroup',
+  'alignment',
+  'arrow',
+  'colorselection',
+  'fontselection',
+  'handlebox',
+  'hvbuttonbox',
+  'hvpaned',
+  'hvscale',
+  'hvscrollbar',
+  'hvseparator',
+  'iconfactory',
+  'iconset',
+  'iconsource',
+  'imagemenuitem',
+  'numerableicon',
+  'radioaction',
+  'recentaction',
+  'statusicon',
+  'stockitem',
+  'table',
+  'tearoffmenuitem',
+  'toggleaction',
+  'uimanager',
+]
+
+# Pairs of hand-coded .h and .cc files.
+gtkmm_extra_any_h_cc_basenames = [
+  'accelkey',
+  'accelmap',
+  'cellrenderer_generation',
+  'childpropertyproxy',
+  'childpropertyproxy_base',
+  'listviewtext',
+  'object',
+  'radiobuttongroup',
+  'selectiondata_private',
+  'styleproperty',
+  'targetentry',
+  'treemodelcolumn',
+  'treeview_private',
+]
+
+gtkmm_extra_deprecated_h_cc_basenames = [
+  'stock',
+  'stockid',
+]
+
+gtkmm_extra_h_files = [
+  'base.h',
+  'wrap_init.h',
+]
+
+gtkmm_extra_cc_files = []
+
+gtkmm_extra_ph_files = [
+  'private' / 'object_p.h',
+]
+
+# All .hg/.ccg files, regardless of deprecation and type of host.
+gtkmm_hg_ccg_basenames = \
+  gtkmm_any_hg_ccg_basenames + \
+  gtkmm_posix_hg_ccg_basenames + \
+  gtkmm_x11_hg_ccg_basenames + \
+  gtkmm_deprecated_hg_ccg_basenames
+
+# Used .hg/.ccg files in the present build.
+gtkmm_used_hg_ccg_basenames = gtkmm_any_hg_ccg_basenames
+if not is_host_windows
+  gtkmm_used_hg_ccg_basenames += gtkmm_posix_hg_ccg_basenames
+endif
+if build_x11_api
+  gtkmm_used_hg_ccg_basenames += gtkmm_x11_hg_ccg_basenames
+endif
+if build_deprecated_api
+  gtkmm_used_hg_ccg_basenames += gtkmm_deprecated_hg_ccg_basenames
+endif
+
+foreach file : gtkmm_extra_any_h_cc_basenames
+  gtkmm_extra_h_files += file + '.h'
+  gtkmm_extra_cc_files += file + '.cc'
+endforeach
+gtkmm_extra_deprecated_h_files = []
+gtkmm_extra_deprecated_cc_files = []
+foreach file : gtkmm_extra_deprecated_h_cc_basenames
+  gtkmm_extra_deprecated_h_files += file + '.h'
+  gtkmm_extra_deprecated_cc_files += file + '.cc'
+endforeach
+gtkmm_extra_used_h_files = gtkmm_extra_h_files
+gtkmm_extra_used_cc_files = gtkmm_extra_cc_files
+gtkmm_extra_h_files += gtkmm_extra_deprecated_h_files
+gtkmm_extra_cc_files += gtkmm_extra_deprecated_cc_files
+if build_deprecated_api
+  gtkmm_extra_used_h_files += gtkmm_extra_deprecated_h_files
+  gtkmm_extra_used_cc_files += gtkmm_extra_deprecated_cc_files
+endif
+
+install_headers('..' / 'gtkmm.h', subdir: gtkmm_pcname)
+install_headers(gtkmm_extra_used_h_files, subdir: gtkmm_pcname / 'gtkmm')
+install_headers(gtkmm_extra_ph_files, subdir: gtkmm_pcname / 'gtkmm' / 'private')
+
+untracked_gtkmm = 'untracked' / 'gtk' / 'gtkmm'
+src_untracked_gtkmm = project_source_root / untracked_gtkmm
+
+gtkmm_cpp_args = [ '-DGTKMM_BUILD=1' ]
+
+if is_msvc and not build_shared_libs_directly
+  gtkmm_cpp_args += '-DGTKMM_USE_GENDEF'
+endif
+
+if maintainer_mode
+
+  # Maintainer mode. Generate .h and .cc files from .hg and .ccg files in ../src.
+
+  # docs/reference/meson.build needs these.
+  built_files_root = project_build_root
+  gtkmm_built_h_file_targets = []
+
+  # Force meson+ninja to generate source files before anything is compiled.
+  # Compilation must depend on these targets.
+  gtkmm_used_built_cc_file_targets = []
+  gtkmm_used_built_h_file_targets = []
+
+  hg_files = []
+  foreach file : gtkmm_hg_ccg_basenames
+    hg_files += '..' / 'src' / file + '.hg'
+  endforeach
+
+  # Create wrap_init.cc in project_build_root/gtk/gtkmm.
+  gtkmm_used_built_cc_file_targets += custom_target('gtkmm-wrap_init.cc',
+    input: hg_files,
+    output: 'wrap_init.cc',
+    command: [
+      python3, generate_binding_py, 'generate_wrap_init',
+      gmmproc_dir,
+      '@OUTPUT@',
+      'Gtk', # namespace
+      '@INPUT@',
+    ],
+    build_by_default: maintainer_mode,
+    install: false,
+  )
+
+  # Create .h/_p.h/.cc files in project_build_root/gtk/gtkmm
+  # from .hg/.ccg files in project_source_root/gtk/src.
+  foreach file : gtkmm_hg_ccg_basenames
+    hg_file = '..' / 'src' / file + '.hg'
+    ccg_file = '..' / 'src' / file + '.ccg'
+    built_file_target = custom_target('gtkmm-' + file + '.cc',
+      input: [hg_file, ccg_file],
+      output: [file + '.stamp', file + '.cc', file + '.h'],
+      command: [
+        python3, generate_binding_py, 'gmmproc',
+        gmmproc_dir,
+        '@OUTPUT0@',
+        file,
+        meson.current_source_dir() / '..' / 'src',
+        project_source_root / 'tools' / 'm4',
+        gmmproc_extra_m4_dirs,
+      ],
+      depend_files: gtkmm_defs_files + m4_files,
+      build_by_default: maintainer_mode,
+      install: false,
+    )
+    gtkmm_built_h_file_targets += built_file_target[2]
+    if gtkmm_used_hg_ccg_basenames.contains(file)
+      gtkmm_used_built_cc_file_targets += built_file_target[1]
+      gtkmm_used_built_h_file_targets += built_file_target[2]
+    endif
+  endforeach
+
+  # Create dummy_header.h, depending on all generated headers.
+  # It's created if it does not exist, but it's never updated.
+  # It guarantees that all generated headers are built before gtkmm_library
+  # is built, at the same time avoiding unnecessary recompilations.
+  # If gtkmm_used_built_h_file_targets would be listed as sources to gtkmm_library,
+  # all generated .cc files could be recompiled if one generated .h file has
+  # been changed.
+  built_dummy_h_file_target = custom_target('gtkmm-dummy_header.h',
+    input: gtkmm_used_built_h_file_targets,
+    output: 'dummy_header.h',
+    command: [
+      python3, dummy_header_py,
+      '@OUTPUT@',
+    ],
+    build_by_default: maintainer_mode,
+    install: false,
+  )
+
+  extra_include_dirs = ['..', '..' / '..' / 'gdk']
+
+  gtk_gen_sources = gtkmm_used_built_cc_file_targets
+
+  built_h_cc_dir = meson.current_build_dir()
+
+else # not maintainer_mode
+
+  # Not maintainer mode. Compile built source code files in
+  # project_source_root/untracked/gtk/gtkmm.
+
+  gtkmm_used_built_h_file_targets = []
+
+  # docs/reference/meson.build needs these.
+  built_files_root = project_source_root / 'untracked'
+  gtkmm_built_h_file_targets = []
+
+  # Two cases:
+  # 1. The source code comes from a tarball, where the built files
+  #    are stored in project_source_root/untracked.
+  #    There are no built files in the build tree.
+  # 2. Files have been built in the build tree. Then maintainer_mode has
+  #    been changed from true to false. Files that are missing or not up to date
+  #    in project_source_root/untracked are copied from the build tree.
+
+  # Try to copy built source code files to the source tree.
+  run_command(
+    python3, generate_binding_py, 'copy_built_files',
+    meson.current_build_dir(),
+    src_untracked_gtkmm,
+    gtkmm_hg_ccg_basenames,
+  )
+
+  built_cc_files = [ src_untracked_gtkmm / 'wrap_init.cc' ]
+  foreach file : gtkmm_used_hg_ccg_basenames
+    built_cc_files += src_untracked_gtkmm / file + '.cc'
+  endforeach
+
+  gtk_gen_sources = built_cc_files
+  built_dummy_h_file_target = []
+
+  extra_include_dirs = [ '..', '..' / '..' / 'untracked' / 'gtk',
+          '..' / '..' / 'gdk', '..' / '..' / 'untracked' / 'gdk',
+  ]
+
+  built_h_cc_dir = src_untracked_gtkmm
+
+endif
+
+extra_gtkmm_objects = []
+
+# Build the .rc file for Windows builds and link to it
+if is_host_windows
+  windows = import('windows')
+  gtkmm_res = windows.compile_resources(gtkmm_rc)
+  extra_gtkmm_objects += gtkmm_res
+endif
+
+if build_shared_libs_directly
+  gtkmm_library = library(gtkmm_pcname, extra_gtkmm_objects,
+    gtk_gen_sources, built_dummy_h_file_target, gtkmm_extra_used_cc_files,
+    include_directories: extra_include_dirs,
+    cpp_args: gtkmm_cpp_args,
+    version: gtkmm_libversion,
+    dependencies: gtkmm_build_dep,
+    link_with: gdkmm_library,
+    install: true,
+  )
+else
+  # Building with headers generated from *.hg files with
+  # gmmproc < 2.64.0 on Visual Studio: We need this so
+  # that we can run gendef.exe to get the .def file
+  # needed for obtaining the .lib file for the gtkmm DLL
+  gtk_int_lib = static_library('gtkmm-int',
+    gtk_gen_sources, built_dummy_h_file_target, gtkmm_extra_used_cc_files,
+    include_directories: extra_include_dirs,
+    cpp_args: gtkmm_cpp_args,
+    dependencies: gtkmm_build_dep,
+    link_with: gdkmm_library,
+    install: false,
+  )
+
+  gtkmm_def = custom_target('gtkmm.def',
+    output: 'gtkmm.def',
+    depends: gtk_int_lib,
+    command: [ gendef,
+      '@OUTPUT@',
+      '@0@-@1@.dll'.format(gtkmm_pcname, gtkmm_libversion.split('.')[0]),
+      gtk_int_lib.full_path(),
+    ],
+    install: false,
+  )
+  gtkmm_extra_link_args = ['/def:@0@'.format(gtkmm_def.full_path())]
+
+  gtkmm_library = library(gtkmm_pcname, extra_gtkmm_objects,
+    objects: gtk_int_lib.extract_all_objects(),
+    version: gtkmm_libversion,
+    dependencies: gtkmm_build_dep,
+    link_depends: gtkmm_def,
+    link_args: gtkmm_extra_link_args,
+    install: true,
+  )
+endif
+
+# Install built .h and _p.h files.
+meson.add_install_script(
+  python3.path(), generate_binding_py, 'install_built_h_files',
+  built_h_cc_dir,
+  install_includedir / gtkmm_pcname / 'gtkmm', # subdir below {prefix}
+  gtkmm_used_hg_ccg_basenames
+)
+
+if not meson.is_subproject()
+  # Distribute built files.
+  # (add_dist_script() is not allowed in a subproject)
+  meson.add_dist_script(
+    python3.path(), generate_binding_py, 'dist_built_files',
+    built_h_cc_dir,
+    untracked_gtkmm,
+    gtkmm_hg_ccg_basenames,
+  )
+endif
+
+# This is useful in the main project when gtkmm is used as a subproject.
+# It's also used when building demo programs and test programs.
+gtkmm_dep = declare_dependency(
+  sources: gdkmm_used_built_h_file_targets + gtkmm_used_built_h_file_targets,
+  link_with: [gdkmm_library, gtkmm_library],
+  include_directories: extra_include_dirs,
+  dependencies: gtkmm_build_dep,
+)
diff --git a/gtk/gtkmmconfig.h.meson b/gtk/gtkmmconfig.h.meson
new file mode 100644
index 00000000..bbacb747
--- /dev/null
+++ b/gtk/gtkmmconfig.h.meson
@@ -0,0 +1,43 @@
+#ifndef _GTKMM_CONFIG_H
+#define _GTKMM_CONFIG_H
+
+#include <gdkmmconfig.h>
+
+/* Defined when the -Dbuild-atkmm-api=true configure argument was given */
+#mesondefine GTKMM_ATKMM_ENABLED
+
+/* Define to omit deprecated API from gtkmm. */
+#mesondefine GTKMM_DISABLE_DEPRECATED
+
+/* Major version number of gtkmm. */
+#mesondefine GTKMM_MAJOR_VERSION
+
+/* Minor version number of gtkmm. */
+#mesondefine GTKMM_MINOR_VERSION
+
+/* Micro version number of gtkmm. */
+#mesondefine GTKMM_MICRO_VERSION
+
+/* Define when building gtkmm as a static library. */
+#mesondefine GTKMM_STATIC_LIB
+
+/* Enable DLL-specific stuff only when not building a static library. */
+#if (!defined(GTKMM_STATIC_LIB) && !defined(__CYGWIN__) && defined(_WIN32))
+# define GTKMM_DLL 1
+#endif
+
+#ifdef GTKMM_DLL
+# if defined(GTKMM_BUILD) && defined(_WINDLL)
+   /* Do not dllexport as it is handled by gendef on MSVC. */
+#  define GTKMM_API
+# elif !defined(GTKMM_BUILD)
+#  define GTKMM_API __declspec(dllimport)
+# else
+   /* Build a static library. */
+#  define GTKMM_API
+# endif /* GTKMM_BUILD - _WINDLL */
+#else
+# define GTKMM_API
+#endif /* GTKMM_DLL */
+
+#endif /* !_GTKMM_CONFIG_H */
diff --git a/gtk/meson.build b/gtk/meson.build
new file mode 100644
index 00000000..4984ceff
--- /dev/null
+++ b/gtk/meson.build
@@ -0,0 +1,29 @@
+# gtk
+
+# Input: pkg_conf_data, gtkmm_pcname, install_pkgconfigdir, install_libdir
+# Output: install_gtkmmconfigdir, gtkmmconfig_h
+
+configure_file(
+  input: 'gtkmm.pc.in',
+  output: gtkmm_pcname + '.pc',
+  configuration: pkg_conf_data,
+  install_dir: install_pkgconfigdir,
+)
+
+gtkmm_pkg_uninst_conf_data = configuration_data()
+gtkmm_pkg_uninst_conf_data.merge_from(pkg_conf_data)
+gtkmm_pkg_uninst_conf_data.set('srcdir', meson.current_source_dir())
+
+configure_file(
+  input: 'gtkmm-uninstalled.pc.in',
+  output: gtkmm_pcname + '-uninstalled.pc',
+  configuration: gtkmm_pkg_uninst_conf_data,
+)
+
+install_gtkmmconfigdir = install_libdir / gtkmm_pcname / 'include'
+gtkmmconfig_h = configure_file(
+  input: 'gtkmmconfig.h.meson',
+  output: 'gtkmmconfig.h',
+  configuration: pkg_conf_data,
+  install_dir: install_gtkmmconfigdir,
+)
diff --git a/meson.build b/meson.build
new file mode 100644
index 00000000..f0076530
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,432 @@
+# This file is part of gtkmm.
+
+# The resource compiler, used in demos/gtk-demo, requires a C compiler.
+project('gtkmm', 'c', 'cpp',
+  version: '3.24.2',
+  license: 'LGPLv2.1+',
+  default_options: [
+    'cpp_std=c++11'
+  ],
+  meson_version: '>= 0.50.0', # required for python3.path()
+)
+
+gtkmm_api_version = '3.0'
+gtkmm_pcname = meson.project_name() + '-' + gtkmm_api_version
+gdkmm_pcname = 'gdkmm-' + gtkmm_api_version
+
+gtkmm_version_array = meson.project_version().split('.')
+gtkmm_major_version = gtkmm_version_array[0].to_int()
+gtkmm_minor_version = gtkmm_version_array[1].to_int()
+gtkmm_micro_version = gtkmm_version_array[2].to_int()
+
+# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+# The relation between libtool's current:revison:age interface versioning
+# and the .so filename, .so.x.y.z, is
+# x = current - age
+# y = age
+# z = revision
+# If libtool_soversion is updated as described in libtool's documentation,
+# x.y.z will usually *not* be equal to meson.project_version().
+libtool_soversion = [2, 0, 1]
+gtkmm_libversion = '@0@.@1@.@2@'.format(
+  libtool_soversion[0] - libtool_soversion[2],
+  libtool_soversion[2],
+  libtool_soversion[1])
+
+# Use these instead of meson.source_root() and meson.build_root() in subdirectories.
+# source_root() and build_root() are not useful, if this is a subproject.
+project_source_root = meson.current_source_dir()
+project_build_root = meson.current_build_dir()
+
+cpp_compiler = meson.get_compiler('cpp')
+is_msvc = cpp_compiler.get_id() == 'msvc'
+is_host_windows = host_machine.system() == 'windows'
+python3 = import('python').find_installation('python3')
+
+python_version = python3.language_version()
+python_version_req = '>= 3.5'
+if not python_version.version_compare(python_version_req)
+  error('Requires Python @0@, found @1@.'.format(python_version_req, python_version))
+endif
+
+# Do we build from a git repository?
+# Suppose we do if and only if a '.git' directory or file exists.
+cmd_py = '''
+import os
+import sys
+sys.exit(os.path.isdir("@0@") or os.path.isfile("@0@"))
+'''.format(project_source_root / '.git')
+is_git_build = run_command(python3, '-c', cmd_py).returncode() != 0
+
+# Are we testing a dist tarball while it's being built?
+# There ought to be a better way. https://github.com/mesonbuild/meson/issues/6866
+is_dist_check = project_source_root.contains('dist-unpack') and \
+                project_build_root.contains('dist-build')
+
+# Options.
+maintainer_mode_opt = get_option('maintainer-mode')
+maintainer_mode = maintainer_mode_opt == 'true' or \
+                 (maintainer_mode_opt == 'if-git-build' and is_git_build)
+if is_dist_check
+  message('Looks like a tarball is being tested. ' + \
+  'Option "dist-warnings" is used instead of "warnings".')
+  warning_level = get_option('dist-warnings')
+else
+  warning_level = get_option('warnings')
+endif
+build_deprecated_api = get_option('build-deprecated-api')
+build_atkmm_api = get_option('build-atkmm-api')
+build_x11_api_opt = get_option('build-x11-api')
+build_documentation_opt = get_option('build-documentation')
+build_documentation = build_documentation_opt == 'true' or \
+                     (build_documentation_opt == 'if-maintainer-mode' and maintainer_mode)
+build_demos = get_option('build-demos')
+build_tests = get_option('build-tests')
+
+# Installation directories are relative to {prefix}.
+install_prefix = get_option('prefix')
+install_includedir = get_option('includedir')
+install_libdir = get_option('libdir')
+install_datadir = get_option('datadir')
+install_pkgconfigdir = install_libdir / 'pkgconfig'
+
+# Dependencies. <pkg> = gdk and gtk
+# <pkg>mm_build_dep: Dependencies when building the <pkg>mm library.
+# <pkg>mm_dep (created in <pkg>/<pkg>mm/meson.build):
+#   Dependencies when using the <pkg>mm library.
+
+# glibmm recently gained Meson build support, so we can try looking
+# for its pkg-config files on Visual Studio as well
+glibmm_req = '>= 2.54.0'
+
+# Gtk supported pkg-config files on MSVC files for a good while, so just use that
+gtk_req = '>= 3.24.0'
+gtk_dep = dependency('gtk+-3.0', version: gtk_req)
+
+cairomm_req = '>= 1.12.0'
+cairomm_dep = dependency('cairomm-1.0', version: cairomm_req)
+
+pangomm_req = '>= 2.38.2'
+pangomm_dep = dependency('pangomm-1.4', version: pangomm_req)
+
+gdk_pixbuf_req = '>= 2.35.5'
+gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req)
+
+# atkmm is required in maintainer mode even if atkmm API shall not be built.
+# gmmproc must be able to find atkmm's installed M4 files.
+atkmm_req = '>= 2.24.2'
+atkmm_dep = dependency('atkmm-1.6', version: atkmm_req, required: build_atkmm_api or maintainer_mode)
+
+epoxy_req = '>= 1.2'
+epoxy_dep = dependency('epoxy', version: epoxy_req, required: build_demos)
+
+# The -mm libraries do not yet have pkg-config files for MSVC builds,
+# so check for them manually
+glibmm_req_minor_ver = '4'
+
+glibmm_dep = dependency('glibmm-2.@0@'.format(glibmm_req_minor_ver), version: glibmm_req, required: not 
is_msvc)
+giomm_dep = dependency('giomm-2.@0@'.format(glibmm_req_minor_ver), version: glibmm_req, required: not 
is_msvc)
+
+# Where to find gmmproc and generate_wrap_init.pl.
+if glibmm_dep.found() and glibmm_dep.type_name() == 'pkgconfig'
+  gmmproc_dir = glibmm_dep.get_pkgconfig_variable('gmmprocdir')
+else
+  # We don't have a pkg-config file for glibmm, so use build option.
+  gmmproc_dir = get_option('gmmproc-dir')
+endif
+
+gmmproc_extra_m4_dirs = [pangomm_dep.get_pkgconfig_variable('gmmprocm4dir')]
+if atkmm_dep.found()
+  gmmproc_extra_m4_dirs += [atkmm_dep.get_pkgconfig_variable('gmmprocm4dir')]
+endif
+
+# Is X11 backend available?
+if build_x11_api_opt == 'false'
+  build_x11_api = false
+else
+  backends = gtk_dep.get_pkgconfig_variable('targets').split()
+  if build_x11_api_opt == 'if-enabled-in-gdk'
+    build_x11_api = backends.contains('x11')
+  else # build_x11_api_opt == 'true'
+    build_x11_api = true
+    if not backends.contains('x11')
+      error('Requested X11 backend not supported by installed gdk.')
+    endif
+  endif
+endif
+
+if is_msvc
+  # We must have Visual Studio 2013 or later...
+  assert(cpp_compiler.version().split('.')[0].to_int() >= 18, 'Visual Studio 2013 or later is required')
+
+  sigc_major_ver = '2'
+
+  if not glibmm_dep.found()
+    assert(cpp_compiler.has_header('sigc++-@0@.0/sigc++/sigc++.h'.format(sigc_major_ver)) and 
cpp_compiler.has_header('sigc++-@0@.0/include/sigc++config.h'.format(sigc_major_ver)),
+           'sigc++-@0@.x headers are required'.format(sigc_major_ver))
+    assert(cpp_compiler.has_header('glibmm-2.@0@/glibmm.h'.format(glibmm_req_minor_ver)) and 
cpp_compiler.has_header('glibmm-2.@0@/include/glibmmconfig.h'.format(glibmm_req_minor_ver)),
+           'glibmm-2.@0@ headers are required'.format(glibmm_req_minor_ver))
+
+  else
+    sigc_dep = dependency('', required: false) # glibmm covers for libsigc++ in its pkg-config file
+  endif
+  message('Ensure your INCLUDE and LIB contain the paths that lead to the appropriate headers and .lib\'s 
for glibmm-2.@0@ and libsigc++-2.x'.format(glibmm_req_minor_ver))
+
+  # We need to look for appropriate versions of Visual
+  # Studio since those built by NMake and the former
+  # Visual Studio projects are versioned by the VS versions
+  if cpp_compiler.version().split('.')[0].to_int() == 18
+    msvc_check_range = [12] # Visual Studio 2013
+    warning('Visual Studio 2013 must configure without -Dwarnings=fatal, which is the default')
+  elif cpp_compiler.version().split('.')[0].to_int() == 19
+    # Visual Studio 2019 can consume libraries built with 2017 and 2015
+    # and Visual Studio 2017 can consume libraries built with 2015
+    msvc_check_range = [14] # Visual Studio 2015, 2017, 2019
+    message('It is safe to ignore warnings from Meson that MSVC does not support C++11')
+  endif
+
+  debugsuffix = ''
+  if get_option('buildtype') == 'debug'
+    debugsuffix = '-d'
+  endif
+
+  # We can be looking for MSVC 2015-built libraries on 2017 and 2019 builds as well,
+  # as well as 2017-built libraries on 2019 as well, so we can't just assume that
+  # libraries exist, but check that compatible versions are really found
+  foreach v : msvc_check_range
+    glibmm_dep = glibmm_dep.found() ? glibmm_dep : 
cpp_compiler.find_library('glibmm-vc@0@0@1@-2_@2@'.format(v.to_string(), debugsuffix, glibmm_req_minor_ver), 
required: false)
+  endforeach
+
+  # Check whether we compile gtkmm without using gendef
+  build_shared_libs_directly = false
+
+  if glibmm_dep.type_name() == 'library'
+    warning('Note: Be sure to check that this finds the same libsigc++ .lib your glibmm is linked to')
+    sigc_dep = cpp_compiler.find_library('sigc-@0@.0'.format(sigc_major_ver), required: false)
+    foreach v : msvc_check_range
+      sigc_dep = sigc_dep.found() ? sigc_dep : 
cpp_compiler.find_library('sigc-vc@0@0@1@-2_0'.format(v.to_string(), debugsuffix), required: false)
+    endforeach
+  endif
+
+  # Now make sure the appropriate -mm libraries are found
+  assert(glibmm_dep.found() and (glibmm_dep.type_name() == 'pkgconfig' or sigc_dep.found()), 'Appropriate 
glibmm-vcxx0@0@-2_@1@.lib and sigc-vcxx0@0@-@2@_0.lib are required'.format(debugsuffix, glibmm_req_minor_ver, 
sigc_major_ver))
+
+  # Put glibmm in the required packages if we find it by pkg-config
+  mm_lib_requires = ''
+  if glibmm_dep.type_name() == 'pkgconfig'
+    mm_lib_requires += ' '.join([
+      'glibmm-2.@0@'.format(glibmm_req_minor_ver), glibmm_req,
+    ]) + ' '
+  endif
+
+  gtkmm_requires = mm_lib_requires + ' '.join([
+    'gtk+-3.0', gtk_req,
+  ])
+
+  gtkmm_build_dep = [giomm_dep, sigc_dep, gtk_dep]
+else
+  # not MSVC
+  gdkmm_build_dep = [giomm_dep, gtk_dep, cairomm_dep, pangomm_dep, gdk_pixbuf_dep]
+  gdkmm_requires = [
+    'giomm-2.@0@'.format(glibmm_req_minor_ver), glibmm_req,
+    'gtk+-3.0', gtk_req,
+    'cairomm-1.0', cairomm_req,
+    'pangomm-1.4', cairomm_req,
+    'gdk-pixbuf-2.0', gdk_pixbuf_req,
+  ]
+
+  gtk_unix_print_dep = dependency('gtk+-unix-print-3.0')
+  gtkmm_build_dep = gdkmm_build_dep + [gtk_unix_print_dep]
+  gtkmm_requires = gdkmm_requires + ['gtk+-unix-print-3.0', '']
+  if build_atkmm_api
+    gtkmm_build_dep += [atkmm_dep]
+    gtkmm_requires += ['atkmm-1.6', atkmm_req]
+  endif
+
+  gdkmm_requires = ' '.join(gdkmm_requires)
+  gtkmm_requires = ' '.join(gtkmm_requires)
+
+  build_shared_libs_directly = true
+endif
+
+# Some dependencies are required only in maintainer mode and/or if
+# reference documentation shall be built.
+mm_common_get = find_program('mm-common-get', required: false)
+if maintainer_mode and not mm_common_get.found()
+  error('mm-common-get not found. mm-common >= 1.0.0 is required.')
+endif
+m4 = find_program('m4', required: maintainer_mode) # Used by gmmproc (in glibmm)
+perl = find_program('perl', required: maintainer_mode or build_documentation)
+doxygen = find_program('doxygen', required: build_documentation)
+dot = find_program('dot', required: build_documentation) # Used by Doxygen
+xsltproc = find_program('xsltproc', required: build_documentation)
+
+# Script files copied to 'untracked' by mm-common-get.
+script_dir = project_source_root / 'untracked' / 'build_scripts'
+generate_binding_py = script_dir / 'generate-binding.py'
+doc_reference_py = script_dir / 'doc-reference.py'
+dist_changelog_py = script_dir / 'dist-changelog.py'
+dist_build_scripts_py = script_dir / 'dist-build-scripts.py'
+check_dllexport_usage_py = script_dir / 'check-dllexport-usage.py'
+
+if maintainer_mode
+  # Copy files to untracked/build_scripts and untracked/doc.
+  run_command(mm_common_get, '--force', script_dir,
+    project_source_root / 'untracked' / 'docs')
+else
+  cmd_py = '''
+import os
+import sys
+sys.exit(os.path.isfile("@0@"))
+'''.format(generate_binding_py)
+  file_exists = run_command(python3, '-c', cmd_py).returncode() != 0
+  if not file_exists
+    error('Missing files in untracked/. You must enable maintainer-mode.')
+  endif
+endif
+
+# gtkmm's own script files.
+gtkmm_script_dir = project_source_root / 'tools'
+dummy_header_py = gtkmm_script_dir / 'dummy-header.py'
+
+if is_msvc
+  add_project_arguments(cpp_compiler.get_supported_arguments([ '/utf-8', '/wd4828']), language: 'cpp')
+
+  # Check for the first line in a file generated with gmmproc,
+  # to see which gmmproc version was used
+  if maintainer_mode
+    check_gmmproc_ver_cmd = [
+      python3, check_dllexport_usage_py,
+      '--gmmprocdir=@0@'.format(gmmproc_dir),
+    ]
+  else
+    check_gmmproc_ver_cmd = [
+      python3, check_dllexport_usage_py,
+      '--file=@0@/untracked/gtk/gtkmm/aboutdialog.h'.format('/'.join(project_source_root.split('\\')))
+    ]
+  endif
+
+  # Enable __declspec(dllexport) if the gtkmm headers generated from the .hg files
+  # were generated using a recent enough gmmproc
+  build_shared_libs_directly = run_command(check_gmmproc_ver_cmd).returncode() == 0
+  message('Using __declspec(dllexport) to build gtkmm: @0@'.format(build_shared_libs_directly ? 'YES' : 
'NO'))
+endif
+
+# Set compiler warnings.
+warning_flags = []
+if warning_level == 'min'
+  if is_msvc
+    warning_flags = ['/W3']
+  else
+    warning_flags = ['-Wall']
+  endif
+elif warning_level == 'max' or warning_level == 'fatal'
+  if is_msvc
+    warning_flags = ['/W4']
+  else
+    warning_flags = '-pedantic -Wall -Wextra -Wformat-security -Wsuggest-override -Wshadow 
-Wno-long-long'.split()
+  endif
+  if warning_level == 'fatal'
+    if is_msvc
+      warning_flags += ['/WX']
+    else
+      warning_flags += ['-Werror']
+    endif
+    deprecations = 'G PANGO ATK GDK GDK_PIXBUF GTK GLIBMM ATKMM PANGOMM CAIROMM SIGCXX'.split()
+    foreach d : deprecations
+      warning_flags += '-D@0@_DISABLE_DEPRECATED'.format(d)
+    endforeach
+  endif
+endif
+
+warning_flags = cpp_compiler.get_supported_arguments(warning_flags)
+add_project_arguments(warning_flags, language: 'cpp')
+
+# MSVC: Ignore warnings that aren't really harmful, but make those
+#       that should not be overlooked stand out.
+if is_msvc
+  foreach wd : ['/FImsvc_recommended_pragmas.h', '/wd4267', '/wd4530', '/wd4251']
+    disabled_warning = cpp_compiler.get_supported_arguments(wd)
+    add_project_arguments(disabled_warning, language: 'cpp')
+  endforeach
+endif
+
+subdir('tools/extra_defs_gen')
+subdir('MSVC_NMake/gendef')
+subdir('gdk')
+subdir('MSVC_NMake/gdkmm')
+subdir('gdk/gdkmm')
+subdir('gtk')
+subdir('MSVC_NMake/gtkmm')
+subdir('gtk/gtkmm')
+subdir('tests')
+subdir('demos/gtk-demo')
+subdir('docs/reference')
+
+if not meson.is_subproject()
+  # Add a ChangeLog file to the distribution directory.
+  # (add_dist_script() is not allowed in a subproject)
+  meson.add_dist_script(
+    python3.path(), dist_changelog_py,
+    project_source_root,
+  )
+  # Add build scripts to the distribution directory, and delete .gitignore
+  # files and an empty $MESON_DIST_ROOT/build/ directory.
+  meson.add_dist_script(
+    python3.path(), dist_build_scripts_py,
+    project_source_root,
+    'untracked' / 'build_scripts',
+  )
+endif
+
+# Print a summary.
+real_maintainer_mode = ''
+if maintainer_mode_opt == 'if-git-build'
+  real_maintainer_mode = ' (@0@)'.format(maintainer_mode)
+endif
+
+real_build_documentation = ''
+if build_documentation_opt == 'if-maintainer-mode'
+  real_build_documentation = ' (@0@)'.format(build_documentation)
+endif
+
+real_build_x11_api = ''
+if build_x11_api_opt == 'if-enabled-in-gdk'
+  real_build_x11_api = ' (@0@)'.format(build_x11_api)
+endif
+
+summary = [
+  '',
+  '------',
+  meson.project_name() + ' ' + meson.project_version(),
+  '',
+  '         Maintainer mode: @0@@1@'.format(maintainer_mode_opt, real_maintainer_mode),
+  '       Compiler warnings: @0@'.format(warning_level),
+  '    Build deprecated API: @0@'.format(build_deprecated_api),
+  '         Build atkmm API: @0@'.format(build_atkmm_api),
+  '           Build X11 API: @0@@1@'.format(build_x11_api_opt, real_build_x11_api),
+  'Build HTML documentation: @0@@1@'.format(build_documentation_opt, real_build_documentation),
+  '     Build demo programs: @0@'.format(build_demos),
+  '     Build test programs: @0@'.format(build_tests),
+  'Directories:',
+  '                  prefix: @0@'.format(install_prefix),
+  '              includedir: @0@'.format(install_prefix / install_includedir),
+  '         includegdkmmdir: @0@'.format(install_prefix / install_includedir / gdkmm_pcname),
+  '         includegtkmmdir: @0@'.format(install_prefix / install_includedir / gtkmm_pcname),
+  '                  libdir: @0@'.format(install_prefix / install_libdir),
+  '          gdkmmconfigdir: @0@'.format(install_prefix / install_gdkmmconfigdir),
+  '          gtkmmconfigdir: @0@'.format(install_prefix / install_gtkmmconfigdir),
+  '                   m4dir: @0@'.format(install_prefix / install_m4dir),
+  '            pkgconfigdir: @0@'.format(install_prefix / install_pkgconfigdir),
+  '                 datadir: @0@'.format(install_prefix / install_datadir),
+  '                  docdir: @0@'.format(install_prefix / install_docdir),
+  '              devhelpdir: @0@'.format(install_prefix / install_devhelpdir),
+]
+if maintainer_mode
+  summary += [
+    '              gmmprocdir: @0@'.format(gmmproc_dir),
+  ]
+endif
+summary += ['------']
+
+message('\n'.join(summary))
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 00000000..997638ae
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,18 @@
+option('maintainer-mode', type: 'combo', choices: ['false', 'if-git-build', 'true'],
+  value: 'if-git-build', description: 'Generate source code from .hg and .ccg files')
+option('warnings', type: 'combo', choices: ['no', 'min', 'max', 'fatal'], value: 'min',
+  description: 'Compiler warning level')
+option('dist-warnings', type: 'combo', choices: ['no', 'min', 'max', 'fatal'], value: 'fatal',
+  description: 'Compiler warning level when a tarball is created')
+option('build-deprecated-api', type: 'boolean', value: true,
+  description: 'Build deprecated API and include it in the library')
+option('build-atkmm-api', type: 'boolean', value: true,
+  description: 'Build atkmm API and include it in the library')
+option('build-x11-api', type: 'combo', choices: ['false', 'if-enabled-in-gdk', 'true'],
+  value: 'if-enabled-in-gdk', description: 'Build X11 API and include it in the library')
+option('build-documentation', type: 'combo', choices: ['false', 'if-maintainer-mode', 'true'],
+  value: 'if-maintainer-mode', description: 'Build and install the documentation')
+option('build-demos', type: 'boolean', value: true, description: 'Build demo programs')
+option('build-tests', type: 'boolean', value: true, description: 'Build test programs')
+option('gmmproc-dir', type: 'string', value: '',
+  description: 'Directory containing gmmproc and its PERL modules (for MSVC builds only)')
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 00000000..07411a27
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,60 @@
+# tests
+
+# Input: gdkmm_dep, gtkmm_dep, build_tests
+# Output: -
+
+test_programs = [
+# [[dir-name], exe-name, [sources], gtkmm-example (not just gdkmm-example), execute]
+  [['builder'], 'test', ['main.cc'], true, false],
+  [['child_widget'], 'test', ['main.cc', 'testwindow.cc'], true, false],
+  [['child_widget2'], 'test', ['main.cc'], true, false],
+  [['child_widget_managed'], 'test', ['main.cc'], true, false],
+  [['delete_cpp_child'], 'test', ['main.cc'], true, false],
+  [['dialog'], 'test', ['main.cc'], true, false],
+  [['dialog_deletethis'], 'test', ['main.cc'], true, false],
+  [['gdk_rgba'], 'test', ['main.cc'], false, true],
+  [['main_with_options'], 'test', ['main.cc'], true, false],
+  [['menu_destruction'], 'test', ['main.cc'], true, false],
+  [['object_move'], 'test', ['main.cc'], true, true],
+  [['property_notification'], 'test', ['main.cc'], true, false],
+  [['refcount_dialog'], 'test', ['main.cc'], true, false],
+  [['scrolledwindow'], 'test', ['main.cc'], true, false],
+  [['wrap_existing'], 'test', ['main.cc'], true, false],
+]
+
+foreach ex : test_programs
+  dir = ''
+  foreach dir_part : ex[0]
+    dir = dir / dir_part
+  endforeach
+  ex_name = (dir / ex[1]).underscorify()
+  ex_sources = []
+  foreach src : ex[2]
+    ex_sources += dir / src
+  endforeach
+
+  exe_file = executable(ex_name, ex_sources,
+    dependencies: ex[3] ? gtkmm_dep : gdkmm_dep,
+    gui_app: ex[3],
+    build_by_default: build_tests,
+    install: false,
+  )
+
+  if ex[4]
+    test(ex_name, exe_file)
+  endif
+endforeach
+
+# An Autotools build also contains a test that is supposed to check all
+# docs/reference/html/*.html files with xmllint. It's omitted here because
+# 1. the test does not do anything since the wrong directory is searched,
+# 2. it's not clear why 'make check' or 'ninja test' in gtkmm shall fail
+#    if Doxygen writes non-standard html files. (If the right directory is
+#    searched, the test finds errors in at least one html file.)
+
+#test('test_validate_docs_html', python3,
+#  args: [
+#    meson.current_source_dir() / 'test_validate_docs_html.py',
+#    project_build_root / 'docs' / 'reference' / 'html',
+#  ],
+#)
diff --git a/tools/dummy-header.py b/tools/dummy-header.py
new file mode 100755
index 00000000..8c614645
--- /dev/null
+++ b/tools/dummy-header.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with custom_target() in meson.build.
+
+# dummy-header.py <output_file>
+
+import os
+import sys
+
+output_file = sys.argv[1]
+
+# A dummy header file is created if it does not exist, but it's never updated.
+if not os.path.isfile(output_file):
+  with open(output_file, 'w') as f:
+    f.write('// Dummy header file. Created and used by meson.build\n')
diff --git a/tools/extra_defs_gen/meson.build b/tools/extra_defs_gen/meson.build
new file mode 100644
index 00000000..8c654c71
--- /dev/null
+++ b/tools/extra_defs_gen/meson.build
@@ -0,0 +1,36 @@
+# tools/extra_defs_gen
+
+# Input: cpp_compiler, gdkmm_build_dep, gtkmm_build_dep, install_libdir,
+#        gtkmm_pcname
+# Output: m4_files, install_m4dir
+
+glibmm_generate_extra_defs_dep = cpp_compiler.find_library(
+  'glibmm_generate_extra_defs-2.4',
+)
+
+executable('generate_defs_gdk', 'generate_defs_gdk.cc',
+  dependencies: [gdkmm_build_dep, glibmm_generate_extra_defs_dep],
+  install: false,
+)
+
+executable('generate_defs_gtk', 'generate_defs_gtk.cc',
+  dependencies: [gtkmm_build_dep, glibmm_generate_extra_defs_dep],
+  install: false,
+)
+
+# Install m4 files for reuse by other *mm projects, when building from git.
+m4_basefiles = [
+  'child_property.m4',
+  'class_gtkobject.m4',
+  'convert.m4',
+  'convert_gdk.m4',
+  'convert_gtk.m4',
+  'convert_gtkmm.m4',
+]
+m4_files = []
+foreach file : m4_basefiles
+  m4_files += '..' / 'm4' / file
+endforeach
+m4_files = files(m4_files)
+install_m4dir = install_libdir / gtkmm_pcname / 'proc' / 'm4'
+install_data(m4_files, install_dir: install_m4dir)
diff --git a/untracked/README b/untracked/README
new file mode 100644
index 00000000..a4392ab3
--- /dev/null
+++ b/untracked/README
@@ -0,0 +1,40 @@
+untracked/README
+
+This directory contains files not tracked by a source code control program,
+such as git. (This README file is the exception.)
+
+The files can have one of two origins.
+
+1. Copied by the mm-common-get command.
+2. Generated when gtkmm is built.
+
+Files of type 2 exist here only if gtkmm is built with maintainer-mode=false,
+or the directory comes from a tarball.
+Files of both types exist here only if gtkmm is built with Meson,
+or the tarball is created with Meson.
+
+1. Files copied by mm-common-get
+--------------------------------
+untracked/docs/doc-install.pl
+               doc-postprocess.pl
+               doxygen-extra.css
+               tagfile-to-devhelp2.xsl
+untracked/build_scripts/check-dllexport-usage.py
+                        dist-build-scripts.py
+                        dist-changelog.py
+                        doc-reference.py
+                        generate-binding.py
+
+mm-common-get may copy more files, but they are not used by gtkmm.
+
+2. Generated files
+------------------
+untracked/gdk/gdkmm/*.h
+                    *.cc
+                    private/*_p.h
+untracked/gtk/gtkmm/*.h
+                    *.cc
+                    private/*_p.h
+untracked/docs/reference/gtkmm-3.0.devhelp2
+                         gtkmm-3.0.tag
+                         html/*


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]