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



commit c48b29e6b41d433d7e7b256a8532cb1c81711771
Author: Kjell Ahlstedt <kjellahlstedt gmail com>
Date:   Fri Sep 13 18:53:08 2019 +0200

    Support modules that are built with Meson
    
    * Makefile.am:
    * meson.build: Install files from util/build_scripts/.
    * README: Describe the new files.
    * util/meson_aux/extra-dist-cmd.sh: Use MESON_DIST_ROOT.
    * 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                              |  14 ++-
 README                                   |  49 ++++----
 meson.build                              |  42 +++++--
 util/build_scripts/dist-build-scripts.py |  42 +++++++
 util/build_scripts/dist-build-scripts.sh |  26 -----
 util/build_scripts/dist-changelog.py     |  26 +++++
 util/build_scripts/dist-changelog.sh     |   9 --
 util/build_scripts/doc-reference.py      | 173 +++++++++++++++++++++++++++++
 util/build_scripts/doc-reference.sh      | 116 -------------------
 util/build_scripts/generate-binding.py   | 185 +++++++++++++++++++++++++++++++
 util/build_scripts/generate-binding.sh   | 150 -------------------------
 util/meson_aux/extra-dist-cmd.sh         |   7 +-
 util/mm-common-get.1.in                  |  64 +++++++++++
 util/mm-common-get.in                    |  62 +++++++++++
 util/mm-common-prepare.1.in              |  41 ++-----
 util/mm-common-prepare.in                |  55 +--------
 16 files changed, 635 insertions(+), 426 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index ae16eab..828c720 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,18 +21,19 @@ ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
 bin_SCRIPTS = util/mm-common-prepare
 man1_MANS = util/mm-common-prepare.1
 
-# These are installed so that mm-common-prepare can copy them
-# into projects at autogen.sh time, or at meson setup or configure 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 \
-  util/build_scripts/dist-build-scripts.sh \
-  util/build_scripts/dist-changelog.sh \
-  util/build_scripts/doc-reference.sh \
-  util/build_scripts/generate-binding.sh
+  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:
@@ -51,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             \
diff --git a/README b/README
index 11ee5de..a94ffe0 100644
--- a/README
+++ b/README
@@ -17,9 +17,10 @@ Autotools or Meson?
 mm-common can be built with Autotools or Meson. Building with Autotools
 may be phased out in the future.
 
-The files that mm-common installs and mm-common-prepare copies to
-other modules are useful both in modules that are built with Autotools and
-in modules that are built with Meson.
+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.
@@ -72,26 +73,34 @@ 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.
 
-mm-common-prepare and Meson
----------------------------
+mm-common-get and Meson
+-----------------------
 
-The mm-common-prepare shell script is installed in ${bindir} and must be
+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
 
-  is_git_build = run_command('test', '-d', project_source_root / '.git').returncode() == 0
+  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_prepare = find_program('mm-common-prepare', required: maintainer_mode)
+  mm_common_get = find_program('mm-common-get', required: maintainer_mode)
 
-  if maintainer_mode and mm_common_prepare.found()
-    # Copy files to untracked/docs and untracked/build_scripts.
-    run_command(mm_common_prepare, '--force', '--copy',
-      '--doctooldir=' + project_source_root / 'untracked' / 'docs',
-      '--buildscriptdir=' + project_source_root / 'untracked' / 'build_scripts')
+  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)
 ------------------------------
 
@@ -188,26 +197,26 @@ 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.sh:
+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.sh:
+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
+  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.sh:
+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.sh:
+util/build_scripts/dist-build-scripts.py:
   Commands that trim the distribution directory before a tarball is made.
-  The scripts copied by mm-common-prepare are distributed, although they are
+  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/
-  diretory are removed
+  directory are removed
 
 Documentation utilities (Meson and Autotools)
 ---------------------------------------------
diff --git a/meson.build b/meson.build
index ead4cc7..36512ed 100644
--- a/meson.build
+++ b/meson.build
@@ -27,6 +27,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
@@ -54,13 +56,13 @@ foreach file : autotools_build_support_basefiles
   build_support_files += 'am_include' / file
 endforeach
 
