[gtkmm/use-dllexport: 43/60] Add support for building gtkmm with Meson



commit e4f49de0d57be395cb3681e7fb2237292184032c
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Tue Jun 2 18:57:37 2020 +0200

    Add support for building gtkmm with Meson
    
    gtkmm-4.0 can be built with either Autotools or Meson.
    New files have been copied from gtkmm-3.0 and modified.
    
    See MR !27

 MSVC_NMake/gdkmm/meson.build     |  11 +
 MSVC_NMake/gendef/meson.build    |   9 +
 MSVC_NMake/gtkmm/meson.build     |  17 ++
 Makefile.am                      |  20 ++
 demos/gtk-demo/meson.build       |  53 ++++
 docs/reference/meson.build       | 173 +++++++++++++
 gdk/gdkmm/meson.build            | 271 ++++++++++++++++++++
 gdk/gdkmmconfig.h.meson          |  18 ++
 gdk/meson.build                  |  53 ++++
 gtk/gtkmm/meson.build            | 526 +++++++++++++++++++++++++++++++++++++++
 gtk/gtkmmconfig.h.meson          |  43 ++++
 gtk/meson.build                  |  29 +++
 meson.build                      | 358 ++++++++++++++++++++++++++
 meson_options.txt                |  16 ++
 tests/meson.build                |  61 +++++
 tools/dummy-header.py            |  15 ++
 tools/extra_defs_gen/meson.build |  35 +++
 untracked/README                 |  40 +++
 18 files changed, 1748 insertions(+)
