From d28031cb786107c8a4400008ee2e41635ddea992 Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Sat, 28 Sep 2019 11:04:37 +0200 Subject: 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(-) create mode 100755 util/build_scripts/dist-build-scripts.py create mode 100755 util/build_scripts/dist-changelog.py create mode 100755 util/build_scripts/doc-reference.py create mode 100755 util/build_scripts/generate-binding.py create mode 100644 util/mm-common-get.1.in create mode 100644 util/mm-common-get.in 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 . 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 . 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 + +# is the directory with the build scripts, relative to . + +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 + +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 ... + +# 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:] + # ... + + # is a relative or absolute path in the build directory. + # 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] + # + + # and 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:] + # ... + + # is a relative or absolute path in the build directory. + # and 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] + # + + # is a distribution directory, relative to MESON_DIST_ROOT. + # is a relative or absolute path in the build directory. + # and 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 ... + +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:] + # ... + + # is an absolute path in glibmm's installation directory. + # is a relative or absolute path in the build directory. + # 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:] + # ... + + # is an absolute path in glibmm's installation directory. + # is a relative or absolute path in the build directory. + # is an absolute path in the source directory. + # 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:] + # ... + + # is an absolute path in the build directory or source directory. + # 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:] + # ... + + # is an absolute path in the build directory or source directory. + # 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:] + # ... + + # is an absolute or relative path of the directory to copy from. + # 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 . + +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 <