-# These are installed so that mm-common-prepare can copy them
+# 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.sh',
-  'dist-changelog.sh',
-  'doc-reference.sh',
-  'generate-binding.sh',
+  '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
@@ -105,7 +107,7 @@ 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-prepare can copy them
+# 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',
@@ -147,18 +149,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',
@@ -273,7 +296,6 @@ if not meson.is_subproject()
     'util' / 'meson_aux' / 'extra-dist-cmd.sh',
     meson.current_source_dir(),
     meson.current_build_dir(),
-    'meson-dist' / meson.project_name() + '-' + meson.project_version(),
   )
 endif
 
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/meson_aux/extra-dist-cmd.sh b/util/meson_aux/extra-dist-cmd.sh
index 186d7e4..1c61ed1 100755
--- a/util/meson_aux/extra-dist-cmd.sh
+++ b/util/meson_aux/extra-dist-cmd.sh
@@ -2,17 +2,16 @@
 
 # External command, intended to be called with meson.add_dist_script() in meson.build
 
-# extra-dist-cmd.sh <root_source_dir> <root_build_dir> <relative_dist_dir>
+# extra-dist-cmd.sh <root_source_dir> <root_build_dir>
 
-# <relative_dist_dir> is the distribution directory path relative to <root_build_dir>.
 # Meson does not preserve timestamps on distributed files.
 # But this script preserves the timestamps on libstdc++.tag.
 
 # Make a ChangeLog file for distribution.
 git --git-dir="$1/.git" --work-tree="$1" log --no-merges --date=short --max-count=200 \
-    --pretty='tformat:%cd  %an  <%ae>%n%n  %s%n%w(0,0,2)%+b' > "$2/$3/ChangeLog"
+    --pretty='tformat:%cd  %an  <%ae>%n%n  %s%n%w(0,0,2)%+b' > "$MESON_DIST_ROOT/ChangeLog"
 
 # Distribute the libstdc++.tag file in addition to the files in the local git clone.
 # -p == --preserve=mode,ownership,timestamps (Posix does not support long options.)
 # Only the preservation of timestamps is essential here.
-cp -p "$2/libstdc++.tag" "$2/$3/doctags/"
+cp -p "$2/libstdc++.tag" "$MESON_DIST_ROOT/doctags/"
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 c16a344..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 2019-08-25 GNOME "@PACKAGE_STRING@"
+.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 ]
@@ -10,8 +10,8 @@ Run
 to copy the
 .I mm-common
 build support files into the source tree of a C++ binding module.
-If the module is built with Autotools, the exact location these files
-will be copied to can be influenced through special macros in the
+The exact location these files will be copied to can be influenced
+through special macros in the
 .I configure.ac
 file.
 .TP
@@ -43,9 +43,7 @@ Instead, it is assumed that the module depends on
 .I mm-common
 and can use the installed documentation utilities that come with it.
 .PP
-If neither
-.BR \-\-doctooldir ", " \-\-buildscriptdir
-nor a
+If no
 .I SOURCE-DIR
 argument has been specified on the command line, the current working
 directory will be used.
@@ -62,16 +60,6 @@ display a help message and exit
 .TP
 .B \-\-version
 show version information and exit
-.TP
-.BI \-\-doctooldir= DOCTOOL-DIR
-copy the documentation utility files to
-.I DOCTOOL-DIR
-(Meson build)
-.TP
-.BI \-\-buildscriptdir= BUILDSCRIPT-DIR
-copy the build scripts to
-.I BUILDSCRIPT-DIR
-(Meson build)
 .SH "EXIT STATUS"
 The exit status is 0 if OK, or 1 if an error occurred.
 .SH FILES
@@ -79,7 +67,7 @@ The build support files currently copied by
 .B mm-common-prepare
 are listed below.
 .TP
-.BI "Automake include files copied to " AUX-DIR " (Autotools):"
+.BI "Automake include files copied to " AUX-DIR :
 .PD 0
 .IP
 .I compile-binding.am
@@ -91,19 +79,7 @@ are listed below.
 .I generate-binding.am
 .PD
 .TP