---
diff --git a/MSVC_NMake/gdkmm/meson.build b/MSVC_NMake/gdkmm/meson.build
new file mode 100644
index 00000000..849157b9
--- /dev/null
+++ b/MSVC_NMake/gdkmm/meson.build
@@ -0,0 +1,11 @@
+# MSVC_NMake/gdkmm
+
+# Input: gdkmmconfig_h
+# Output: -
+
+# 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 713e2b91..f94f297d 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..c1510995
--- /dev/null
+++ b/demos/gtk-demo/meson.build
@@ -0,0 +1,53 @@
+# demos/gtk-demo
+
+# Input: gtkmm_dep, epoxy_dep, build_demos, gui_app_ldflags, gtkmm_extra_gendef_cpp_args
+# Output: -
+
+gtkmm_demo_cc_files = [
+  'main.cc',
+  'demowindow.cc',
+  'textwidget.cc',
+  'example_appwindow.cc',
+  'example_builder.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_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,
+    link_args: gui_app_ldflags,
+    cpp_args: gtkmm_extra_gendef_cpp_args,
+    install: false,
+  )
+endif
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
new file mode 100644
index 00000000..241aa23f
--- /dev/null
+++ b/docs/reference/meson.build
@@ -0,0 +1,173 @@
+# docs/reference
+
+# Input: built_files_root, project_source_root, gdkmm_pcname, gtkmm_pcname,
+#        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++-3.0',
+  'glibmm-2.66',
+  'cairomm-1.16',
+  'pangomm-2.44',
+  'atkmm-2.30',
+]
+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)
+
+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..293dc928
--- /dev/null
+++ b/gdk/gdkmm/meson.build
@@ -0,0 +1,271 @@
+# gdk/gdkmm
+
+# Input: gdkmm_build_dep, gtkmm_pcname, maintainer_mode, project_source_root,
+#        generate_binding_py, m4_files, install_includedir, python3,
+#        dummy_header_py, gmmproc_dir, build_deprecated_api,
+#        gmmproc_extra_m4_dirs, gdkmm_extra_gendef_cpp_args
+# Output: gdkmm_hg_ccg_basenames, gdkmm_extra_h_files, built_files_root,
+#         gdkmm_built_h_file_targets, gdkmm_used_built_h_file_targets,
+#         gdkmm_library
+
+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_vfuncs.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',
+  'cairocontext',
+  'clipboard',
+  'contentformats',
+  'contentformatsbuilder',
+  'contentprovider',
+  'cursor',
+  'device',
+  'devicepad',
+  'devicetool',
+  'display',
+  'displaymanager',
+  'drag',
+  'dragsurface',
+  'drawcontext',
+  'drop',
+  'enums',
+  'event',
+  'frameclock',
+  'frametimings',
+  'glcontext',
+  'gltexture',
+  'monitor',
+  'paintable',
+  'pixbuf',
+  'pixbufanimation',
+  'pixbufanimationiter',
+  'pixbufformat',
+  'pixbufloader',
+  'popup',
+  'popuplayout',
+  'rectangle',
+  'rgba',
+  'seat',
+  'snapshot',
+  'surface',
+  'texture',
+  'timecoord',
+  'toplevel',
+  'toplevellayout',
+  'types',
+]
+
+gdkmm_deprecated_hg_ccg_basenames = []
+
+# Pairs of hand-coded .h and .cc files.
+gdkmm_extra_any_h_cc_basenames = [
+  'cairoutils',
+  'devicewithpad',
+  'general',
+  'value_cairo',
+]
+
+gdkmm_extra_cc_files = []
+
+gdkmm_extra_h_files = [
+  '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
+
+foreach file : gdkmm_extra_any_h_cc_basenames
+  gdkmm_extra_h_files += file + '.h'
+  gdkmm_extra_cc_files += file + '.cc'
+endforeach
+
+install_headers('..' / 'gdkmm.h', subdir: gtkmm_pcname)
+install_headers(gdkmm_extra_h_files, subdir: gtkmm_pcname / 'gdkmm')
+
+untracked_gdkmm = 'untracked' / 'gdk' / 'gdkmm'
+src_untracked_gdkmm = project_source_root / untracked_gdkmm
+
+gdkmm_cpp_args = [ '-DGDKMM_BUILD=1' ] + gdkmm_extra_gendef_cpp_args
+
+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
+
+# This is an internal static library.
+# The objects in this library will be included in gtkmm_library.
+gdkmm_library = static_library('gdkmm',
+  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,
+)
+
+# 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 / '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
+
+# We don't define gdkmm_dep = declare_dependency() with gdkmm_library,
+# which is an internal library.
diff --git a/gdk/gdkmmconfig.h.meson b/gdk/gdkmmconfig.h.meson
new file mode 100644
index 00000000..872cc8b1
--- /dev/null
+++ b/gdk/gdkmmconfig.h.meson
@@ -0,0 +1,18 @@
+#ifndef _GDKMM_CONFIG_H
+#define _GDKMM_CONFIG_H
+
+#include <pangommconfig.h>
+
+/* 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..7ebf3a3e
--- /dev/null
+++ b/gdk/meson.build
@@ -0,0 +1,53 @@
+# gdk
+
+# Input: install_prefix, install_libdir, install_datadir, install_includedir,
+#        gtkmm_pcname, gtkmm_api_version, gtkmm_requires, build_deprecated_api,
+#        cpp_compiler, gtkmm_major_version, gtkmm_minor_version,
+#        gtkmm_micro_version, build_atkmm_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('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
+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('GTKMM_STATIC_LIB', 1)
+endif
+
+install_gdkmmconfigdir = install_libdir / gtkmm_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..4d1e98a2
--- /dev/null
+++ b/gtk/gtkmm/meson.build
@@ -0,0 +1,526 @@
+# 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, gmmproc_extra_m4_dirs, is_host_windows,
+#        gdkmm_library, gdkmm_used_built_h_file_targets, gtkmm_extra_gendef_cpp_args
+# 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',
+  'accellabel',
+  'actionable',
+  'actionbar',
+  'adjustment',
+  'appchooser',
+  'appchooserbutton',
+  'appchooserdialog',
+  'appchooserwidget',
+  'application',
+  'applicationwindow',
+  'aspectframe',
+  'assistant',
+  'assistantpage',
+  'binlayout',
+  'border',
+  'box',
+  'boxlayout',
+  'buildable',
+  'builder',
+  'button',
+  'calendar',
+  'cellarea',
+  'cellareabox',
+  'cellareacontext',
+  'celleditable',
+  'celllayout',
+  'cellrenderer',
+  'cellrendereraccel',
+  'cellrenderercombo',
+  'cellrendererpixbuf',
+  'cellrendererprogress',
+  'cellrendererspin',
+  'cellrendererspinner',
+  'cellrenderertext',
+  'cellrenderertoggle',
+  'cellview',
+  'centerbox',
+  'centerlayout',
+  'checkbutton',
+  'colorbutton',
+  'colorchooser',
+  'colorchooserdialog',
+  'combobox',
+  'comboboxtext',
+  'constraint',
+  'constraintguide',
+  'constraintlayout',
+  'constrainttarget',
+  'csslocation',
+  'cssprovider',
+  'csssection',
+  'dialog',
+  'dragicon',
+  'dragsource',
+  'drawingarea',
+  'dropcontrollermotion',
+  'droptarget',
+  'droptargetasync',
+  'editable',
+  'emojichooser',
+  'entry',
+  'entrycompletion',
+  'entrybuffer',
+  'enums',
+  'eventcontroller',
+  'eventcontrollerfocus',
+  'eventcontrollerkey',
+  'eventcontrollermotion',
+  'eventcontrollerscroll',
+  'expander',
+  'filechooser',
+  'filechooserbutton',
+  'filechooserdialog',
+  'filechoosernative',
+  'filechooserwidget',
+  'filefilter',
+  'fixed',
+  'flowbox',
+  'flowboxchild',
+  'fontbutton',
+  'fontchooser',
+  'fontchooserdialog',
+  'fontchooserwidget',
+  'frame',
+  'gesture',
+  'gestureclick',
+  'gesturedrag',
+  'gesturelongpress',
+  'gesturepan',
+  'gesturerotate',
+  'gesturesingle',
+  'gesturestylus',
+  'gestureswipe',
+  'gesturezoom',
+  'glarea',
+  'grid',
+  'gridlayout',
+  'gridlayoutchild',
+  'headerbar',
+  'iconpaintable',
+  'icontheme',
+  'iconview',
+  'image',
+  'infobar',
+  'label',
+  'layoutchild',
+  'layoutmanager',
+  'levelbar',
+  'linkbutton',
+  'listbox',
+  'listboxrow',
+  'liststore',
+  'lockbutton',
+  'main',
+  'mediacontrols',
+  'mediafile',
+  'mediastream',
+  'menubutton',
+  'messagedialog',
+  'native',
+  'nativedialog',
+  'noselection',
+  'notebook',
+  'notebookpage',
+  'orientable',
+  'overlay',
+  'padactionentry',
+  'padcontroller',
+  'pagesetup',
+  'paned',
+  'papersize',
+  'passwordentry',
+  'picture',
+  'popover',
+  'popovermenu',
+  'popovermenubar',
+  'printcontext',
+  'printoperation',
+  'printoperationpreview',
+  'printsettings',
+  'progressbar',
+  'radiobutton',
+  'range',
+  'recentinfo',
+  'recentmanager',
+  'requisition',
+  'revealer',
+  'root',
+  'scale',
+  'scalebutton',
+  'scrollable',
+  'scrollbar',
+  'scrolledwindow',
+  'searchbar',
+  'searchentry',
+  'selectionmodel',
+  'separator',
+  'settings',
+  'shortcutlabel',
+  'shortcutsgroup',
+  'shortcutssection',
+  'shortcutsshortcut',
+  'shortcutswindow',
+  'singleselection',
+  'sizegroup',
+  'snapshot',
+  'spinbutton',
+  'spinner',
+  'stack',
+  'stackpage',
+  'stacksidebar',
+  'stackswitcher',
+  'statusbar',
+  'stylecontext',
+  'styleprovider',
+  'switch',
+  'text',
+  'textbuffer',
+  'textchildanchor',
+  'textiter',
+  'textmark',
+  'texttag',
+  'texttagtable',
+  'textview',
+  'togglebutton',
+  'tooltip',
+  'treedragdest',
+  'treedragsource',
+  'treeiter',
+  'treemodel',
+  'treemodelfilter',
+  'treemodelsort',
+  'treepath',
+  'treerowreference',
+  'treeselection',
+  'treesortable',
+  'treestore',
+  'treeview',
+  'treeviewcolumn',
+  'video',
+  'viewport',
+  'volumebutton',
+  'widget',
+  'widgetpaintable',
+  'window',
+  'windowcontrols',
+  'windowgroup',
+  'windowhandle',
+]
+
+gtkmm_posix_hg_ccg_basenames = [
+  'pagesetupunixdialog',
+  'printer',
+  'printjob',
+  'printunixdialog',
+]
+
+gtkmm_deprecated_hg_ccg_basenames = []
+
+# Pairs of hand-coded .h and .cc files.
+gtkmm_extra_any_h_cc_basenames = [
+  'accelerator',
+  'accelkey',
+  'cellrenderer_generation',
+  'listviewtext',
+  'object',
+  'radiobuttongroup',
+  'treemodelcolumn',
+  'treeview_private',
+]
+
+gtkmm_extra_deprecated_h_cc_basenames = []
+
+gtkmm_extra_h_files = [
+  'version.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_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_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' ] + gtkmm_extra_gendef_cpp_args
+
+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_whole: gdkmm_library,
+    install: true,
+  )
+else
+  # Building with headers generated from *.hg files with
+  # gmmproc < 2.64.3 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,
+    version: gtkmm_libversion,
+    dependencies: gtkmm_build_dep,
+    link_depends: gtkmm_def,
+    link_args: gtkmm_extra_link_args,
+    link_whole: [gdkmm_library, gtk_int_lib],
+    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: 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..a2d0f148
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,358 @@
+# This file is part of gtkmm.
+
+# The resource compiler, used in demos/gtk-demo, requires a C compiler.
+project('gtkmm', 'c', 'cpp',
+  version: '3.97.1',
+  license: 'LGPLv2.1+',
+  default_options: [
+    'cpp_std=c++17'
+  ],
+  meson_version: '>= 0.50.0', # required for python3.path()
+)
+
+gtkmm_api_version = '4.0'
+gtkmm_pcname = meson.project_name() + '-' + 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 = [0, 0, 0]
+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_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.65.1'
+
+# Gtk supported pkg-config files on MSVC files for a good while, so just use that
+gtk_req = '>= 3.98.0'
+gtk_dep = dependency('gtk4', version: gtk_req)
+
+cairomm_req = '>= 1.15.4'
+cairomm_dep = dependency('cairomm-1.16', version: cairomm_req)
+
+pangomm_req = '>= 2.43.1'
+pangomm_dep = dependency('pangomm-2.44', 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.29.1'
+atkmm_dep = dependency('atkmm-2.30', 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 = '66'
+
+glibmm_dep = dependency('glibmm-2.@0@'.format(glibmm_req_minor_ver), version: glibmm_req)
+giomm_dep = dependency('giomm-2.@0@'.format(glibmm_req_minor_ver), version: glibmm_req)
+
+# 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
+
+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,
+  'gtk4', gtk_req,
+  'cairomm-1.16', cairomm_req,
+  'pangomm-2.44', cairomm_req,
+  'gdk-pixbuf-2.0', gdk_pixbuf_req,
+]
+
+gtkmm_build_dep = gdkmm_build_dep
+gtkmm_requires = gdkmm_requires
+
+if build_atkmm_api
+  gtkmm_build_dep += [atkmm_dep]
+  gtkmm_requires += ['atkmm-2.30', atkmm_req]
+endif
+
+# not Windows
+if host_machine.system() != 'windows'
+  gtk_unix_print_dep = dependency('gtk4-unix-print')
+  gtkmm_build_dep += [gtk_unix_print_dep]
+  gtkmm_requires += ['gtk4-unix-print', '']
+endif
+
+gdkmm_requires = ' '.join(gdkmm_requires)
+gtkmm_requires = ' '.join(gtkmm_requires)
+
+# 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'
+
+# Do we build the gdkmm/gtkmm without using gendef.exe?
+gdkmm_extra_gendef_cpp_args = []
+gtkmm_extra_gendef_cpp_args = []
+if is_msvc
+  add_project_arguments(cpp_compiler.get_supported_arguments([ '/utf-8', '/wd4828']), language: 'cpp')
+  add_project_arguments(cpp_compiler.get_supported_arguments([ '/utf-8']), language: 'c')
+
+  # 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'))
+  if not build_shared_libs_directly
+    gdkmm_extra_gendef_cpp_args += '-DGDKMM_USE_GENDEF'
+    gtkmm_extra_gendef_cpp_args = gdkmm_extra_gendef_cpp_args + [ '-DGTKMM_USE_GENDEF' ]
+  endif
+else
+  build_shared_libs_directly = true
+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')
+
+gui_app_ldflags = []
+
+# MSVC: Ignore warnings that aren't really harmful, but make those
+#       that should not be overlooked stand out.  For gtkmm applications
+#       where we do not want a console window to show up with Visual Studio
+#       builds, we must use '-entry:mainCRTStartup' in the linker flags,
+#       otherwise the program will fail to link unless we defined a WinMain()
+#       for them
+if is_msvc
+  foreach wd : ['/FImsvc_recommended_pragmas.h', '/wd4267', '/wd4530', '/wd4250', '/wd4251', '/wd4273', 
'/wd4275', '/wd4805']
+    disabled_warning = cpp_compiler.get_supported_arguments(wd)
+    add_project_arguments(disabled_warning, language: 'cpp')
+  endforeach
+  gui_app_ldflags += '-entry:mainCRTStartup'
+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
+
+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 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),
+  '         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..eabeaf86
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,16 @@
+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-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..11717625
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,61 @@
+# tests
+
+# Input: gtkmm_dep, build_tests, gui_app_ldflags, gtkmm_extra_gendef_cpp_args
+# Output: -
+
+test_programs = [
+# [[dir-name], exe-name, [sources], GUI, 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_deletethis'], 'test', ['main.cc'], true, false],
+  [['gdk_rgba'], 'test', ['main.cc'], false, true],
+  [['main_with_options'], 'test', ['main.cc'], true, false],
+  [['object_move'], 'test', ['main.cc'], false, true],
+  [['property_notification'], 'test', ['main.cc'], true, false],
+  [['refcount_dialog'], 'test', ['main.cc'], true, false],
+  [['scrolledwindow'], 'test', ['main.cc'], true, false],
+  [['tree_model_iterator'], 'test', ['main.cc'], false, true],
+  [['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: gtkmm_dep,
+    gui_app: ex[3],
+    build_by_default: build_tests,
+    link_args: ex[3] ? gui_app_ldflags : [],
+    cpp_args: gtkmm_extra_gendef_cpp_args,
+    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..486fefb6
--- /dev/null
+++ b/tools/extra_defs_gen/meson.build
@@ -0,0 +1,35 @@
+# 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.66',
+)
+
+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 = [
+  '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..91dec5a7
--- /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-4.0.devhelp2
+                         gtkmm-4.0.tag
+                         html/*


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