[mm-common/wip/kjellahl/meson-build] Support modules that are built with Meson



commit d28031cb786107c8a4400008ee2e41635ddea992
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Sat Sep 28 11:04:37 2019 +0200

    Support modules that are built with Meson
    
    * configure.ac:
    * Makefile.am:
    * meson.build: Install files from util/build_scripts/.
    Configure mm-common-get and mm-common-get.1.
    * README: Describe the new files.
    * util/build_scripts/*.py:
    * util/mm-common-get.1.in:
    * util/mm-common-get.in: New files for modules built with Meson.
    * util/mm-common-prepare.1.in:
    * util/mm-common-prepare.in: Mention that these are used for modules built
    with Autotools.
    
    See MR !2

 Makefile.am                              |  22 +++-
 README                                   |  94 +++++++++++++---
 configure.ac                             |   1 +
 meson.build                              |  47 +++++++-
 util/build_scripts/dist-build-scripts.py |  42 +++++++
 util/build_scripts/dist-changelog.py     |  26 +++++
 util/build_scripts/doc-reference.py      | 173 +++++++++++++++++++++++++++++
 util/build_scripts/generate-binding.py   | 185 +++++++++++++++++++++++++++++++
 util/mm-common-get.1.in                  |  64 +++++++++++
 util/mm-common-get.in                    |  62 +++++++++++
 util/mm-common-prepare.1.in              |   5 +-
 util/mm-common-prepare.in                |   2 +-
 12 files changed, 692 insertions(+), 31 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 9b59a9f..1cd5df1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,17 +18,22 @@
 # Pick up aclocal flags from the environment.
 ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
 
-bin_SCRIPTS = util/mm-common-prepare
-man1_MANS = util/mm-common-prepare.1
+bin_SCRIPTS = util/mm-common-prepare util/mm-common-get
+man1_MANS = util/mm-common-prepare.1 util/mm-common-get.1
 
-# These are installed so that mm-common-prepare can copy them
-# into projects at autogen.sh time:
+# These are installed so that mm-common-prepare can copy the .am files
+# into projects at autogen.sh time, and mm-common-get can copy the .py files
+# at Meson setup or configure time:
 build_supportdir = $(pkgdatadir)/build
 dist_build_support_DATA =              \
        am_include/compile-binding.am   \
        am_include/dist-changelog.am            \
        am_include/doc-reference.am             \
-       am_include/generate-binding.am
+       am_include/generate-binding.am \
+  util/build_scripts/dist-build-scripts.py \
+  util/build_scripts/dist-changelog.py \
+  util/build_scripts/doc-reference.py \
+  util/build_scripts/generate-binding.py
 
 # These are installed so that aclocal can copy them into aclocal.m4
 # at autogen.sh time:
@@ -47,6 +52,7 @@ dist_aclocal_macro_DATA =             \
 # at autogen.sh time if a directory path is given to MM_CONFIG_DOCTOOL_DIR(),
 # or they can be found via pkg-config --variable=doctooldir mm-common-util,
 # which is preferrable.
+# mm-common-get can copy them at Meson setup or configure time.
 doctooldir = $(pkgdatadir)/doctool
 dist_doctool_DATA =                    \
        util/doc-install.pl             \
@@ -118,7 +124,7 @@ skeletonmm_script_files = \
 
 skeletonmm_files = $(skeletonmm_script_files) $(skeletonmm_data_files)
 
-dist_noinst_DATA = util/mm-common-prepare.1.in $(skeletonmm_data_files)
+dist_noinst_DATA = util/mm-common-prepare.1.in util/mm-common-get.1.in $(skeletonmm_data_files)
 dist_noinst_SCRIPTS = autogen.sh $(skeletonmm_script_files)
 
 CLEANFILES = $(man1_MANS) $(doc_DATA)
@@ -170,6 +176,10 @@ doctags/libstdc++.tag:
 util/mm-common-prepare.1: $(srcdir)/util/mm-common-prepare.1.in Makefile
        $(AM_V_GEN)$(subst_manpage) $(srcdir)/util/mm-common-prepare.1.in >$@
 
+# Build the mm-common-get(1) manual page.
+util/mm-common-get.1: $(srcdir)/util/mm-common-get.1.in Makefile
+       $(AM_V_GEN)$(subst_manpage) $(srcdir)/util/mm-common-get.1.in >$@
+
 # Create tar archive of skeletonmm for installation.
 skeletonmm.tar.gz: $(skeletonmm_files)
        $(AM_V_GEN)($(srctar_stdout) $(skeletonmm_files)) | gzip -c -n >$@
diff --git a/README b/README
index 4995ef8..7c8ad06 100644
--- a/README
+++ b/README
@@ -14,13 +14,16 @@ is available at <http://gcc.gnu.org/onlinedocs/libstdc++/>.
 Autotools or Meson?
 ===================
 
-mm-common can be built with autotools or meson. Building with autotools
+mm-common can be built with Autotools or Meson. Building with Autotools
 may be phased out in the future.
 
-Most of the files that mm-common installs and mm-common-prepare copies to
-other modules are useful only if those modules are built with autotools.
+The files that mm-common installs and mm-common-prepare copies to other
+modules are useful in modules that are built with Autotools.
+The files that mm-common installs and mm-common-get copies to other
+modules are useful in modules that are built with Meson.
+
 The files in the skeletonmm directory show the start of a project that will
-use autotools.
+use Autotools.
 
 Skeleton C++ binding module
 ===========================
@@ -28,7 +31,7 @@ Skeleton C++ binding module
 When creating a new C++ binding module based on mm-common, the easiest way
 to get started is to copy the skeletonmm directory shipped with mm-common.
 It contains the build support files required for a C++ binding module using
-gmmproc and glibmm.
+Autotools, gmmproc and glibmm.
 
 In order to create a new binding project from the copied skeleton directory,
 any files which have "skeleton" in the filename must be renamed.  References
@@ -42,8 +45,8 @@ The following sections provide an overview of the various files shipped
 with mm-common, and briefly explain their purpose.  Detailed documentation
 and usage instructions can be found in the files themselves.
 
-mm-common-prepare
------------------
+mm-common-prepare and Autotools
+-------------------------------
 
 The mm-common-prepare shell script is installed in ${bindir} and must be
 invoked from the bootstrap script of a binding module in order to set up
@@ -70,8 +73,36 @@ Also note that mm-common-prepare inspects the project's configure.ac file
 for the AC_CONFIG_AUX_DIR([...]) argument.  This is explained in further
 detail below in the section on Automake include files.
 
-Autoconf M4 macros
-------------------
+mm-common-get and Meson
+-----------------------
+
+The mm-common-get shell script is installed in ${bindir} and must be
+invoked with run_command() early in a meson.build file. The meson.build file
+should contain code similar to
+
+  python = import('python').find_installation('python3')
+  cmd_py = 'import os, sys\n' \
+         + 'sys.exit(0 if os.path.isdir("' + (project_source_root/'.git') + '") else 1)\n'
+  is_git_build = run_command(python, '-c', cmd_py).returncode() == 0
+  maintainer_mode_opt = get_option('maintainer-mode')
+  maintainer_mode = maintainer_mode_opt == 'true' or \
+                   (maintainer_mode_opt == 'if-git-build' and is_git_build)
+  mm_common_get = find_program('mm-common-get', required: maintainer_mode)
+
+  if maintainer_mode and mm_common_get.found()
+    # Copy files to untracked/build_scripts and untracked/docs.
+    run_command(mm_common_get, '--force',
+      project_source_root / 'untracked' / 'build_scripts',
+      project_source_root / 'untracked' / 'docs')
+  endif
+
+In a Unix-like system the first few lines can be replaced with
+
+  is_git_build = run_command('test', '-d', project_source_root/'.git').returncode() == 0
+
+
+Autoconf M4 macros (Autotools)
+------------------------------
 
 The Autoconf M4 macros are installed into the system-wide macro repository
 in the ${datadir}/aclocal directory.  Since all used M4 macros are copied
@@ -131,8 +162,8 @@ macros/mm-ax_cxx_compile_stdcxx.m4:
   http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html,
   except for the MM_ prefix.
 
-Automake include files
-----------------------
+Automake include files (Autotools)
+----------------------------------
 
 The Automake include files are located in the am_include/ directory.
 The installed mm-common-prepare program copies all of the .am files into
@@ -159,14 +190,43 @@ am_include/dist-changelog.am:
   a release, intended to be used by modules which use the version control
   log exclusively to document changes.
 
-Documentation utilities
------------------------
+Python build scripts (Meson)
+----------------------------
+
+These scripts can be called from meson.build files with run_command(),
+custom_target(), meson.add_postconf_script(), meson.add_install_script()
+and meson.add_dist_script().
+
+util/build_scripts/generate-binding.py:
+  Commands for running the gmmproc code generator to produce
+  the source code files for a C++ binding module.
+
+util/build_scripts/doc-reference.py:
+  Commands for building the API reference documentation using
+  Doxygen, and to create a Devhelp book for the library. The installation
+  rules also take care of translating references to external documentation
+  in the generated hypertext documents.
+
+util/build_scripts/dist-changelog.py:
+  A git command to generate a ChangeLog file when making a release,
+  intended to be used by modules which use the version control
+  log exclusively to document changes.
+
+util/build_scripts/dist-build-scripts.py:
+  Commands that trim the distribution directory before a tarball is made.
+  The scripts copied by mm-common-get are distributed, although they are
+  not checked into the git repository. All .gitignore files and an empty build/
+  directory are removed
+
+Documentation utilities (Meson and Autotools)
+---------------------------------------------
 
 These are two Perl scripts, a style sheet, and one XSL transformation
 which assist with the task of generating and installing the Doxygen
 reference documentation.  At least doc-install.pl is also required for
 tarball builds.
-To avoid copying these files into all binding modules, they are
+
+Autotools: To avoid copying these files into all binding modules, they are
 distributed and installed with the mm-common module.  Those binding modules
 which shall depend on mm-common only in maintainer-mode must call
 MM_CONFIG_DOCTOOL_DIR([...]) in configure.ac to indicate to mm-common-prepare
@@ -219,9 +279,9 @@ doctags/libstdc++.tag:
   The Doxygen tag file for the GNU libstdc++ reference documentation
   hosted at <http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/>.
   This file is distributed with release archives of mm-common, but not
-  checked into version control on gnome.org.  If mm-common is built in
-  maintainer-mode, the file will be downloaded automatically from the
-  gcc.gnu.org web server.
+  checked into version control on gnome.org.  If mm-common is built with
+  Autotools in maintainer-mode or with Meson and use-network=true,
+  the file will be downloaded automatically from the gcc.gnu.org web server.
   The file libstdc++.tag is installed into the package data directory
   of mm-common.  The mm-common-libstdc++ pkg-config module defines the
   variables ${doxytagfile} and ${htmlrefpub}, which can be queried for
diff --git a/configure.ac b/configure.ac
index 461a310..18da79c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -56,6 +56,7 @@ AC_CONFIG_FILES([
   doctags/mm-common-libstdc++-uninstalled.pc
   macros/mm-common.m4
   util/mm-common-prepare
+  util/mm-common-get
   util/mm-common-util.pc
   util/mm-common-util-uninstalled.pc
 ])
diff --git a/meson.build b/meson.build
index f61fa9e..a14b535 100644
--- a/meson.build
+++ b/meson.build
@@ -41,6 +41,8 @@ install_man1dir = install_mandir / 'man1'
 #   doctags/mm-common-libstdc++.pc.in -> mm-common-libstdc++.pc
 #   doctags/mm-common-libstdc++-uninstalled.pc.in -> mm-common-libstdc++-uninstalled.pc
 #   macros/mm-common.m4.in -> mm-common.m4
+#   util/mm-common-get.1.in -> mm-common-get.1
+#   util/mm-common-get.in -> mm-common-get
 #   util/mm-common-prepare.1.in -> mm-common-prepare.1
 #   util/mm-common-prepare.in -> mm-common-prepare
 #   util/mm-common-util.pc.in -> mm-common-util.pc
@@ -57,16 +59,28 @@ conf_data.set('PACKAGE_STRING', meson.project_name() + ' ' + meson.project_versi
 
 # These are installed so that mm-common-prepare can copy them
 # into projects at autogen.sh time.
-build_support_basefiles = [
+autotools_build_support_basefiles = [
   'compile-binding.am',
   'dist-changelog.am',
   'doc-reference.am',
   'generate-binding.am',
 ]
 build_support_files = []
-foreach file : build_support_basefiles
+foreach file : autotools_build_support_basefiles
   build_support_files += 'am_include' / file
 endforeach
+
+# These are installed so that mm-common-get can copy them
+# into projects at Meson setup or configure time.
+meson_build_support_basefiles = [
+  'dist-build-scripts.py',
+  'dist-changelog.py',
+  'doc-reference.py',
+  'generate-binding.py',
+]
+foreach file : meson_build_support_basefiles
+  build_support_files += 'util' / 'build_scripts' / file
+endforeach
 install_data(build_support_files, install_dir: install_build_supportdir)
 
 # These are installed so that aclocal can copy them into aclocal.m4
@@ -107,6 +121,8 @@ endif
 # These are installed so that mm-common-prepare can copy them into projects
 # at autogen.sh time, if a directory path is given to MM_CONFIG_DOCTOOL_DIR(),
 # or they can be found via pkg-config --variable=doctooldir mm-common-util.
+# They are also installed so that mm-common-get can copy them
+# into projects at Meson setup or configure time.
 doctool_basefiles = [
   'doc-install.pl',
   'doc-postprocess.pl',
@@ -147,18 +163,39 @@ configure_file(
   configuration: conf_data,
 )
 
-# mm-common-prepare command.
+# mm-common-get command.
 conf_data3 = configuration_data()
 conf_data3.merge_from(conf_data)
-conf_data3.set('configure_input', 'mm-common-prepare.  Generated from util/mm-common-prepare.in')
+conf_data3.set('configure_input', 'mm-common-get.  Generated from util/mm-common-get.in')
+conf_data3.set('datadir_py', install_prefix / install_datadir)
 configure_file(
-  input: 'util' / 'mm-common-prepare.in',
+  input: 'util' / 'mm-common-get.in',
   output: '@BASENAME@',
   configuration: conf_data3,
   install_dir: install_bindir,
   install_mode: 'rwxr-xr-x'
 )
 
+# mm-common-get.1 manual page.
+configure_file(
+  input: 'util' / 'mm-common-get.1.in',
+  output: '@BASENAME@',
+  configuration: conf_data,
+  install_dir: install_man1dir
+)
+
+# mm-common-prepare command.
+conf_data4 = configuration_data()
+conf_data4.merge_from(conf_data)
+conf_data4.set('configure_input', 'mm-common-prepare.  Generated from util/mm-common-prepare.in')
+configure_file(
+  input: 'util' / 'mm-common-prepare.in',
+  output: '@BASENAME@',
+  configuration: conf_data4,
+  install_dir: install_bindir,
+  install_mode: 'rwxr-xr-x'
+)
+
 # mm-common-prepare.1 manual page.
 configure_file(
   input: 'util' / 'mm-common-prepare.1.in',
diff --git a/util/build_scripts/dist-build-scripts.py b/util/build_scripts/dist-build-scripts.py
new file mode 100755
index 0000000..3ead7cd
--- /dev/null
+++ b/util/build_scripts/dist-build-scripts.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with meson.add_dist_script() in meson.build
+
+#                         sys.argv[1]      sys.argv[2]
+# dist-build-scripts.py <root_src_dir> <relative_script_dir>
+
+# <relative_script_dir> is the directory with the build scripts, relative to <root_source_dir>.
+
+import os
+import sys
+import shutil
+
+src_script_dir = os.path.join(sys.argv[1], sys.argv[2])
+dist_script_dir = os.path.join(os.getenv('MESON_DIST_ROOT'), sys.argv[2])
+
+# Create the distribution script directory, if it does not exist.
+os.makedirs(dist_script_dir, exist_ok=True)
+
+# Distribute files that mm-common-prepare has copied to src_script_dir.
+files = [
+  'dist-build-scripts.py',
+  'dist-changelog.py',
+  'doc-reference.py',
+  'generate-binding.py'
+]
+for file in files:
+  shutil.copy(os.path.join(src_script_dir, file), dist_script_dir)
+
+# Don't distribute .gitignore files.
+for dirpath, dirnames, filenames in os.walk(os.getenv('MESON_DIST_ROOT')):
+  if '.gitignore' in filenames:
+    os.remove(os.path.join(dirpath, '.gitignore'))
+
+# Remove an empty MESON_DIST_ROOT/build directory.
+dist_build_dir = os.path.join(os.getenv('MESON_DIST_ROOT'), 'build')
+if os.path.isdir(dist_build_dir):
+  try:
+    os.rmdir(dist_build_dir)
+  except OSError:
+    # Ignore the error, if not empty.
+    pass
diff --git a/util/build_scripts/dist-changelog.py b/util/build_scripts/dist-changelog.py
new file mode 100755
index 0000000..c38fde3
--- /dev/null
+++ b/util/build_scripts/dist-changelog.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with meson.add_dist_script() in meson.build
+
+#                      sys.argv[1]
+# dist-changelog.py <root_source_dir>
+
+import os
+import sys
+import subprocess
+
+# Make a ChangeLog file for distribution.
+cmd = [
+  'git',
+  '--git-dir=' + os.path.join(sys.argv[1], '.git'),
+  '--work-tree=' + sys.argv[1],
+  'log',
+  '--no-merges',
+  '--date=short',
+  '--max-count=200',
+  '--pretty=tformat:%cd  %an  <%ae>%n%n  %s%n%w(0,0,2)%+b',
+]
+logfile = open(os.path.join(os.getenv('MESON_DIST_ROOT'), 'ChangeLog'), mode='w')
+result = subprocess.run(cmd, stdout=logfile)
+logfile.close()
+sys.exit(result.returncode)
diff --git a/util/build_scripts/doc-reference.py b/util/build_scripts/doc-reference.py
new file mode 100755
index 0000000..2b6f552
--- /dev/null
+++ b/util/build_scripts/doc-reference.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with custom_target(),
+# meson.add_install_script() or meson.add_dist_script() in meson.build.
+
+#                     argv[1]      argv[2]     argv[3:]
+# doc-reference.py <subcommand> <MMDOCTOOLDIR> <xxx>...
+
+# <MMDOCTOOLDIR> is an absolute path in the source directory.
+
+import os
+import sys
+import subprocess
+import shutil
+
+subcommand = sys.argv[1]
+MMDOCTOOLDIR = sys.argv[2]
+
+# Invoked from custom_target() in meson.build.
+def doxygen():
+  #    argv[3]         argv[4:]
+  # <doxytagfile> <doc_input_files>...
+
+  # <doxytagfile> is a relative or absolute path in the build directory.
+  # <doc_input_files> are absolute paths in the source or build directory.
+  doxytagfile = sys.argv[3]
+  doc_outdir = os.path.dirname(doxytagfile)
+
+  # Export this variable for use in the Doxygen configuration file.
+  child_env = os.environ.copy()
+  child_env['MMDOCTOOLDIR'] = MMDOCTOOLDIR
+
+  # Remove old files.
+  if os.path.isfile(doxytagfile):
+    os.remove(doxytagfile)
+  shutil.rmtree(os.path.join(doc_outdir, 'html'), ignore_errors=True)
+
+  # Relative paths in Doxyfile assume that Doxygen is run from the
+  # build directory one level above Doxyfile.
+  doxygen_cwd = os.path.join(doc_outdir, '..')
+  DOXYGEN = 'doxygen'
+  if ('DOXYGEN' in child_env) and child_env['DOXYGEN']:
+    DOXYGEN = child_env['DOXYGEN']
+
+  doxygen_input = '@INCLUDE = ' + os.path.join('reference', 'Doxyfile') + '\n' \
+                + 'INPUT = "' + '" "'.join(sys.argv[4:]) + '"\n'
+  result = subprocess.run([DOXYGEN, '-'],
+    input=doxygen_input, text=True, env=child_env, cwd=doxygen_cwd)
+  if result.returncode:
+    return result.returncode
+
+  cmd = [
+    'perl',
+    '--',
+    os.path.join(MMDOCTOOLDIR, 'doc-postprocess.pl'),
+    os.path.join(doc_outdir, 'html', '*.html'),
+  ]
+  return subprocess.run(cmd).returncode
+
+# Invoked from custom_target() in meson.build.
+def devhelp():
+  #    argv[3]       argv[4]       argv[5]     argv[6]
+  # <doxytagfile> <devhelpfile> <book_name> <book_title>
+
+  # <doxytagfile> and <devhelpfile> are relative or absolute paths in the build directory.
+  doxytagfile = sys.argv[3]
+  devhelpfile = sys.argv[4]
+  book_name = sys.argv[5]
+  book_title = sys.argv[6]
+  tagfile_to_devhelp = os.path.join(MMDOCTOOLDIR, 'tagfile-to-devhelp2.xsl')
+
+  # The parameters to the Doxygen-to-Devhelp XSLT script.
+  cmd = [
+    'xsltproc',
+    '--stringparam', 'book_title', book_title,
+    '--stringparam', 'book_name', book_name,
+    '--stringparam', 'book_base', 'html',
+    '-o', devhelpfile,
+    tagfile_to_devhelp,
+    doxytagfile,
+  ]
+  return subprocess.run(cmd).returncode
+
+# Invoked from meson.add_install_script().
+def install_doc():
+  #    argv[3]       argv[4]      argv[5]        argv[6:]
+  # <devhelpfile> <devhelpdir> <htmlrefdir> <docinstall_flags>...
+
+  # <devhelpfile> is a relative or absolute path in the build directory.
+  # <htmlrefdir> and <devhelpdir> are installation directories, relative to {prefix}.
+  devhelpfile = sys.argv[3]
+  devhelpdir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[4])
+  htmlrefdir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[5])
+  build_dir = os.path.dirname(devhelpfile)
+
+  # Create the installation directories, if they do not exist.
+  os.makedirs(htmlrefdir, exist_ok=True)
+  os.makedirs(devhelpdir, exist_ok=True)
+
+  # Install html files.
+  cmd = [
+    'perl',
+    '--',
+    os.path.join(MMDOCTOOLDIR, 'doc-install.pl'),
+    '--verbose',
+    '--mode=0644',
+  ] + sys.argv[6:] + [
+    '-t', htmlrefdir,
+    '--glob',
+    '--',
+    os.path.join(build_dir, 'html', '*'),
+  ]
+  result1 = subprocess.run(cmd)
+
+  # Install the Devhelp file.
+  # rstrip('/') means remove trailing /, if any.
+  cmd = [
+    'perl',
+    '--',
+    os.path.join(MMDOCTOOLDIR, 'doc-install.pl'),
+    '--verbose',
+    '--mode=0644',
+    '--book-base=' + htmlrefdir.rstrip('/'),
+    '-t', devhelpdir,
+    '--',
+    devhelpfile,
+  ]
+  result2 = subprocess.run(cmd)
+
+  if result1.returncode:
+    return result1.returncode
+  return result2.returncode
+
+# Invoked from meson.add_dist_script().
+def dist_doc():
+  #      argv[3]              argv[4]       argv[5]     argv[6]
+  # <doctool_dist_dir> <doc_ref_build_dir> <tagfile> <devhelpfile>
+
+  # <doctool_dist_dir> is a distribution directory, relative to MESON_DIST_ROOT.
+  # <doc_ref_build_dir> is a relative or absolute path in the build directory.
+  # <tagfile> and <devhelpfile> are relative or absolute paths in the build directory.
+  doctool_dist_dir = os.path.join(os.getenv('MESON_DIST_ROOT'), sys.argv[3])
+  doc_ref_build_dir = sys.argv[4]
+  tagfile = sys.argv[5]
+  devhelpfile = sys.argv[6]
+
+  # Create the distribution directory, if it does not exist.
+  os.makedirs(os.path.join(doctool_dist_dir, 'reference'), exist_ok=True)
+
+  # Distribute files that mm-common-prepare has copied to MMDOCTOOLDIR.
+  # shutil.copy() does not copy timestamps.
+  for file in ['doc-install.pl', 'doc-postprocess.pl', 'doxygen-extra.css', 'tagfile-to-devhelp2.xsl']:
+    shutil.copy(os.path.join(MMDOCTOOLDIR, file), doctool_dist_dir)
+
+  # Distribute built files: tag file, devhelp file, html files.
+  for file in [tagfile, devhelpfile]:
+    shutil.copy(file, os.path.join(doctool_dist_dir, 'reference'))
+  shutil.copytree(os.path.join(doc_ref_build_dir, 'html'),
+                  os.path.join(doctool_dist_dir, 'reference', 'html'),
+                  copy_function=shutil.copy)
+  return 0
+
+# ----- Main -----
+if subcommand == 'doxygen':
+  sys.exit(doxygen())
+if subcommand == 'devhelp':
+  sys.exit(devhelp())
+if subcommand == 'install_doc':
+  sys.exit(install_doc())
+if subcommand == 'dist_doc':
+  sys.exit(dist_doc())
+print(sys.argv[0], ': illegal subcommand,', subcommand)
+sys.exit(1)
diff --git a/util/build_scripts/generate-binding.py b/util/build_scripts/generate-binding.py
new file mode 100755
index 0000000..a1244a8
--- /dev/null
+++ b/util/build_scripts/generate-binding.py
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+
+# External command, intended to be called with run_command(), custom_target(),
+# meson.add_install_script() and meson.add_dist_script().
+
+#                        argv[1]   argv[2:]
+# generate-binding.py <subcommand> <xxx>...
+
+import os
+import sys
+import subprocess
+from pathlib import Path
+import shutil
+
+subcommand = sys.argv[1]
+
+# Invoked from custom_target() in meson.build.
+def generate_wrap_init():
+  #    argv[2]       argv[3]      argv[4]    argv[5:]
+  # <gmmproc_dir> <output_file> <namespace> <hg_files>...
+
+  # <gmmproc_dir> is an absolute path in glibmm's installation directory.
+  # <output_file> is a relative or absolute path in the build directory.
+  # <hg_files> are relative or absolute paths in the source directory.
+  gmmproc_dir = sys.argv[2]
+  output_file = sys.argv[3]
+  parent_dir = os.path.basename(os.path.dirname(output_file))
+  namespace = sys.argv[4]
+  cmd = [
+    'perl',
+    '--',
+    os.path.join(gmmproc_dir, 'generate_wrap_init.pl'),
+    '--namespace=' + namespace,
+    '--parent_dir=' + parent_dir,
+  ] + sys.argv[5:]
+  output_file_obj = open(output_file, mode='w')
+  result = subprocess.run(cmd, stdout=output_file_obj)
+  output_file_obj.close()
+  return result.returncode
+
+# Invoked from custom_target() in meson.build.
+def gmmproc():
+  #    argv[2]       argv[3]        argv[4]     argv[5]   argv[6:]
+  # <gmmproc_dir> <output_file> <basefilename> <src_dir> <m4_dirs>...
+
+  # <gmmproc_dir> is an absolute path in glibmm's installation directory.
+  # <output_file> is a relative or absolute path in the build directory.
+  # <src_dir> is an absolute path in the source directory.
+  # <m4_dirs> are absolute paths in the source directory.
+  gmmproc_dir = sys.argv[2]
+  output_file = sys.argv[3]
+  output_dir = os.path.dirname(output_file)
+  basefilename = sys.argv[4] # name without filetype
+  src_dir = sys.argv[5]
+
+  include_m4_dirs = []
+  for dir in sys.argv[6:]:
+    include_m4_dirs += ['-I', dir]
+
+  # Create the private/ directory, if it does not exist.
+  os.makedirs(os.path.join(output_dir, 'private'), exist_ok=True)
+
+  # gmmproc generates output_dir/basefilename.cc, output_dir/basefilename.h
+  # and output_dir/private/{basefilename}_p.h
+  cmd = [
+    'perl',
+    '-I' + os.path.join(gmmproc_dir, 'pm'),
+    '--',
+    os.path.join(gmmproc_dir, 'gmmproc'),
+  ] + include_m4_dirs + [
+    '--defs',
+    src_dir,
+    basefilename,
+    src_dir,
+    output_dir,
+  ]
+  result = subprocess.run(cmd)
+  if result.returncode:
+    return result.returncode
+
+  # gmmproc does not update the timestamps of output files that have not changed.
+  # That's by design, to avoid unnecessary recompilations.
+  # The updated timestamp of output_file shows meson that this custom_target()
+  # has been updated.
+  Path(output_file).touch(exist_ok=True)
+  return 0
+
+# Invoked from meson.add_install_script().
+def install_built_h_files():
+  #    argv[2]       argv[3]          argv[4:]
+  # <built_h_dir> <install_subdir> <basefilenames>...
+
+  # <built_h_dir> is an absolute path in the build directory or source directory.
+  # <install_subdir> is an installation directory, relative to {prefix}.
+  built_h_dir = sys.argv[2]
+  install_dir = os.path.join(os.getenv('MESON_INSTALL_DESTDIR_PREFIX'), sys.argv[3])
+
+  # Create the installation directory, if it does not exist.
+  os.makedirs(os.path.join(install_dir, 'private'), exist_ok=True)
+
+  for file in sys.argv[4:]:
+    path_h = os.path.join(built_h_dir, file+'.h')
+    print('Installing ', path_h, ' to ', install_dir)
+    # shutil.copy2() copies timestamps and some other file metadata.
+    shutil.copy2(path_h, install_dir)
+
+    path_h = os.path.join(built_h_dir, 'private', file+'_p.h')
+    install_priv_dir = os.path.join(install_dir, 'private')
+    print('Installing ', path_h, ' to ', install_priv_dir)
+    shutil.copy2(path_h, install_priv_dir)
+  return 0
+
+# Invoked from meson.add_dist_script().
+def dist_built_files():
+  #     argv[2]        argv[3]     argv[4:]
+  # <built_h_cc_dir> <dist_dir> <basefilenames>...
+
+  # <built_h_cc_dir> is an absolute path in the build directory or source directory.
+  # <dist_dir> is a distribution directory, relative to MESON_DIST_ROOT.
+  built_h_cc_dir = sys.argv[2]
+  dist_dir = os.path.join(os.getenv('MESON_DIST_ROOT'), sys.argv[3])
+
+  # Create the distribution directory, if it does not exist.
+  os.makedirs(os.path.join(dist_dir, 'private'), exist_ok=True)
+
+  # Distribute wrap_init.cc.
+  # shutil.copy() does not copy timestamps.
+  shutil.copy(os.path.join(built_h_cc_dir, 'wrap_init.cc'), dist_dir)
+
+  # Distribute .h/.cc/_p.h files built from .hg/.ccg files.
+  for file in sys.argv[4:]:
+    shutil.copy(os.path.join(built_h_cc_dir, file+'.h'), dist_dir)
+    shutil.copy(os.path.join(built_h_cc_dir, file+'.cc'), dist_dir)
+    shutil.copy(os.path.join(built_h_cc_dir, 'private', file+'_p.h'),
+                os.path.join(dist_dir, 'private'))
+  return 0
+
+# Invoked from run_command() in meson.build.
+def copy_built_files():
+  #  argv[2]    argv[3]    argv[4:]
+  # <from_dir> <to_dir> <basefilenames>...
+
+  # <from_dir> is an absolute or relative path of the directory to copy from.
+  # <to_dir> is an absolute or relative path of the directory to copy to.
+  from_dir = sys.argv[2]
+  to_dir = sys.argv[3]
+
+  # Create the destination directory, if it does not exist.
+  os.makedirs(os.path.join(to_dir, 'private'), exist_ok=True)
+
+  # Copy some built files if they exist in from_dir, but not in the destination
+  # directory, or if they are not up to date in the destination directory.
+  # (The term "source directory" is avoided here, because from_dir might not
+  # be what Meson calls a source directory as opposed to a build directory.)
+
+  # Copy wrap_init.cc.
+  from_file = os.path.join(from_dir, 'wrap_init.cc')
+  to_file = os.path.join(to_dir, 'wrap_init.cc')
+  if os.path.isfile(from_file) and ((not os.path.isfile(to_file))
+     or (os.stat(from_file).st_mtime > os.stat(to_file).st_mtime)):
+    shutil.copy(from_file, to_file)
+
+  # Copy .h/.cc/_p.h files built from .hg/.ccg files.
+  for basefile in sys.argv[4:]:
+    for file in [basefile+'.h', basefile+'.cc', os.path.join('private', basefile+'_p.h')]:
+      from_file = os.path.join(from_dir, file)
+      to_file = os.path.join(to_dir, file)
+      if os.path.isfile(from_file) and ((not os.path.isfile(to_file))
+         or (os.stat(from_file).st_mtime > os.stat(to_file).st_mtime)):
+        shutil.copy(from_file, to_file)
+  return 0
+
+# ----- Main -----
+if subcommand == 'generate_wrap_init':
+  sys.exit(generate_wrap_init())
+if subcommand == 'gmmproc':
+  sys.exit(gmmproc())
+if subcommand == 'install_built_h_files':
+  sys.exit(install_built_h_files())
+if subcommand == 'dist_built_files':
+  sys.exit(dist_built_files())
+if subcommand == 'copy_built_files':
+  sys.exit(copy_built_files())
+print(sys.argv[0], ': illegal subcommand,', subcommand)
+sys.exit(1)
diff --git a/util/mm-common-get.1.in b/util/mm-common-get.1.in
new file mode 100644
index 0000000..ff8996c
--- /dev/null
+++ b/util/mm-common-get.1.in
@@ -0,0 +1,64 @@
+.TH MM-COMMON-GET 1 2019-09-12 GNOME "@PACKAGE_STRING@"
+.SH NAME
+mm-common-get \- Copy files from mm-common to a C++ binding module that uses Meson
+.SH SYNOPSIS
+.B mm-common-get
+.RI [ OPTION "]... " "BUILDSCRIPT-DIR DOCTOOL-DIR"
+.SH DESCRIPTION
+Run
+.B mm-common-get
+to copy the
+.I mm-common
+build support files into the source tree of a C++ binding module.
+.SH OPTIONS
+.TP
+.BR \-f ", " \-\-force
+forcefully replace existing files
+.TP
+.B \-\-help
+display a help message and exit
+.TP
+.B \-\-version
+show version information and exit
+.SH "EXIT STATUS"
+The exit status is 0 if OK, or 1 if an error occurred.
+.SH FILES
+The build support files currently copied by
+.B mm-common-get
+are listed below.
+.TP
+.BI "Meson build scripts copied to " BUILDSCRIPT-DIR :
+.PD 0
+.IP
+.I dist-build-scripts.py
+.IP
+.I dist-changelog.py
+.IP
+.I doc-reference.py
+.IP
+.I generate-binding.py
+.PD
+.TP
+.BI "Documentation utilities copied to " DOCTOOL-DIR :
+.PD 0
+.IP
+.I doc-install.pl
+.IP
+.I doc-postprocess.pl
+.IP
+.I doxygen.css
+.IP
+.I doxygen-extra.css
+.IP
+.I tagfile-to-devhelp2.xsl
+.PD
+.SH "SEE ALSO"
+.PD 0
+.BR mm-common-prepare (1)
+.PP
+.I @docdir@/README
+.PP
+.I @docdir@/skeletonmm.tar.xz or
+.PP
+.I @docdir@/skeletonmm.tar.gz
+.PD
diff --git a/util/mm-common-get.in b/util/mm-common-get.in
new file mode 100644
index 0000000..e0b28f0
--- /dev/null
+++ b/util/mm-common-get.in
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2019 The gtkmm Development Team
+#
+# @configure_input@
+#
+# mm-common is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 2 of the License,
+# or (at your option) any later version.
+#
+# mm-common is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with mm-common.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import argparse
+import shutil
+import filecmp
+
+pkgdatadir = os.path.join('@datadir_py@', '@PACKAGE_TARNAME@')
+progname = os.path.basename(sys.argv[0])
+
+parser = argparse.ArgumentParser(
+  description='Copy files from mm-common to a C++ binding module that uses Meson')
+parser.add_argument('--version', action='version', version='%(prog)s @PACKAGE_VERSION@')
+parser.add_argument('-f', '--force', help='replace existing files', action='store_true')
+parser.add_argument('buildscript_dir', help='where to store build scripts')
+parser.add_argument('doctool_dir', help='where to store doc tool files')
+args = parser.parse_args()
+
+forceflag = args.force
+buildscriptdir = args.buildscript_dir
+doctooldir = args.doctool_dir
+
+print(progname + ': putting Meson build scripts in ' + buildscriptdir)
+# Create the destination directory, if it does not exist.
+os.makedirs(buildscriptdir, exist_ok=True)
+for file in ['dist-build-scripts.py', 'dist-changelog.py', 'doc-reference.py', 'generate-binding.py']:
+  src_file = os.path.join(pkgdatadir, 'build', file)
+  dest_file = os.path.join(buildscriptdir, file)
+  # Don't update the timestamp of dest_file, if it's equal to src_file.
+  # if file-does-not-exist or (force and files-are-not-equal)
+  if (not os.path.isfile(dest_file)) or (forceflag and (not filecmp.cmp(src_file, dest_file))):
+    print(progname + ': copying file ' + file)
+    # shutil.copy() does not copy timestamps.
+    shutil.copy(src_file, dest_file)
+
+print(progname + ': putting documentation utilities in ' + doctooldir)
+os.makedirs(doctooldir, exist_ok=True)
+for file in ['doc-install.pl', 'doc-postprocess.pl',
+             'doxygen.css', 'doxygen-extra.css', 'tagfile-to-devhelp2.xsl']:
+  src_file = os.path.join(pkgdatadir, 'doctool', file)
+  dest_file = os.path.join(doctooldir, file)
+  if (not os.path.isfile(dest_file)) or (forceflag and (not filecmp.cmp(src_file, dest_file))):
+    print(progname + ': copying file ' + file)
+    shutil.copy(src_file, dest_file)
diff --git a/util/mm-common-prepare.1.in b/util/mm-common-prepare.1.in
index a9ebd50..edbe042 100644
--- a/util/mm-common-prepare.1.in
+++ b/util/mm-common-prepare.1.in
@@ -1,6 +1,6 @@
 .TH MM-COMMON-PREPARE 1 2014-08-13 GNOME "@PACKAGE_STRING@"
 .SH NAME
-mm-common-prepare \- Prepare a C++ binding module to use mm-common
+mm-common-prepare \- Prepare a C++ binding module to use mm-common and Autotools
 .SH SYNOPSIS
 .B mm-common-prepare
 .RI [ OPTION "]... [" SOURCE-DIR ]
@@ -94,7 +94,8 @@ are listed below.
 .PD
 .SH "SEE ALSO"
 .PD 0
-.BR autoreconf (1)
+.BR autoreconf (1),
+.BR mm-common-get (1)
 .PP
 .I @docdir@/README
 .PP
diff --git a/util/mm-common-prepare.in b/util/mm-common-prepare.in
index 5285095..3a0a7de 100644
--- a/util/mm-common-prepare.in
+++ b/util/mm-common-prepare.in
@@ -35,7 +35,7 @@ do
     cat <<EOF
 Usage: $progname [OPTION]... [DIRECTORY | CONFIGURE-FILE]
 
-Prepare a C++ binding module to use mm-common.
+Prepare a C++ binding module to use mm-common and Autotools.
 
  -c, --copy          copy files rather than symlinking them
  -f, --force         replace existing files


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