-.BI "Shell build scripts copied to " BUILDSCRIPT-DIR " (Meson):"
-.PD 0
-.IP
-.I dist-build-scripts.sh
-.IP
-.I dist-changelog.sh
-.IP
-.I doc-reference.sh
-.IP
-.I generate-binding.sh
-.PD
-.TP
-.BI "Documentation utilities copied to " DOCTOOL-DIR " (Autotools and Meson):"
+.BI "Documentation utilities copied to " DOCTOOL-DIR :
 .PD 0
 .IP
 .I doc-install.pl
@@ -118,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 9ed8502..3a0a7de 100644
--- a/util/mm-common-prepare.in
+++ b/util/mm-common-prepare.in
@@ -27,8 +27,6 @@ installcmd='ln -s'
 instaction=symlinking
 forceflag=
 target=.
-doctooldir=
-buildscriptdir=
 
 for arg
 do
@@ -37,15 +35,12 @@ 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
      --help          display this help message
      --version       print version information
-     --doctooldir=DIR where to store doc tool files (Meson build)
-     --buildscriptdir=DIR where to store build scripts (Meson build)
- DIRECTORY | CONFIGURE-FILE (Autotools build)
 EOF
     exit 0
     ;;
@@ -65,12 +60,6 @@ EOF
     instaction=copying
     forceflag=' -f'
     ;;
-  --doctooldir=*)
-    doctooldir="${arg#--doctooldir=}"
-    ;;
-  --buildscriptdir=*)
-    buildscriptdir="${arg#--buildscriptdir=}"
-    ;;
   -*)
     echo "$progname: error: unrecognized option '$arg'" >&2
     exit 1
@@ -81,46 +70,6 @@ EOF
   esac
 done
 
-# Copy or link files for Meson build.
-if [ -n "$doctooldir" ]; then
-  echo "$progname: putting documentation utilities in '$doctooldir'."
-  # -p == --parents (Posix does not support long options.)
-  mkdir -p "$doctooldir"
-
-  for file in doc-install.pl doc-postprocess.pl doxygen.css doxygen-extra.css tagfile-to-devhelp2.xsl
-  do
-    # Don't update the timestamp of $doctooldir/$file, if it's equal to "$pkgdatadir/doctool/$file".
-    # if file-does-not-exist || (force && files-are-not-equal)
-    # -s == --quiet, --silent
-    if test ! -f "$doctooldir/$file" || \
-       { test -n "$forceflag" && ! cmp -s "$pkgdatadir/doctool/$file" "$doctooldir/$file"; }; then
-      echo "$progname: $instaction file '$file'"
-      $installcmd$forceflag "$pkgdatadir/doctool/$file" "$doctooldir/$file"
-    fi
-  done
-fi
-
-if [ -n "$buildscriptdir" ]; then
-  echo "$progname: putting Meson build scripts in '$buildscriptdir'."
-  mkdir -p "$buildscriptdir"
-
-  for file in dist-build-scripts.sh dist-changelog.sh doc-reference.sh generate-binding.sh
-  do
-    if test ! -f "$buildscriptdir/$file" || \
-       { test -n "$forceflag" && ! cmp -s "$pkgdatadir/build/$file" "$buildscriptdir/$file"; }; then
-      echo "$progname: $instaction file '$file'"
-      $installcmd$forceflag "$pkgdatadir/build/$file" "$buildscriptdir/$file"
-    fi
-  done
-fi
-
-if [ -n "$doctooldir" -o -n "$buildscriptdir" ]; then
-  exit 0
-fi
-
-# Copy or link files for Autotools build.
-# The configure.ac file is read in order to find directories where to store files.
-
 if test -d "$target"; then
   srcdir=$target
   acfile=$target/configure.ac
@@ -140,7 +89,7 @@ auxdir=`sed -n "s/^[$s]*AC_CONFIG_AUX_DIR([[$s]*\\([^])\$,$s]*\\).*/\\1/p" "$acf
 doctooldir=`sed -n "s/^[$s]*MM_CONFIG_DOCTOOL_DIR([[$s]*\\([^])\$,$s]*\\).*/\\1/p" "$acfile"`
 
 auxdir=$srcdir${auxdir:+/}$auxdir
-echo "$progname: putting auxiliary Automake files in '$auxdir'."
+echo "$progname: putting auxiliary files in '$auxdir'."
 test -d "$auxdir" || mkdir "$auxdir"
 
 for file in compile-binding.am dist-changelog.am doc-reference.am generate-binding.am



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