summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Selyutin <ghostmansd@gmail.com>2018-01-29 19:07:42 +0300
committerDmitry Selyutin <ghostmansd@gmail.com>2018-01-29 19:08:46 +0300
commitcee75f59103adf5bcefb537706f32b944b01ffb0 (patch)
treed6bb8bc9d7fb3f37499188e28762e1f79293c165
parentab12fb43daea48e8bb71a35b3b63a3c4c80e87c9 (diff)
downloadgnulib-cee75f59103adf5bcefb537706f32b944b01ffb0.tar.gz
refactored generators; bugfix; tests Makefile.am
-rwxr-xr-xpygnulib.py75
-rw-r--r--pygnulib/config.py50
-rw-r--r--pygnulib/generator.py2057
-rw-r--r--pygnulib/module.py12
-rw-r--r--pygnulib/tools.py64
-rw-r--r--pygnulib/vfs.py27
6 files changed, 1235 insertions, 1050 deletions
diff --git a/pygnulib.py b/pygnulib.py
index f662907916..defa62650a 100755
--- a/pygnulib.py
+++ b/pygnulib.py
@@ -12,23 +12,26 @@ import tempfile
import traceback
import subprocess as sp
+
from pygnulib.error import CommandLineError
from pygnulib.error import UnknownModuleError
from pygnulib.config import BaseConfig
from pygnulib.config import CachedConfig
-from pygnulib.generator import CommandLineGenerator
-from pygnulib.generator import GnulibCacheGenerator
-from pygnulib.generator import LibMakefileGenerator
-from pygnulib.generator import POMakevarsGenerator
-from pygnulib.generator import GnulibCompGenerator
+from pygnulib.generator import gnulib_cache
+from pygnulib.generator import gnulib_comp
+from pygnulib.generator import lib_makefile
+from pygnulib.generator import po_make_vars
+from pygnulib.generator import tests_makefile
from pygnulib.module import DummyModule
from pygnulib.module import Database
from pygnulib.parser import CommandLine as CommandLineParser
+from pygnulib.tools import Executable
+
from pygnulib.vfs import BaseVFS
from pygnulib.vfs import GnulibGitVFS
from pygnulib.vfs import backup as vfs_backup
@@ -44,6 +47,23 @@ from pygnulib.vfs import unlink as vfs_unlink
+class GnulibExecutable(Executable):
+ def __init__(self, name, encoding=None, shell_name=None, shell_path=None):
+ path = None
+ if shell_name is None:
+ shell_name = shell_name.upper()
+ if shell_path is None:
+ shell_path = "{}PATH".format(shell_name)
+ environ = dict(ENVIRON)
+ environ.update(os.environ)
+ if shell_name in environ:
+ path = shell_name
+ elif shell_path in environ:
+ path = "{}{}".format(shell_path)
+ super().__init__(name, path)
+
+
+
AC_VERSION_PATTERN = re.compile(r"AC_PREREQ\(\[(.*?)\]\)", re.S | re.M)
IGNORED_LICENSES = {
"GPLed build tool",
@@ -56,7 +76,7 @@ TRANSFER_MODES = {
"hardlink": vfs_hardlink,
"symlink": vfs_symlink,
}
-SUBSTITUTION_RULES = {
+SUBSTITUTION = {
"build-aux": "auxdir",
"doc": "doc_base",
"lib": "source_base",
@@ -96,7 +116,12 @@ def extract_hook(program, gnulib, mode, namespace, *args, **kwargs):
def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args, **kwargs):
(_, _) = (args, kwargs)
config = BaseConfig(**namespace)
- cache = CachedConfig(root=config.root)
+ try:
+ cache = CachedConfig(root=config.root)
+ except FileNotFoundError:
+ cache = BaseConfig(**config)
+ cache.files = set()
+ cache.ac_version = "2.59"
for key in {"ac_version", "files"}:
if key not in namespace:
config[key] = cache[key]
@@ -165,16 +190,19 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
table = {}
overrides = []
- for (tbl_key, cfg_key) in SUBSTITUTION_RULES.items():
- table[tbl_key] = config[cfg_key] if cfg_key else ""
project = BaseVFS(config.root, **table)
overrides = {BaseVFS(override, **table) for override in config.overrides}
+ for (name, key) in SUBSTITUTION.items():
+ project[name] = config[key] if key else ""
+ for override in overrides:
+ for (name, key) in SUBSTITUTION.items():
+ override[name] = config[key] if key else ""
table = {}
old_files = set(cache.files)
if "m4/gnulib-tool.m4" in project:
old_files |= set(["m4/gnulib-tool.m4"])
- for (tbl_key, cfg_key) in SUBSTITUTION_RULES.items():
+ for (tbl_key, cfg_key) in SUBSTITUTION.items():
table[tbl_key] = cache[cfg_key] if cfg_key else ""
new_files = frozenset(files | set(["m4/gnulib-tool.m4"]))
@@ -271,7 +299,8 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
# Generate the contents of library makefile.
path = os.path.join(config.source_base, config.makefile_name)
with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
- for line in LibMakefileGenerator(path, config, explicit, database, mkedits, False):
+ modules = database.main_modules
+ for line in lib_makefile(path, config, explicit, database, modules, mkedits, False):
print(line, file=tmp)
(src, dst) = (tmp.name, path)
present = vfs_exists(project, dst)
@@ -297,7 +326,7 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
action(bool(match), vfs, src, project, dst, present)
# Create po makefile parameterization, part 1.
with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
- for line in POMakevarsGenerator(config):
+ for line in po_make_vars(config):
print(line, file=tmp)
(src, dst) = (tmp.name, "po/Makevars")
present = vfs_exists(project, dst)
@@ -308,7 +337,7 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
os.unlink(tmp.name)
# Create po makefile parameterization, part 2.
with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
- for line in POMakevarsGenerator(config):
+ for line in po_make_vars(config):
print(line, file=tmp)
(src, dst) = (tmp.name, "po/POTFILESGenerator.in")
present = vfs_exists(project, dst)
@@ -353,7 +382,7 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
# Create m4/gnulib-cache.m4.
with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
- for line in GnulibCacheGenerator(config):
+ for line in gnulib_cache(config):
print(line, file=tmp)
(src, dst) = (tmp.name, "m4/gnulib-cache.m4")
present = vfs_exists(project, dst)
@@ -365,7 +394,7 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
# Create m4/gnulib-comp.m4.
with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
- for line in GnulibCompGenerator(config, explicit, database):
+ for line in gnulib_comp(config, explicit, database, True):
print(line, file=tmp)
(src, dst) = (tmp.name, "m4/gnulib-comp.m4")
present = vfs_exists(project, dst)
@@ -375,6 +404,21 @@ def import_hook(script, gnulib, namespace, explicit, verbosity, options, *args,
action(False, None, src, project, dst, present)
os.unlink(tmp.name)
+ # Generate the contents of tests makefile.
+ if config.tests:
+ path = os.path.join(config.tests_base, config.makefile_name)
+ with tempfile.NamedTemporaryFile("w", encoding="UTF-8", delete=False) as tmp:
+ modules = database.test_modules
+ for line in tests_makefile(path, config, explicit, database, modules, mkedits, False):
+ print(line, file=tmp)
+ (src, dst) = (tmp.name, path)
+ present = vfs_exists(project, dst)
+ if present:
+ added_files.add(dst)
+ action = update_file if present else add_file
+ action(False, None, src, project, dst, present)
+ os.unlink(tmp.name)
+
return os.EX_OK
@@ -420,6 +464,7 @@ HOOKS = {
def main(script, gnulib, program, arguments, environ):
gnulib = GnulibGitVFS(gnulib)
+ gnulib["tests=lib"] = "lib"
parser = CommandLineParser(program)
try:
(namespace, mode, verbosity, options) = parser.parse(arguments)
diff --git a/pygnulib/config.py b/pygnulib/config.py
index 546c804ce7..71c04cb322 100644
--- a/pygnulib/config.py
+++ b/pygnulib/config.py
@@ -41,6 +41,45 @@ OTHER_LICENSES = frozenset({
+KEYS = frozenset({
+ "root",
+ "overrides",
+ "source_base",
+ "m4_base",
+ "po_base",
+ "doc_base",
+ "tests_base",
+ "auxdir",
+ "libname",
+ "makefile_name",
+ "macro_prefix",
+ "po_domain",
+ "witness_c_macro",
+ "licenses",
+ "ac_version",
+ "ac_file",
+ "modules",
+ "avoids",
+ "files",
+ "copymode",
+ "local_copymode",
+ "tests",
+ "obsolete",
+ "cxx_tests",
+ "longrunning_tests",
+ "privileged_tests",
+ "unportable_tests",
+ "libtool",
+ "conditionals",
+ "copyrights",
+ "gnumake",
+ "single_configure",
+ "vc_files",
+ "all_tests",
+})
+
+
+
class BaseConfig:
"""gnulib generic configuration"""
_TABLE = {
@@ -424,7 +463,7 @@ class BaseConfig:
@property
def obsolete(self):
"""include obsolete modules when they occur among the modules?"""
- return bool(self.__options & BaseConfig._Option.Tests)
+ return bool(self.__options & BaseConfig._Option.Obsolete)
@obsolete.setter
def obsolete(self, value):
@@ -586,17 +625,17 @@ class BaseConfig:
def __getitem__(self, key):
- if key not in BaseConfig._TABLE:
+ if key not in KEYS:
key = key.replace("-", "_")
- if key not in BaseConfig._TABLE:
+ if key not in KEYS:
raise KeyError("unsupported option: {0}".format(key))
return getattr(self, key)
def __setitem__(self, key, value):
- if key not in BaseConfig._TABLE:
+ if key not in KEYS:
key = key.replace("_", "-")
- if key not in BaseConfig._TABLE:
+ if key not in KEYS:
raise KeyError("unsupported option: {0}".format(key))
return setattr(self, key, value)
@@ -657,6 +696,7 @@ class CachedConfig(BaseConfig):
if ac_file is None:
ac_file = "configure.ac"
_type_assert("ac_file", ac_file, str)
+
ac_path = _os.path.join(root, ac_file)
if not _os.path.exists(ac_path):
ac_file = "configure.in"
diff --git a/pygnulib/generator.py b/pygnulib/generator.py
index c511048247..8b2be1c3c4 100644
--- a/pygnulib/generator.py
+++ b/pygnulib/generator.py
@@ -29,11 +29,7 @@ _LGPL = {
_LGPL_LICENSE: "yes",
(_GPLv2_LICENSE | _LGPLv3_LICENSE): "3orGPLv2",
}
-_ITERABLES = frozenset((list, tuple, set, frozenset, type({}.keys()), type({}.values())))
-
-
-
-_DISCLAIMER = (
+__DISCLAIMER = (
"## DO NOT EDIT! GENERATED AUTOMATICALLY!",
"#",
"# This file is free software; you can redistribute it and/or modify",
@@ -56,1053 +52,1086 @@ _DISCLAIMER = (
"#",
"# Generated by gnulib-tool.",
)
+_ITERABLES = frozenset((list, tuple, set, frozenset, type({}.keys()), type({}.values())))
-class BaseGenerator:
- """gnulib file content generator"""
- def __repr__(self):
- module = self.__class__.__module__
- name = self.__class__.__name__
- return "{0}.{1}".format(module, name)
-
-
- def __str__(self):
- return "\n".join([_ for _ in self])
-
-
- def __enter__(self):
- return self
-
-
- def __exit__(self, exctype, excval, exctrace):
- pass
-
-
- def __iter__(self):
- yield
-
-
-
-class POMakevarsGenerator(BaseGenerator):
- """PO Makefile parameterization"""
- _TEMPLATE = (
- "# These options get passed to xgettext.",
- "XGETTEXT_OPTIONS = \\",
- " --keyword=_ --flag=_:1:pass-c-format \\",
- " --keyword=N_ --flag=N_:1:pass-c-format \\",
- " --keyword='proper_name:1,\"This is a proper name." # comma omitted
- " See the gettext manual, section Names.\"' \\",
- " --keyword='proper_name_utf8:1,\"This is a proper name." # comma omitted
- " See the gettext manual, section Names.\"' \\",
- " --flag=error:3:c-format --flag=error_at_line:5:c-format",
- "",
- "# This is the copyright holder that gets inserted into the header of the",
- "# $(DOMAIN).pot file. gnulib is copyrighted by the FSF.",
- "COPYRIGHT_HOLDER = Free Software Foundation, Inc.",
- "",
- "# This is the email address or URL to which the translators shall report",
- "# bugs in the untranslated strings:",
- "# - Strings which are not entire sentences, see the maintainer guidelines",
- "# in the GNU gettext documentation, section 'Preparing Strings'.",
- "# - Strings which use unclear terms or require additional context to be",
- "# understood.",
- "# - Strings which make invalid assumptions about notation of date, time or",
- "# money.",
- "# - Pluralisation problems.",
- "# - Incorrect English spelling.",
- "# - Incorrect formatting.",
- "# It can be your email address, or a mailing list address where translators",
- "# can write to without being subscribed, or the URL of a web page through",
- "# which the translators can contact you.",
- "MSGID_BUGS_ADDRESS = bug-gnulib@gnu.org",
- "",
- "# This is the list of locale categories, beyond LC_MESSAGES, for which the",
- "# message catalogs shall be used. It is usually empty.",
- "EXTRA_LOCALE_CATEGORIES =",
- "",
- "# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt'",
- "# context. Possible values are \"yes\" and \"no\". Set this to yes if the",
- "# package uses functions taking also a message context, like pgettext(), or",
- "# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument.",
- "USE_MSGCTXT = no"
- )
-
-
- def __init__(self, config):
- _type_assert("config", config, _BaseConfig)
- super().__init__()
- self.__config = config
-
-
- @property
- def po_base(self):
- """directory relative to ROOT where *.po files are placed; defaults to 'po'"""
- return self.__config.po_base
-
-
- @property
- def po_domain(self):
- """the prefix of the i18n domain"""
- return self.__config.po_domain
-
-
- def __repr__(self):
- module = self.__class__.__module__
- name = self.__class__.__name__
- fmt = "{}.{}{po_base={}, po_domain={}}"
- return fmt.format(module, name, repr(self.__config.po_base), repr(self.__config.po_domain))
-
-
- def __iter__(self):
- for line in _DISCLAIMER:
- yield line
- yield "# Usually the message domain is the same as the package name."
- yield "# But here it has a '-gnulib' suffix."
- yield "DOMAIN = {}-gnulib".format(self.po_domain)
- yield ""
- yield "# These two variables depend on the location of this directory."
- yield "subdir = {}".format(self.po_domain)
- yield "top_subdir = {}".format("/".join(".." for _ in self.po_base.split(_os.path.sep)))
- for line in POMakevarsGenerator._TEMPLATE:
- yield line
-
-
-
-class POTFILESGenerator(BaseGenerator):
- """file list to be passed to xgettext"""
- def __init__(self, config, files):
- _type_assert("config", config, _BaseConfig)
- super().__init__()
- self.__config = config
- self.__files = tuple(files)
-
-
- @property
- def files(self):
- """list of files"""
- return tuple(self.files)
-
-
- def __repr__(self):
- module = self.__class__.__module__
- name = self.__class__.__name__
- fmt = "{}.{}{files={}}"
- return fmt.format(module, name, repr(self.__files))
-
+__PO_MAKE_VARS = (
+ "# These options get passed to xgettext.",
+ "XGETTEXT_OPTIONS = \\",
+ " --keyword=_ --flag=_:1:pass-c-format \\",
+ " --keyword=N_ --flag=N_:1:pass-c-format \\",
+ " --keyword='proper_name:1,\"This is a proper name. See the gettext manual, section Names.\"' \\",
+ " --keyword='proper_name_utf8:1,\"This is a proper name. See the gettext manual, section Names.\"' \\",
+ " --flag=error:3:c-format --flag=error_at_line:5:c-format",
+ "",
+ "# This is the copyright holder that gets inserted into the header of the",
+ "# $(DOMAIN).pot file. gnulib is copyrighted by the FSF.",
+ "COPYRIGHT_HOLDER = Free Software Foundation, Inc.",
+ "",
+ "# This is the email address or URL to which the translators shall report",
+ "# bugs in the untranslated strings:",
+ "# - Strings which are not entire sentences, see the maintainer guidelines",
+ "# in the GNU gettext documentation, section 'Preparing Strings'.",
+ "# - Strings which use unclear terms or require additional context to be",
+ "# understood.",
+ "# - Strings which make invalid assumptions about notation of date, time or",
+ "# money.",
+ "# - Pluralisation problems.",
+ "# - Incorrect English spelling.",
+ "# - Incorrect formatting.",
+ "# It can be your email address, or a mailing list address where translators",
+ "# can write to without being subscribed, or the URL of a web page through",
+ "# which the translators can contact you.",
+ "MSGID_BUGS_ADDRESS = bug-gnulib@gnu.org",
+ "",
+ "# This is the list of locale categories, beyond LC_MESSAGES, for which the",
+ "# message catalogs shall be used. It is usually empty.",
+ "EXTRA_LOCALE_CATEGORIES =",
+ "",
+ "# This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt'",
+ "# context. Possible values are \"yes\" and \"no\". Set this to yes if the",
+ "# package uses functions taking also a message context, like pgettext(), or",
+ "# if in $(XGETTEXT_OPTIONS) you define keywords with a context argument.",
+ "USE_MSGCTXT = no"
+)
- def __iter__(self):
- for line in _DISCLAIMER:
- yield line
- yield "# List of files which contain translatable strings."
- for file in [_ for _ in self.files if _.startswith("lib/")]:
- yield _os.path.join(self.__config.source_base, file[4:])
-
-
-
-class AutoconfSnippetGenerator(BaseGenerator):
- """autoconf snippet generator for standalone module"""
- def __init__(self, config, module, toplevel, no_libtool, no_gettext):
- """
- config: gnulib configuration
- module: gnulib module instance
- toplevel: make a subordinate use of gnulib if False
- no_libtool: disable libtool (regardless of configuration)
- no_gettext: disable AM_GNU_GETTEXT invocations if True
- """
- _type_assert("config", config, _BaseConfig)
- _type_assert("module", module, _BaseModule)
- _type_assert("toplevel", toplevel, bool)
- _type_assert("no_libtool", no_libtool, bool)
- _type_assert("no_gettext", no_gettext, bool)
- super().__init__()
- self.__config = config
- self.__module = module
- self.__toplevel = toplevel
- self.__no_libtool = no_libtool
- self.__no_gettext = no_gettext
-
-
- @property
- def toplevel(self):
- """top level indicator; subordinate use of pygnulib"""
- return self.__toplevel
-
-
- @property
- def libtool(self):
- """libtool switch, disabling libtool configuration parameter"""
- return self.__config.libtool and not self.__no_libtool
-
- @property
- def gettext(self):
- """gettext switch, disabling AM_GNU_GETTEXT invocations"""
- return not self.__no_gettext
-
-
- def __repr__(self):
- flags = []
- module = self.__class__.__module__
- name = self.__class__.__name__
- if self.toplevel:
- flags += ["toplevel"]
- if self.libtool:
- flags += ["libtool"]
- if self.gettext:
- flags += ["gettext"]
- include_guard_prefix = self.__config.include_guard_prefix
- flags = "|".join(flags)
- fmt = "{}.{}{include_guard_prefix={}, flags={}}"
- return fmt.format(module, name, repr(include_guard_prefix), flags)
-
-
- def __iter__(self):
- module = self.__module
- if module.name not in ("gnumakefile", "maintainer-makefile") or self.toplevel:
- snippet = module.autoconf_snippet
- include_guard_prefix = self.__config.include_guard_prefix
- snippet.replace(r"${gl_include_guard_prefix}", include_guard_prefix)
- if not self.libtool:
- table = (
- (r"$gl_cond_libtool", "false"),
- ("gl_libdeps", "gltests_libdeps"),
- ("gl_ltlibdeps", "gltests_ltlibdeps"),
- )
- for (src, dst) in table:
- snippet = snippet.replace(src, dst)
- if not self.gettext:
- src = "AM_GNU_GETTEXT([external])"
- dst = "dnl you must add AM_GNU_GETTEXT([external]) or similar to configure.ac.'"
+def po_make_vars(config, **override):
+ """Generate PO Makefile parameterization."""
+ _type_assert("config", config, _BaseConfig)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+
+ po_base = config.po_base
+ po_domain = comnfig.po_domain
+ for line in __DISCLAIMER:
+ yield line
+ yield "# Usually the message domain is the same as the package name."
+ yield "# But here it has a '-gnulib' suffix."
+ yield f"DOMAIN = {po_domain}-gnulib"
+ yield ""
+ yield "# These two variables depend on the location of this directory."
+ yield f"subdir = {po_base}"
+ top_builddir = "/".join(".." for _ in config.po_base.split(_os.path.sep))
+ yield f"top_builddir = {top_builddir}"
+ for line in __PO_MAKE_VARS:
+ yield line
+
+
+
+def POTFILES(config, files, **override):
+ """Generate file list to be passed to xgettext."""
+ _type_assert("config", config, _BaseConfig)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+
+ source_base = config.source_base
+ for line in __DISCLAIMER:
+ yield line
+ yield "# List of files which contain translatable strings."
+ for file in filter(lambda file: file.startswith("lib/"), files):
+ yield _os.path.join(source_base, file[4:])
+
+
+
+def autoconf_snippet(config, module, toplevel, no_libtool, no_gettext, **override):
+ """
+ Generate autoconf snippet for a standalone module.
+
+ <config> gnulib configuration
+ <module> gnulib module instance
+ <toplevel> make a subordinate use of gnulib if False
+ <no_libtool> disable libtool (regardless of configuration)
+ <no_gettext> disable AM_GNU_GETTEXT invocations if True
+ """
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("module", module, _BaseModule)
+ _type_assert("toplevel", toplevel, bool)
+ _type_assert("no_libtool", no_libtool, bool)
+ _type_assert("no_gettext", no_gettext, bool)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+
+ libtool = config.libtool and not no_libtool
+ gettext = not no_gettext
+ if module.name not in ("gnumakefile", "maintainer-makefile") or toplevel:
+ snippet = module.autoconf_snippet
+ include_guard_prefix = config.include_guard_prefix
+ snippet.replace(r"${gl_include_guard_prefix}", include_guard_prefix)
+ if not config.libtool:
+ table = (
+ (r"$gl_cond_libtool", "false"),
+ (r"gl_libdeps", "gltests_libdeps"),
+ (r"gl_ltlibdeps", "gltests_ltlibdeps"),
+ )
+ for (src, dst) in table:
snippet = snippet.replace(src, dst)
- else:
- # Don't indent AM_GNU_GETTEXT_VERSION line, as that confuses
- # autopoint through at least GNU gettext version 0.18.2.
- snippet = snippet.lstrip()
- lines = (_ for _ in snippet.split("\n") if _)
- for line in lines:
- yield line
- if module.name == "alloca" and self.libtool:
- yield "changequote(,)dnl"
- yield "LTALLOCA=`echo \"$ALLOCA\" | sed -e 's/\\.[^.]* /.lo /g;s/\\.[^.]*$/.lo/'`"
- yield "changequote([, ])dnl"
- yield "AC_SUBST([LTALLOCA])"
-
-
-
-class AutoconfMultisnippetGenerator(BaseGenerator):
- """multi-module autoconf snippets generator"""
- def __init__(self, config, database, modules, toplevel, no_libtool, no_gettext, macro_prefix=None):
- _type_assert("config", config, _BaseConfig)
- _type_assert("database", database, _Database)
- _type_assert("modules", modules, _ITERABLES)
- _type_assert("toplevel", toplevel, bool)
- _type_assert("no_libtool", no_libtool, bool)
- _type_assert("no_gettext", no_gettext, bool)
- if macro_prefix is None:
- macro_prefix = config.macro_prefix
- _type_assert("macro_prefix", macro_prefix, str)
- super().__init__()
- self.__config = config
- self.__database = database
- self.__modules = set()
+ if not gettext:
+ src = "AM_GNU_GETTEXT([external])"
+ dst = "dnl you must add AM_GNU_GETTEXT([external]) or similar to configure.ac.'"
+ snippet = snippet.replace(src, dst)
+ else:
+ # Don't indent AM_GNU_GETTEXT_VERSION line, as that confuses
+ # autopoint through at least GNU gettext version 0.18.2.
+ snippet = snippet.lstrip()
+ lines = filter(lambda line: line.strip(), snippet.split("\n"))
+ for line in lines:
+ yield line
+ if module.name == "alloca" and libtool:
+ yield "changequote(,)dnl"
+ yield "LTALLOCA=`echo \"$ALLOCA\" | sed -e 's/\\.[^.]* /.lo /g;s/\\.[^.]*$/.lo/'`"
+ yield "changequote([, ])dnl"
+ yield "AC_SUBST([LTALLOCA])"
+
+
+
+def autoconf_snippet_sequence(config, database, modules, toplevel, no_libtool, no_gettext, **override):
+ """
+ Generate an autoconf snippet for multiple modules.
+
+ <config> gnulib configuration
+ <module> gnulib module instance
+ <toplevel> make a subordinate use of gnulib if False
+ <no_libtool> disable libtool (regardless of configuration)
+ <no_gettext> disable AM_GNU_GETTEXT invocations if True
+ [macro_prefix] the prefix of the macros 'gl_EARLY' and 'gl_INIT'
+ """
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("database", database, _Database)
+ _type_assert("modules", modules, _ITERABLES)
+ _type_assert("toplevel", toplevel, bool)
+ _type_assert("no_libtool", no_libtool, bool)
+ _type_assert("no_gettext", no_gettext, bool)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+ macro_prefix = config.macro_prefix
+
+ arguments = {
+ "config": config,
+ "module": None,
+ "toplevel": toplevel,
+ "no_libtool": no_libtool,
+ "no_gettext": no_gettext,
+ }
+ if not config.conditionals:
for module in modules:
- _type_assert("module", module, _BaseModule)
- self.__modules.add(module)
- self.__modules = sorted(self.__modules)
- self.__toplevel = toplevel
- self.__no_libtool = no_libtool
- self.__no_gettext = no_gettext
- self.__macro_prefix = macro_prefix
-
-
- def __iter__(self):
- config = self.__config
- database = self.__database
- modules = self.__modules
- macro_prefix = self.__macro_prefix
-
- arguments = {
- "config": config,
- "module": None,
- "toplevel": self.__toplevel,
- "no_libtool": self.__no_libtool,
- "no_gettext": self.__no_gettext,
- }
- if not config.conditionals:
- for module in sorted(modules):
- arguments["module"] = module
- for line in AutoconfSnippetGenerator(**arguments):
- yield " {}".format(line)
- return
-
- conditional = set()
- unconditional = set()
- for dependency in modules:
- if database.conditional(dependency):
- conditional.add(dependency)
- else:
- unconditional.add(dependency)
- conditional = sorted(conditional)
- unconditional = sorted(unconditional)
-
- # Emit the autoconf code for the unconditional modules.
- for module in unconditional:
arguments["module"] = module
- for line in AutoconfSnippetGenerator(**arguments):
- yield " {}".format(line)
-
- # Initialize the shell variables indicating that the modules are enabled.
- for module in conditional:
- shellvar = module.shell_variable(macro_prefix)
- yield " {}=false".format(shellvar)
-
- # Emit the autoconf code for the conditional modules, each in a separate
- # function. This makes it possible to support cycles among conditional
- # modules.
- for demander in conditional:
- shellvar = demander.shell_variable(macro_prefix)
- shellfunc = demander.shell_function(macro_prefix)
- yield " {} ()".format(shellfunc)
- yield " {"
- yield " if ! ${}; then".format(shellvar)
- arguments["module"] = demander
- for line in AutoconfSnippetGenerator(**arguments):
- yield " {}".format(line)
- yield " {}=true".format(shellvar)
- for (dependency, condition) in sorted(database.dependencies(demander)):
- if database.conditional(dependency):
- shellfunc = dependency.shell_function(macro_prefix)
- if condition is not None:
- yield " if {}; then".format(condition)
- yield " {}".format(shellfunc)
- yield " fi"
- else:
- yield " {}".format(shellfunc)
- yield " fi"
- yield " }"
-
- # Emit the dependencies from the unconditional to the conditional modules.
- for demander in unconditional:
- for (dependency, condition) in sorted(database.dependencies(demander)):
- if dependency in modules and database.conditional(dependency):
- condname = dependency.conditional_name(macro_prefix)
- shellfunc = dependency.shell_function(macro_prefix)
- if condition is not None:
- yield " if {}; then".format(condition)
- yield " {}".format(shellfunc)
- yield " fi"
- else:
- yield " {}".format(shellfunc)
-
- # Define the Automake conditionals.
- yield " m4_pattern_allow([^{}_GNULIB_ENABLED_])".format(macro_prefix)
- for module in conditional:
- condname = module.conditional_name(macro_prefix)
- shellvar = module.shell_variable(macro_prefix)
- yield " AM_CONDITIONAL([{}], [${}])".format(condname, shellvar)
-
-
-
-class InitMacroGenerator(BaseGenerator):
- """basic gl_INIT macro generator"""
- def __init__(self, config, macro_prefix=None):
- """
- config: gnulib configuration
- macro_prefix: macro prefix; if None, consider configuration
- """
- _type_assert("config", config, _BaseConfig)
- if macro_prefix is None:
- macro_prefix = config.macro_prefix
- _type_assert("macro_prefix", macro_prefix, str)
- super().__init__()
- self.__macro_prefix = macro_prefix
-
-
- @property
- def macro_prefix(self):
- """the prefix of the macros 'gl_EARLY' and 'gl_INIT'"""
- return self.__macro_prefix
-
-
- def __repr__(self):
- module = self.__class__.__module__
- name = self.__class__.__name__
- fmt = "{}.{}{macro_prefix={}}"
- return fmt.format(module, name, repr(self.__macro_prefix))
-
-
-
-class InitMacroHeaderGenerator(InitMacroGenerator):
- """the first few statements of the gl_INIT macro"""
- _TEMPLATE = (
- # Overriding AC_LIBOBJ and AC_REPLACE_FUNCS has the effect of storing
- # platform-dependent object files in ${macro_prefix_arg}_LIBOBJS instead
- # of LIBOBJS. The purpose is to allow several gnulib instantiations under
- # a single configure.ac file. (AC_CONFIG_LIBOBJ_DIR does not allow this
- # flexibility).
- # Furthermore it avoids an automake error like this when a Makefile.am
- # that uses pieces of gnulib also uses $(LIBOBJ):
- # automatically discovered file `error.c' should not be explicitly
- # mentioned.
- " m4_pushdef([AC_LIBOBJ], m4_defn([{macro_prefix}_LIBOBJ]))",
- " m4_pushdef([AC_REPLACE_FUNCS], m4_defn([{macro_prefix}_REPLACE_FUNCS]))",
-
- # Overriding AC_LIBSOURCES has the same purpose of avoiding the automake
- # error when a Makefile.am that uses pieces of gnulib also uses $(LIBOBJ):
- # automatically discovered file `error.c' should not be explicitly
- # mentioned
- # We let automake know about the files to be distributed through the
- # EXTRA_lib_SOURCES variable.
- " m4_pushdef([AC_LIBSOURCES], m4_defn([{macro_prefix}_LIBSOURCES]))",
-
- # Create data variables for checking the presence of files that are
- # mentioned as AC_LIBSOURCES arguments. These are m4 variables, not shell
- # variables, because we want the check to happen when the configure file is
- # created, not when it is run. ${macro_prefix_arg}_LIBSOURCES_LIST is the
- # list of files to check for. ${macro_prefix_arg}_LIBSOURCES_DIR is the
- # subdirectory in which to expect them.
- " m4_pushdef([{macro_prefix}_LIBSOURCES_LIST], [])",
- " m4_pushdef([{macro_prefix}_LIBSOURCES_DIR], [])",
- " gl_COMMON",
- )
-
+ for line in autoconf_snippet(**arguments):
+ yield f" {line}"
+ return
+
+ conditional = set()
+ unconditional = set()
+ for dependency in modules:
+ if database.conditional(dependency):
+ conditional.add(dependency)
+ else:
+ unconditional.add(dependency)
+ conditional = sorted(conditional)
+ unconditional = sorted(unconditional)
+
+ # Emit the autoconf code for the unconditional modules.
+ for module in unconditional:
+ arguments["module"] = module
+ for line in autoconf_snippet(**arguments):
+ yield f" {line}"
+
+ # Initialize the shell variables indicating that the modules are enabled.
+ for module in conditional:
+ shellvar = module.shell_variable(macro_prefix)
+ yield f" {shellvar}=false"
+
+ # Emit the autoconf code for the conditional modules, each in a separate
+ # function. This makes it possible to support cycles among conditional
+ # modules.
+ for demander in conditional:
+ arguments["module"] = demander
+ shellvar = demander.shell_variable(macro_prefix)
+ shellfunc = demander.shell_function(macro_prefix)
+ yield f" {shellfunc} ()"
+ yield f" {{"
+ yield f" if ! ${shellvar}; then"
+ for line in autoconf_snippet(**arguments):
+ yield f" {line}"
+ yield f" {shellvar}=true"
+ for (dependency, condition) in sorted(database.dependencies(demander)):
+ if database.conditional(dependency):
+ shellfunc = dependency.shell_function(macro_prefix)
+ if condition is not None:
+ yield f" if {condition}; then"
+ yield f" {shellfunc}"
+ yield f" fi"
+ else:
+ yield f" {shellfunc}"
+ yield f" fi"
+ yield f" }}"
+
+ # Emit the dependencies from the unconditional to the conditional modules.
+ for demander in unconditional:
+ for (dependency, condition) in sorted(database.dependencies(demander)):
+ if dependency in modules and database.conditional(dependency):
+ condname = dependency.conditional_name(macro_prefix)
+ shellfunc = dependency.shell_function(macro_prefix)
+ if condition is not None:
+ yield f" if {condition}; then"
+ yield f" {shellfunc}"
+ yield f" fi"
+ continue
+ else:
+ yield f" {shellfunc}"
+
+ # Define the Automake conditionals.
+ yield f" m4_pattern_allow([^{macro_prefix}_GNULIB_ENABLED_])"
+ for module in conditional:
+ condname = module.conditional_name(macro_prefix)
+ shellvar = module.shell_variable(macro_prefix)
+ yield f" AM_CONDITIONAL([{condname}], [${shellvar}])"
+
+
+
+__INIT_MACRO_HEADER = (
+ # Overriding AC_LIBOBJ and AC_REPLACE_FUNCS has the effect of storing
+ # platform-dependent object files in ${macro_prefix_arg}_LIBOBJS instead
+ # of LIBOBJS. The purpose is to allow several gnulib instantiations under
+ # a single configure.ac file. (AC_CONFIG_LIBOBJ_DIR does not allow this
+ # flexibility).
+ # Furthermore it avoids an automake error like this when a Makefile.am
+ # that uses pieces of gnulib also uses $(LIBOBJ):
+ # automatically discovered file `error.c' should not be explicitly
+ # mentioned.
+ " m4_pushdef([AC_LIBOBJ], m4_defn([{macro_prefix}_LIBOBJ]))",
+ " m4_pushdef([AC_REPLACE_FUNCS], m4_defn([{macro_prefix}_REPLACE_FUNCS]))",
+
+ # Overriding AC_LIBSOURCES has the same purpose of avoiding the automake
+ # error when a Makefile.am that uses pieces of gnulib also uses $(LIBOBJ):
+ # automatically discovered file `error.c' should not be explicitly
+ # mentioned
+ # We let automake know about the files to be distributed through the
+ # EXTRA_lib_SOURCES variable.
+ " m4_pushdef([AC_LIBSOURCES], m4_defn([{macro_prefix}_LIBSOURCES]))",
+
+ # Create data variables for checking the presence of files that are
+ # mentioned as AC_LIBSOURCES arguments. These are m4 variables, not shell
+ # variables, because we want the check to happen when the configure file is
+ # created, not when it is run. ${macro_prefix_arg}_LIBSOURCES_LIST is the
+ # list of files to check for. ${macro_prefix_arg}_LIBSOURCES_DIR is the
+ # subdirectory in which to expect them.
+ " m4_pushdef([{macro_prefix}_LIBSOURCES_LIST], [])",
+ " m4_pushdef([{macro_prefix}_LIBSOURCES_DIR], [])",
+ " gl_COMMON",
+)
- def __init__(self, config, macro_prefix=None):
- """
- config: gnulib configuration
- macro_prefix: macro prefix; if None, consider configuration
- """
- super().__init__(config=config, macro_prefix=macro_prefix)
-
-
- def __iter__(self):
- macro_prefix = self.macro_prefix
- for line in InitMacroHeaderGenerator._TEMPLATE:
- yield line.format(macro_prefix=macro_prefix)
-
-
-
-class InitMacroFooterGenerator(InitMacroGenerator):
- """the last few statements of the gl_INIT macro"""
- _TEMPLATE = (
- " m4_ifval({macro_prefix}_LIBSOURCES_LIST, [",
- " m4_syscmd([test ! -d ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[ ||",
- " for gl_file in ]{macro_prefix}_LIBSOURCES_LIST[ ; do",
- " if test ! -r ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[/$gl_file ; then",
- " echo \"missing file ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[/$gl_file\" >&2",
- " exit 1",
- " fi",
- " done])dnl",
- " m4_if(m4_sysval, [0], [],",
- " [AC_FATAL([expected source file, required through AC_LIBSOURCES, not found])])",
- " ])",
- " m4_popdef([{macro_prefix}_LIBSOURCES_DIR])",
- " m4_popdef([{macro_prefix}_LIBSOURCES_LIST])",
- " m4_popdef([AC_LIBSOURCES])",
- " m4_popdef([AC_REPLACE_FUNCS])",
- " m4_popdef([AC_LIBOBJ])",
- " AC_CONFIG_COMMANDS_PRE([",
- " {macro_prefix}_libobjs=",
- " {macro_prefix}_ltlibobjs=",
- " if test -n \"${macro_prefix}_LIBOBJS\"; then",
- " # Remove the extension.",
- " sed_drop_objext='s/\\.o$//;s/\\.obj$//'",
- " for i in `for i in ${macro_prefix}_LIBOBJS; " # comma omitted
- "do echo \"$i\"; done | sed -e \"$sed_drop_objext\" | sort | uniq`; do",
- " {macro_prefix}_libobjs=\"${macro_prefix}_libobjs $i.$ac_objext\"",
- " {macro_prefix}_ltlibobjs=\"${macro_prefix}_ltlibobjs $i.lo\"",
- " done",
- " fi",
- " AC_SUBST([{macro_prefix}_LIBOBJS], [${macro_prefix}_libobjs])",
- " AC_SUBST([{macro_prefix}_LTLIBOBJS], [${macro_prefix}_ltlibobjs])",
- " ])",
- )
+def init_macro_header(config, **override):
+ """
+ Generate the first few statements of the gl_INIT macro.
+
+ [macro_prefix] the prefix of the macros 'gl_EARLY' and 'gl_INIT'
+ """
+ _type_assert("config", config, _BaseConfig)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+ macro_prefix = config.macro_prefix
+
+ for line in __INIT_MACRO_HEADER:
+ yield line.format(**config)
+
+
+
+__INIT_MACRO_FOOTER = (
+ # Check the presence of files that are mentioned as AC_LIBSOURCES
+ # arguments. The check is performed only when autoconf is run from the
+ # directory where the configure.ac resides; if it is run from a different
+ # directory, the check is skipped.
+ " m4_ifval({macro_prefix}_LIBSOURCES_LIST, [",
+ " m4_syscmd([test ! -d ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[ ||",
+ " for gl_file in ]{macro_prefix}_LIBSOURCES_LIST[ ; do",
+ " if test ! -r ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[/$gl_file ; then",
+ " echo \"missing file ]m4_defn([{macro_prefix}_LIBSOURCES_DIR])[/$gl_file\" >&2",
+ " exit 1",
+ " fi",
+ " done])dnl",
+ " m4_if(m4_sysval, [0], [],",
+ " [AC_FATAL([expected source file, required through AC_LIBSOURCES, not found])])",
+ " ])",
+ " m4_popdef([{macro_prefix}_LIBSOURCES_DIR])",
+ " m4_popdef([{macro_prefix}_LIBSOURCES_LIST])",
+ " m4_popdef([AC_LIBSOURCES])",
+ " m4_popdef([AC_REPLACE_FUNCS])",
+ " m4_popdef([AC_LIBOBJ])",
+ " AC_CONFIG_COMMANDS_PRE([",
+ " {macro_prefix}_libobjs=",
+ " {macro_prefix}_ltlibobjs=",
+ " if test -n \"${macro_prefix}_LIBOBJS\"; then",
+ " # Remove the extension.",
+ " sed_drop_objext='s/\\.o$//;s/\\.obj$//'",
+ " for i in `for i in ${macro_prefix}_LIBOBJS; " # comma omitted
+ "do echo \"$i\"; done | sed -e \"$sed_drop_objext\" | sort | uniq`; do",
+ " {macro_prefix}_libobjs=\"${macro_prefix}_libobjs $i.$ac_objext\"",
+ " {macro_prefix}_ltlibobjs=\"${macro_prefix}_ltlibobjs $i.lo\"",
+ " done",
+ " fi",
+ " AC_SUBST([{macro_prefix}_LIBOBJS], [${macro_prefix}_libobjs])",
+ " AC_SUBST([{macro_prefix}_LTLIBOBJS], [${macro_prefix}_ltlibobjs])",
+ " ])",
+)
+def init_macro_footer(config, **override):
+ """Generate the last few statements of the gl_INIT macro."""
+ _type_assert("config", config, _BaseConfig)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+ macro_prefix = config.macro_prefix
+
+ for line in __INIT_MACRO_FOOTER:
+ yield line.format(**config)
+
+
+
+__INIT_MACRO_DONE = (
+ "",
+ "# Like AC_LIBOBJ, except that the module name goes",
+ "# into {macro_prefix}_LIBOBJS instead of into LIBOBJS.",
+ "AC_DEFUN([{macro_prefix}_LIBOBJ], [",
+ " AS_LITERAL_IF([$1], [{macro_prefix}_LIBSOURCES([$1.c])])dnl",
+ " {macro_prefix}_LIBOBJS=\"${macro_prefix}_LIBOBJS $1.$ac_objext\"",
+ "])",
+ "",
+ "# Like AC_REPLACE_FUNCS, except that the module name goes",
+ "# into {macro_prefix}_LIBOBJS instead of into LIBOBJS.",
+ "AC_DEFUN([{macro_prefix}_REPLACE_FUNCS], [",
+ " m4_foreach_w([gl_NAME], [$1], [AC_LIBSOURCES(gl_NAME[.c])])dnl",
+ " AC_CHECK_FUNCS([$1], , [{macro_prefix}_LIBOBJ($ac_func)])",
+ "])",
+ "",
+ "# Like AC_LIBSOURCES, except the directory where the source file is",
+ "# expected is derived from the gnulib-tool parameterization,",
+ "# and alloca is special cased (for the alloca-opt module).",
+ "# We could also entirely rely on EXTRA_lib..._SOURCES.",
+ "AC_DEFUN([{macro_prefix}_LIBSOURCES], [",
+ " m4_foreach([_gl_NAME], [$1], [",
+ " m4_if(_gl_NAME, [alloca.c], [], [",
+ " m4_define([{macro_prefix}_LIBSOURCES_DIR], [{source_base}])",
+ " m4_append([{macro_prefix}_LIBSOURCES_LIST], _gl_NAME, [ ])",
+ " ])",
+ " ])",
+ "])",
+)
- def __init__(self, config, macro_prefix=None):
- """
- config: gnulib configuration
- macro_prefix: macro prefix; if None, consider configuration
- """
- super().__init__(config=config, macro_prefix=macro_prefix)
-
-
- def __iter__(self):
- # Check the presence of files that are mentioned as AC_LIBSOURCES
- # arguments. The check is performed only when autoconf is run from the
- # directory where the configure.ac resides; if it is run from a different
- # directory, the check is skipped.
- for line in InitMacroFooterGenerator._TEMPLATE:
- yield line.format(macro_prefix=self.macro_prefix)
-
-
-
-class InitMacroDoneGenerator(InitMacroGenerator):
- """few statements AFTER the gl_INIT macro"""
- _TEMPLATE = (
- "",
- "# Like AC_LIBOBJ, except that the module name goes",
- "# into {macro_prefix}_LIBOBJS instead of into LIBOBJS.",
- "AC_DEFUN([{macro_prefix}_LIBOBJ], [",
- " AS_LITERAL_IF([$1], [{macro_prefix}_LIBSOURCES([$1.c])])dnl",
- " {macro_prefix}_LIBOBJS=\"${macro_prefix}_LIBOBJS $1.$ac_objext\"",
- "])",
- "",
- "# Like AC_REPLACE_FUNCS, except that the module name goes",
- "# into {macro_prefix}_LIBOBJS instead of into LIBOBJS.",
- "AC_DEFUN([{macro_prefix}_REPLACE_FUNCS], [",
- " m4_foreach_w([gl_NAME], [$1], [AC_LIBSOURCES(gl_NAME[.c])])dnl",
- " AC_CHECK_FUNCS([$1], , [{macro_prefix}_LIBOBJ($ac_func)])",
- "])",
- "",
- "# Like AC_LIBSOURCES, except the directory where the source file is",
- "# expected is derived from the gnulib-tool parameterization,",
- "# and alloca is special cased (for the alloca-opt module).",
- "# We could also entirely rely on EXTRA_lib..._SOURCES.",
- "AC_DEFUN([{macro_prefix}_LIBSOURCES], [",
- " m4_foreach([_gl_NAME], [$1], [",
- " m4_if(_gl_NAME, [alloca.c], [], [",
- " m4_define([{macro_prefix}_LIBSOURCES_DIR], [{source_base}])",
- " m4_append([{macro_prefix}_LIBSOURCES_LIST], _gl_NAME, [ ])",
- " ])",
- " ])",
- "])",
- )
+def init_macro_done(config, **override):
+ """
+ Generate few statements after the gl_INIT macro.
+ [macro_prefix] the prefix of the macros 'gl_EARLY' and 'gl_INIT'
+ """
+ _type_assert("config", config, _BaseConfig)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
- def __init__(self, config, source_base=None, macro_prefix=None):
- if source_base is None:
- source_base = config.source_base
- _type_assert("source_base", source_base, str)
- super().__init__(config=config, macro_prefix=macro_prefix)
- self.__source_base = source_base
+ for line in __INIT_MACRO_DONE:
+ yield line.format(**config)
- @property
- def source_base(self):
- """directory relative to ROOT where source code is placed; defaults to 'lib'"""
- return self.__source_base
+__COMMAND_LINE_PATHS = (
+ ("libname", lambda k, v, d: f"--lib={v}"),
+ ("source_base", lambda k, v, d: f"--source_base={v}"),
+ ("m4_base", lambda k, v, d: f"--m4-base={v}"),
+ ("po_base", lambda k, v, d: f"--po-base={v}" if k in d else None),
+ ("doc_base", lambda k, v, d: f"--doc-base={v}"),
+ ("tests_base", lambda k, v, d: f"--tests-base={v}"),
+ ("auxdir", lambda k, v, d: f"--aux-dir={v}"),
+)
+__COMMAND_LINE_TESTS = (
+ ("tests", lambda v: "--with-tests" if v else None),
+ ("cxx_tests", lambda v: "--with-c++-tests" if v else None),
+ ("longrunning_tests", lambda v: "--with-longrunning-tests" if v else None),
+ ("privileged_tests", lambda v: "--with-privileged-tests" if v else None),
+ ("unportable_tests", lambda v: "--with-unportable-tests" if v else None),
+ ("all_tests", lambda v: "--with-all-tests" if v else None),
+)
+__COMMAND_LINE_MISC = (
+ ("conditionals", lambda k, v, d: ("--no", "--")[v] + "conditional-dependencies"),
+ ("libtool", lambda k, v, d: ("--no", "--")[v] + "libtool"),
+ ("macro_prefix", lambda k, v, d: f"--macro-prefix={v}"),
+ ("gnumake", lambda k, v, d: "--gnu-make" if v else None),
+ ("makefile_name", lambda k, v, d: f"--makefile-name={v}"),
+ ("po_domain", lambda k, v, d: f"--po-domain={v}" if k in d else None),
+ ("witness_c_macro", lambda k, v, d: f"--witness-c-macro={v}" if k in d else None),
+ ("vc_files", lambda k, v, d: ("--no", "--")[v] + "vc-files" if k in d else None),
+)
- def __iter__(self):
- for line in InitMacroDoneGenerator._TEMPLATE:
- yield line.format(source_base=self.__source_base, macro_prefix=self.macro_prefix)
+def command_line(config, explicit, **override):
+ """Generate gnulib command-line invocation."""
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("explicit", explicit, _ITERABLES)
+
+ yield "gnulib-tool --import"
+ for path in config.overrides:
+ yield f"--local-dir={path}"
+ for (key, hook) in __COMMAND_LINE_PATHS:
+ value = config[key]
+ option = hook(key, value, explicit)
+ if option is not None:
+ yield option
+ for (key, hook) in __COMMAND_LINE_TESTS:
+ value = config[key]
+ option = hook(value)
+ if option is not None:
+ yield option
+ for module in config.avoids:
+ yield "--avoid={module.name}"
+ if config.licenses in _LGPL:
+ lgpl = _LGPL[config.licenses]
+ if lgpl != "yes":
+ yield f"--lgpl={lgpl}"
+ else:
+ yield "--lgpl"
+ for (key, hook) in __COMMAND_LINE_MISC:
+ value = config[key]
+ option = hook(key, value, explicit)
+ if option is not None:
+ yield option
+ for module in sorted(config.modules):
+ yield "{}".format(module)
-class CommandLineGenerator(BaseGenerator):
- """gnulib command-line invocation generator"""
- _TESTS = {
- "tests": "tests",
- "obsolete": "obsolete",
- "cxx_tests": "c++-tests",
- "longrunning_tests": "longrunning-tests",
- "privileged_tests": "privileged-tests",
- "unportable_tests": "unportable-tests",
- }
+__MAKEFILE_PKGDATA = _re.compile(r"^pkgdata_DATA\s+\=")
+__MAKEFILE_SUBDIRS = _re.compile(r"lib/.*/.*\.c", _re.S)
+__MAKEFILE_LDFLAGS = _re.compile(r"^lib_LDFLAGS\s*\+\=.*?$", _re.S)
+__MAKEFILE_LIBNAME = _re.compile(r"lib_([A-Z][A-Z]*)", _re.S)
+__MAKEFILE_GNUMAKE = _re.compile(r"^if (.*?)$", _re.S)
- def __init__(self, config, explicit):
- _type_assert("config", config, _BaseConfig)
- _type_assert("explicit", explicit, _ITERABLES)
- super().__init__()
- self.__config = config
- self.__explicit = explicit
-
-
- def __iter__(self):
- config = self.__config
- explicit = self.__explicit
- yield "gnulib-tool --import"
- for path in config.overrides:
- yield "--local-dir={}".format(path)
- yield "--lib={}".format(config.libname)
- yield "--source-base={}".format(config.source_base)
- yield "--m4-base={}".format(config.m4_base)
- if "po_base" in explicit:
- yield "--po-base={}".format(config.po_base)
- yield "--doc-base={}".format(config.doc_base)
- yield "--tests-base={}".format(config.tests_base)
- yield "--aux-dir={}".format(config.auxdir)
- for (key, value) in CommandLineGenerator._TESTS.items():
- if config[key]:
- yield "--with-{}".format(value)
- if config.all_tests:
- yield "--with-all-tests"
- for module in config.avoids:
- yield "--avoid={}".format(module)
- if config.licenses in _LGPL:
- lgpl = _LGPL[config.licenses]
- yield "--lgpl={}".format(lgpl) if lgpl != "yes" else "--lgpl"
- if config.gnumake:
- yield "--gnu-make"
- if "makefile_name" in explicit:
- yield "--makefile-name={}".format(config.makefile_name)
- yield "--{}conditional-dependencies".format("" if config.conditionals else "no-")
- yield "--{}libtool".format("" if config.libtool else "no-")
- yield "--macro-prefix={}".format(config.macro_prefix)
- if "po_domain" in explicit:
- yield "--po-domain={}".format(config.po_domain)
- if "witness_c_macro" in explicit:
- yield "--witness-c-macro={}".format(config.witness_c_macro)
- if "vc_files" in explicit:
- yield "--{}vc-files".format("" if config.vc_files else "no-")
- for module in sorted(config.modules):
- yield "{}".format(module)
-
-
-
-class LibMakefileGenerator(BaseGenerator):
- """library Makefile.am generator"""
- _LDFLAGS = _re.compile(r"^lib_LDFLAGS\s*\+\=.*?$", _re.S)
- _LIBNAME = _re.compile(r"lib_([A-Z][A-Z]*)", _re.S)
- _GNUMAKE = _re.compile(r"^if (.*?)$", _re.S)
-
-
- def __init__(self, path, config, explicit, database, mkedits, testing):
- _type_assert("path", path, str)
- _type_assert("config", config, _BaseConfig)
- _type_assert("explicit", explicit, _ITERABLES)
- _type_assert("database", database, _Database)
- _type_assert("mkedits", mkedits, _ITERABLES)
- _type_assert("testing", testing, bool)
- super().__init__()
- self.__config = config
- self.__explicit = explicit
- self.__database = database
- self.__path = path
- self.__mkedits = mkedits
- self.__testing = testing
-
-
- def __iter__(self):
- date = _datetime.now()
- config = self.__config
- explicit = self.__explicit
- testing = self.__testing
- database = self.__database
-
- gnumake = config.gnumake
- libtool = config.libtool
- kwargs = {
- "libname": config.libname,
- "macro_prefix": config.macro_prefix,
- "libext": "la" if libtool else "a",
- "perhaps_LT": "LT" if libtool else "",
- }
- assign = "+=" if gnumake or "makefile_name" in explicit else "="
- eliminate_LDFLAGS = True if libtool else False
-
- # When creating a package for testing: Attempt to provoke failures,
- # especially link errors, already during "make" rather than during
- # "make check", because "make check" is not possible in a cross-compiling
- # situation. Turn check_PROGRAMS into noinst_PROGRAMS.
- transform_check_PROGRAMS = True if testing else False
-
- yield "## DO NOT EDIT! GENERATED AUTOMATICALLY!"
- yield "## Process this file with automake to produce Makefile.in."
- yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
- for line in _DISCLAIMER:
- yield line
+def _lib_makefile_callback(conditionals, gnumake):
- # The maximum line length (excluding the terminating newline) of any file
- # that is to be preprocessed by config.status is 3070. config.status uses
- # awk, and the HP-UX 11.00 awk fails if a line has length >= 3071;
- # similarly, the IRIX 6.5 awk fails if a line has length >= 3072.
- actioncmd = " ".join(CommandLineGenerator(config, explicit))
- if len(actioncmd) <= 3000:
- yield "# Reproduce by: {}".format(actioncmd)
+ def _automake_conditional(module, conditional, unconditional, macro_prefix):
yield ""
+ yield "if {}".format(module.conditional_name(macro_prefix))
+ yield conditional
+ yield "endif"
+ yield unconditional
- def _snippet():
- lines = []
-
- def _common_conditional(module, conditional, unconditional):
- yield ""
- yield "if {}".format(module.conditional_name(config.macro_prefix))
- yield conditional
- yield "endif"
- yield unconditional
-
- def _common_unconditional(module, conditional, unconditional):
- yield ""
- yield conditional
- yield unconditional
-
- def _gnumake_conditional(module, conditional, unconditional):
- yield "ifeq (,$(OMIT_GNULIB_MODULE_{}))".format(module.name)
- yield ""
- yield "ifneq (,$({}))".format(module.conditional_name(config.macro_prefix))
- yield LibMakefileGenerator._GNUMAKE.sub("ifneq (,$(\\1))", conditional)
- yield "endif"
- yield "endif"
- yield LibMakefileGenerator._GNUMAKE.sub("ifneq (,$(\\1))", unconditional)
-
- def _gnumake_unconditional(module, conditional, unconditional):
- yield ""
- yield LibMakefileGenerator._GNUMAKE.sub("ifneq (,$(\\1))", conditional)
- yield LibMakefileGenerator._GNUMAKE.sub("ifneq (,$(\\1))", unconditional)
-
- uses_subdirs = False
- process = (
- (_common_unconditional, _gnumake_unconditional),
- (_common_conditional, _gnumake_conditional),
- )[config.conditionals][gnumake]
- for module in database.main_modules:
- if module.test:
- continue
- conditional = module.conditional_automake_snippet
- conditional = conditional.replace("lib_LIBRARIES", "lib%_LIBRARIES")
- conditional = conditional.replace("lib_LTLIBRARIES", "lib%_LTLIBRARIES")
- if eliminate_LDFLAGS:
- conditional = LibMakefileGenerator._LDFLAGS.sub("", conditional)
- conditional = LibMakefileGenerator._LIBNAME.sub("{libname}_{libext}_\\1".format(**kwargs), conditional)
- conditional = conditional.replace("lib%_LIBRARIES", "lib_LIBRARIES")
- conditional = conditional.replace("lib%_LTLIBRARIES", "lib_LTLIBRARIES")
- if transform_check_PROGRAMS:
- conditional = conditional.replace("check_PROGRAMS", "noinst_PROGRAMS")
- conditional = conditional.replace(r"${gl_include_guard_prefix}", config.include_guard_prefix)
- unconditional = module.unconditional_automake_snippet.format(auxdir=config.auxdir)
- unconditional = LibMakefileGenerator._LIBNAME.sub("{libname}_{libext}_\\1".format(**kwargs), unconditional)
- if (conditional + unconditional).strip():
- lines.append("## begin gnulib module {}".format(module.name))
- if module.name == "alloca":
- lines.append("{libname}_{libext}_LIBADD += @{perhaps_LT}ALLOCA@".format(**kwargs))
- lines.append("{libname}_{libext}_DEPENDENCIES += @{perhaps_LT}ALLOCA@".format(**kwargs))
- lines += list(process(module, conditional, unconditional))
- lines.append("## end gnulib module {}".format(module.name))
- lines.append("")
- return (uses_subdirs, lines)
-
- (uses_subdirs, overall_snippet) = _snippet()
- if "makefile_name" not in explicit:
- # If there are source files in subdirectories, prevent collision of the
- # object files (example: hash.c and libxml/hash.c).
- yield "AUTOMAKE_OPTIONS = 1.9.6 gnits{}".format(" subdir-objects" if uses_subdirs else "")
+ def _automake_unconditional(module, conditional, unconditional, macro_prefix):
yield ""
- if "makefile_name" not in explicit:
- yield "SUBDIRS ="
- yield "noinst_HEADERS ="
- yield "noinst_LIBRARIES ="
- yield "noinst_LTLIBRARIES ="
- # Automake versions < 1.11.4 create an empty pkgdatadir at
- # installation time if you specify pkgdata_DATA to empty.
- # See automake bugs #10997 and #11030:
- # * http://debbugs.gnu.org/10997
- # * http://debbugs.gnu.org/11030
- # So we need this workaround.
- if {line for line in overall_snippet if line.startswith()}:
- yield "pkgdata_DATA ="
- yield "EXTRA_DIST ="
- yield "BUILT_SOURCES ="
- yield "SUFFIXES ="
- yield "MOSTLYCLEANFILES {} core *.stackdump".format(assign)
- if "makefile_name" not in explicit:
- yield "MOSTLYCLEANDIRS ="
- yield "CLEANFILES ="
- yield "DISTCLEANFILES ="
- yield "MAINTAINERCLEANFILES ="
-
- if gnumake:
- yield "# Start of GNU Make output."
- self.__autoconf = "autoconf"
- self.__configure_ac = "configure.ac"
- cmdargs = (self.__autoconf, "-t", "AC_SUBST:$1 = @$1@", self.__configure_ac)
- with _sp.Popen(cmdargs, stdout=_sp.PIPE, stderr=_sp.PIPE) as process:
- (stdout, stderr) = process.communicate()
- stdout = stdout.decode("UTF-8")
- stderr = stderr.decode("UTF-8")
- if process.returncode == 0:
- for line in sorted(stdout.splitlines()):
- yield line
- else:
- yield "== gnulib-tool GNU Make output failed as follows =="
- for line in stderr.splitlines():
- yield "# stderr: {}".format(line)
- yield "# End of GNU Make output."
- else:
- yield "# No GNU Make output."
-
- for (directory, key, value) in self.__mkedits:
- if key and _os.path.join(directory, "Makefile.am") == self.__path:
- yield f"{key} += {value}"
-
- cppflags = "".join((
- " -D{}=1".format(config.witness_c_macro) if "witness_c_macro" in explicit else "",
- " -DGNULIB_STRICT_CHECKING=1" if testing else "",
- ))
- if "makefile_name" not in explicit:
- yield ""
- yield "AM_CPPFLAGS ={}".format(cppflags)
- yield "AM_CFLAGS ="
- elif "".join(cppflags):
- yield ""
- yield "AM_CPPFLAGS +={}".format(cppflags)
+ yield conditional
+ yield unconditional
+
+ def _gnumake_conditional(module, conditional, unconditional, macro_prefix):
+ yield "ifeq (,$(OMIT_GNULIB_MODULE_{}))".format(module.name)
yield ""
+ yield "ifneq (,$({}))".format(module.conditional_name(macro_prefix))
+ yield __MAKEFILE_GNUMAKE.sub("ifneq (,$(\\1))", conditional)
+ yield "endif"
+ yield "endif"
+ yield __MAKEFILE_GNUMAKE.sub("ifneq (,$(\\1))", unconditional)
- snippet = "\n".join(overall_snippet)
- if "makefile_name" in explicit:
- makefile = _os.path.join(config.source_base, "Makefile.am")
- if _os.path.exists(makefile):
- with _codecs.open(makefile, "rb", "UTF-8") as stream:
- snippet += ("\n" + stream.read())
- # One of the snippets or the user's Makefile.am already specifies an
- # installation location for the library. Don't confuse automake by saying
- # it should not be installed.
- # By default, the generated library should not be installed.
- regex = "^[a-zA-Z0-9_]*_{perhaps_LT}LIBRARIES\\s*\\+?\\=\\s*{libname}\\.{libext}$"
- pattern = _re.compile(regex.format(**kwargs), _re.S)
- if not pattern.findall(snippet):
- yield "noinst_{perhaps_LT}LIBRARIES += {libname}.{libext}".format(**kwargs)
+ def _gnumake_unconditional(module, conditional, unconditional, macro_prefix):
+ yield ""
+ yield __MAKEFILE_GNUMAKE.sub("ifneq (,$(\\1))", conditional)
+ yield __MAKEFILE_GNUMAKE.sub("ifneq (,$(\\1))", unconditional)
+ callbacks = (
+ (_automake_unconditional, _gnumake_unconditional),
+ (_automake_conditional, _gnumake_conditional),
+ )
+ return callbacks[conditionals][gnumake]
+
+
+def lib_makefile(path, config, explicit, database, modules, mkedits, testing, **override):
+ """Generate library Makefile.am file."""
+ _type_assert("path", path, str)
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("explicit", explicit, _ITERABLES)
+ _type_assert("database", database, _Database)
+ _type_assert("modules", modules, _ITERABLES)
+ _type_assert("mkedits", mkedits, _ITERABLES)
+ _type_assert("testing", testing, bool)
+
+ date = _datetime.now()
+ kwargs = {
+ "libname": config.libname,
+ "macro_prefix": config.macro_prefix,
+ "libext": "la" if config.libtool else "a",
+ "perhaps_LT": "LT" if config.libtool else "",
+ }
+ assign = "+=" if config.gnumake or "makefile_name" in explicit else "="
+ eliminate_LDFLAGS = True if config.libtool else False
+
+ # When creating a package for testing: Attempt to provoke failures,
+ # especially link errors, already during "make" rather than during
+ # "make check", because "make check" is not possible in a cross-compiling
+ # situation. Turn check_PROGRAMS into noinst_PROGRAMS.
+ transform_check_PROGRAMS = True if testing else False
+
+ yield "## DO NOT EDIT! GENERATED AUTOMATICALLY!"
+ yield "## Process this file with automake to produce Makefile.in."
+ yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
+ for line in __DISCLAIMER[1:]:
+ yield line
+ yield ""
+
+ # The maximum line length (excluding the terminating newline) of any file
+ # that is to be preprocessed by config.status is 3070. config.status uses
+ # awk, and the HP-UX 11.00 awk fails if a line has length >= 3071;
+ # similarly, the IRIX 6.5 awk fails if a line has length >= 3072.
+ actioncmd = " ".join(command_line(config, explicit))
+ if len(actioncmd) <= 3000:
+ yield "# Reproduce by: {}".format(actioncmd)
+ yield ""
+
+ callback = _lib_makefile_callback(config.conditionals, config.gnumake)
+ def _snippet():
+ lines = []
+ subdirs = False
+ for module in database.main_modules:
+ if module.test:
+ continue
+ conditional = module.conditional_automake_snippet
+ conditional = conditional.replace("lib_LIBRARIES", "lib%_LIBRARIES")
+ conditional = conditional.replace("lib_LTLIBRARIES", "lib%_LTLIBRARIES")
+ if eliminate_LDFLAGS:
+ conditional = __MAKEFILE_LDFLAGS.sub("", conditional)
+ conditional = __MAKEFILE_LIBNAME.sub("{libname}_{libext}_\\1".format(**kwargs), conditional)
+ conditional = conditional.replace("lib%_LIBRARIES", "lib_LIBRARIES")
+ conditional = conditional.replace("lib%_LTLIBRARIES", "lib_LTLIBRARIES")
+ if transform_check_PROGRAMS:
+ conditional = conditional.replace("check_PROGRAMS", "noinst_PROGRAMS")
+ conditional = conditional.replace(r"${gl_include_guard_prefix}", config.include_guard_prefix)
+ unconditional = module.unconditional_automake_snippet.format(auxdir=config.auxdir)
+ unconditional = __MAKEFILE_LIBNAME.sub("{libname}_{libext}_\\1".format(**kwargs), unconditional)
+ if (conditional + unconditional).strip():
+ lines.append("## begin gnulib module {}".format(module.name))
+ if module.name == "alloca":
+ lines.append("{libname}_{libext}_LIBADD += @{perhaps_LT}ALLOCA@".format(**kwargs))
+ lines.append("{libname}_{libext}_DEPENDENCIES += @{perhaps_LT}ALLOCA@".format(**kwargs))
+ lines += list(callback(module, conditional, unconditional, config.macro_prefix))
+ lines.append("## end gnulib module {}".format(module.name))
+ lines.append("")
+ subdirs |= any(__MAKEFILE_SUBDIRS.match(file) for file in module.files)
+ return (subdirs, lines)
+
+ (subdirs, lines) = _snippet()
+ if "makefile_name" not in explicit:
+ # If there are source files in subdirectories, prevent collision of the
+ # object files (example: hash.c and libxml/hash.c).
+ yield "AUTOMAKE_OPTIONS = 1.9.6 gnits{}".format(" subdir-objects" if subdirs else "")
+ yield ""
+ if "makefile_name" not in explicit:
+ yield "SUBDIRS ="
+ yield "noinst_HEADERS ="
+ yield "noinst_LIBRARIES ="
+ yield "noinst_LTLIBRARIES ="
+ # Automake versions < 1.11.4 create an empty pkgdatadir at
+ # installation time if you specify pkgdata_DATA to empty.
+ # See automake bugs #10997 and #11030:
+ # * http://debbugs.gnu.org/10997
+ # * http://debbugs.gnu.org/11030
+ # So we need this workaround.
+ if __MAKEFILE_PKGDATA.match("\n".join(lines)):
+ yield "pkgdata_DATA ="
+ yield "EXTRA_DIST ="
+ yield "BUILT_SOURCES ="
+ yield "SUFFIXES ="
+ yield "MOSTLYCLEANFILES {} core *.stackdump".format(assign)
+ if "makefile_name" not in explicit:
+ yield "MOSTLYCLEANDIRS ="
+ yield "CLEANFILES ="
+ yield "DISTCLEANFILES ="
+ yield "MAINTAINERCLEANFILES ="
+
+ if config.gnumake:
+ yield "# Start of GNU Make output."
+ autoconf = "autoconf"
+ cmdargs = (autoconf, "-t", "AC_SUBST:$1 = @$1@", config.ac_file)
+ with _sp.Popen(cmdargs, stdout=_sp.PIPE, stderr=_sp.PIPE) as process:
+ (stdout, stderr) = process.communicate()
+ stdout = stdout.decode("UTF-8")
+ stderr = stderr.decode("UTF-8")
+ if process.returncode == 0:
+ for line in sorted(stdout.splitlines()):
+ yield line
+ else:
+ yield "== gnulib-tool GNU Make output failed as follows =="
+ for line in stderr.splitlines():
+ yield "# stderr: {}".format(line)
+ yield "# End of GNU Make output."
+ else:
+ yield "# No GNU Make output."
+
+ for (directory, key, value) in mkedits:
+ if key and _os.path.join(directory, "Makefile.am") == path:
+ del (directory, key, value)
+ yield f"{key} += {value}"
+
+ cppflags = "".join((
+ " -D{}=1".format(config.witness_c_macro) if "witness_c_macro" in explicit else "",
+ " -DGNULIB_STRICT_CHECKING=1" if testing else "",
+ ))
+ if "makefile_name" not in explicit:
yield ""
- yield "{libname}_{libext}_SOURCES =".format(**kwargs)
- # Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
- # automake during its analysis looks for $(LIBOBJS), not for @LIBOBJS@.
- yield "{libname}_{libext}_LIBADD = $({macro_prefix}_{perhaps_LT}LIBOBJS)".format(**kwargs)
- yield "{libname}_{libext}_DEPENDENCIES = $({macro_prefix}_{perhaps_LT}LIBOBJS)".format(**kwargs)
- yield "EXTRA_{libname}_{libext}_SOURCES =".format(**kwargs)
- if libtool:
- yield "{libname}_{libext}_LDFLAGS = $(AM_LDFLAGS)".format(**kwargs)
- yield "{libname}_{libext}_LDFLAGS += -no-undefined".format(**kwargs)
- # Synthesize an ${libname}_${libext}_LDFLAGS augmentation by combining
- # the link dependencies of all modules.
- def _directives(modules):
- directives = (module.link_directive for module in sorted(modules))
- for directive in filter(lambda directive: directive.strip(), directives):
- index = directive.find("when linking with libtool")
- if index != -1:
- directive = directive[:index].strip(" ")
- yield directive
- for directive in _directives(database.main_modules):
- yield ("{libname}_{libext}_LDFLAGS += {directive}".format(directive=directive, **kwargs))
+ yield "AM_CPPFLAGS ={}".format(cppflags)
+ yield "AM_CFLAGS ="
+ elif "".join(cppflags):
yield ""
-
- if "po_base" in explicit:
- yield "AM_CPPFLAGS += -DDEFAULT_TEXT_DOMAIN=\\\"{}-gnulib\\\"".format(config.po_domain)
- yield ""
-
- for line in overall_snippet:
- yield line.replace("$(top_srcdir)/build-aux/", _os.path.join("$(top_srcdir)", config.auxdir))
+ yield "AM_CPPFLAGS +={}".format(cppflags)
+ yield ""
+
+ snippet = "\n".join(lines)
+ if "makefile_name" in explicit:
+ makefile = _os.path.join(config.source_base, "Makefile.am")
+ if _os.path.exists(makefile):
+ with _codecs.open(makefile, "rb", "UTF-8") as stream:
+ snippet += ("\n" + stream.read())
+ # One of the snippets or the user's Makefile.am already specifies an
+ # installation location for the library. Don't confuse automake by saying
+ # it should not be installed.
+ # By default, the generated library should not be installed.
+ regex = "^[a-zA-Z0-9_]*_{perhaps_LT}LIBRARIES\\s*\\+?\\=\\s*{libname}\\.{libext}$"
+ pattern = _re.compile(regex.format(**kwargs), _re.S)
+ if not pattern.findall(snippet):
+ yield "noinst_{perhaps_LT}LIBRARIES += {libname}.{libext}".format(**kwargs)
+
+ yield ""
+ yield "{libname}_{libext}_SOURCES =".format(**kwargs)
+ # Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
+ # automake during its analysis looks for $(LIBOBJS), not for @LIBOBJS@.
+ yield "{libname}_{libext}_LIBADD = $({macro_prefix}_{perhaps_LT}LIBOBJS)".format(**kwargs)
+ yield "{libname}_{libext}_DEPENDENCIES = $({macro_prefix}_{perhaps_LT}LIBOBJS)".format(**kwargs)
+ yield "EXTRA_{libname}_{libext}_SOURCES =".format(**kwargs)
+ if config.libtool:
+ yield "{libname}_{libext}_LDFLAGS = $(AM_LDFLAGS)".format(**kwargs)
+ yield "{libname}_{libext}_LDFLAGS += -no-undefined".format(**kwargs)
+ # Synthesize an ${libname}_${libext}_LDFLAGS augmentation by combining
+ # the link dependencies of all modules.
+ def _directives(modules):
+ directives = (module.link_directive for module in sorted(modules))
+ for directive in filter(lambda directive: directive.strip(), directives):
+ index = directive.find("when linking with libtool")
+ if index != -1:
+ directive = directive[:index].strip(" ")
+ yield directive
+ for directive in _directives(database.main_modules):
+ yield "{libname}_{libext}_LDFLAGS += {directive}".format(directive=directive, **kwargs)
+ yield ""
+
+ if "po_base" in explicit:
+ yield "AM_CPPFLAGS += -DDEFAULT_TEXT_DOMAIN=\\\"{}-gnulib\\\"".format(config.po_domain)
yield ""
- yield "mostlyclean-local: mostlyclean-generic"
- yield "\t@for dir in '' $(MOSTLYCLEANDIRS); do \\"
- yield "\t if test -n \"$$dir\" && test -d $$dir; then \\"
- yield "\t echo \"rmdir $$dir\"; rmdir $$dir; \\"
- yield "\t fi; \\"
- yield "\tdone; \\"
- yield "\t:"
-
-
-
-class GnulibCacheGenerator(BaseGenerator):
- """gnulib-cache.m4 generator"""
- _OPTIONS = (
- ("obsolete", "gl_WITH_OBSOLETE"),
- ("cxx_tests", "gl_WITH_CXX_TESTS"),
- ("longrunning", "gl_WITH_LONGRUNNING_TESTS"),
- ("privileged", "gl_WITH_PRIVILEGED_TESTS"),
- )
+ for line in lines:
+ src = "$(top_srcdir)/build-aux/"
+ dst = _os.path.join("$(top_srcdir)", config.auxdir)
+ yield line.replace(src, dst)
+ yield ""
+ yield "mostlyclean-local: mostlyclean-generic"
+ yield "\t@for dir in '' $(MOSTLYCLEANDIRS); do \\"
+ yield "\t if test -n \"$$dir\" && test -d $$dir; then \\"
+ yield "\t echo \"rmdir $$dir\"; rmdir $$dir; \\"
+ yield "\t fi; \\"
+ yield "\tdone; \\"
+ yield "\t:"
- def __init__(self, config):
- _type_assert("config", config, _BaseConfig)
- super().__init__()
- self.__config = config
+def _tests_makefile_callback(gnumake):
- def __iter__(self):
- date = _datetime.now()
- config = self.__config
- yield "## DO NOT EDIT! GENERATED AUTOMATICALLY!"
- yield "## Process this file with automake to produce Makefile.in."
- yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
- for line in _DISCLAIMER:
- yield line
- yield "#"
- yield "# This file represents the specification of how gnulib-tool is used."
- yield "# It acts as a cache: It is written and read by gnulib-tool."
- yield "# In projects that use version control, this file is meant to be put under"
- yield "# version control, like the configure.ac and various Makefile.am files."
- yield ""
+ def _automake(module, snippet):
yield ""
- yield "# Specification in the form of a command-line invocation:"
- yield "gl_LOCAL_DIR([$relative_local_gnulib_path])"
- yield "gl_MODULES(["
- for module in sorted(config.modules):
- yield " {}".format(module)
- yield "])"
- for key in ("obsolete", "cxx_tests", "longrunning_tests", "privileged_tests", "unportable_tests"):
- if config[key]:
- yield "gl_WITH_{}".format(key.upper())
- if config.all_tests:
- yield "gl_WITH_ALL_TESTS"
- yield "gl_AVOID([{}])".format(" ".join(sorted(config.avoids)))
- yield "gl_SOURCE_BASE([{}])".format(config.source_base)
- yield "gl_M4_BASE([{}])".format(config.m4_base)
- yield "gl_PO_BASE([{}])".format(config.po_base)
- yield "gl_DOC_BASE([{}])".format(config.doc_base)
- yield "gl_TESTS_BASE([{}])".format(config.tests_base)
- if config.tests:
- yield "gl_WITH_TESTS"
- yield "gl_LIB([{}])".format(config.libname)
- if config.licenses in _LGPL:
- lgpl = _LGPL[config.licenses]
- yield "gl_LGPL([{}])".format(lgpl) if lgpl != "yes" else "gl_LGPL"
- yield "gl_MAKEFILE_NAME([{}])".format(config.makefile_name)
- if config.conditionals:
- yield "gl_CONDITIONAL_DEPENDENCIES"
- if config.libtool:
- yield "gl_LIBTOOL"
- yield "gl_MACRO_PREFIX([{}])".format(config.macro_prefix)
- yield "gl_PO_DOMAIN([{}])".format(config.po_domain)
- yield "gl_WITNESS_C_MACRO([{}])".format(config.witness_c_macro)
- if config.vc_files:
- yield "gl_VC_FILES([{}])".format(" ".join(sorted(config.vc_files)))
-
-
-
-class GnulibCompGenerator(BaseGenerator):
- """gnulib-comp.m4 generator"""
- def __init__(self, config, explicit, database, macro_prefix=None):
- _type_assert("config", config, _BaseConfig)
- _type_assert("explicit", explicit, _ITERABLES)
- _type_assert("database", database, _Database)
- if macro_prefix is None:
- macro_prefix = config.macro_prefix
- _type_assert("macro_prefix", macro_prefix, str)
- super().__init__()
- self.__config = config
- self.__explicit = explicit
- self.__database = database
- self.__macro_prefix = macro_prefix
- self.__uses_subdirs = True
-
-
- def __iter__(self):
- config = self.__config
- explicit = self.__explicit
- database = self.__database
- main_modules = database.main_modules
- test_modules = database.test_modules
- macro_prefix = self.__macro_prefix
-
- date = _datetime.now()
- yield "# DO NOT EDIT! GENERATED AUTOMATICALLY!"
- yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
- iterable = super().__iter__()
- try:
- next(iterable)
- except StopIteration:
- pass
- for line in iterable:
- yield line
+ yield snippet
- yield "#"
- yield "# This file represents the compiled summary of the specification in"
- yield "# gnulib-cache.m4. It lists the computed macro invocations that need"
- yield "# to be invoked from configure.ac."
- yield "# In projects that use version control, this file can be treated like"
- yield "# other built files."
- yield ""
+ def _gnumake(module, snippet):
+ yield "ifeq (,$(OMIT_GNULIB_MODULE_{}))".format(module.name)
yield ""
- yield "# This macro should be invoked from {}, in the section".format(config.ac_file)
- yield "# \"Checks for programs\", right after AC_PROG_CC, and certainly before"
- yield "# any checks for libraries, header files, types and library functions."
- yield "AC_DEFUN([{}_EARLY],".format(config.macro_prefix)
- yield "["
- yield " m4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace"
- yield " m4_pattern_allow([^gl_ES$])dnl a valid locale name"
- yield " m4_pattern_allow([^gl_LIBOBJS$])dnl a variable"
- yield " m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable"
- yield ""
- yield " # Pre-early section."
- if "externsions" not in (module.name for module in database.final_modules):
- yield " AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])"
- yield " AC_REQUIRE([gl_PROG_AR_RANLIB])"
- yield ""
- if not config.gnumake and self.__uses_subdirs:
- yield " AC_REQUIRE([AM_PROG_CC_C_O])"
- for module in database.final_modules:
- yield " # Code from module {}:".format(module.name)
- lines = module.early_autoconf_snippet.split("\n")
- for line in filter(lambda line: line.strip(), lines):
- yield " {}".format(line)
- yield "])"
+ yield snippet
+ yield "endif"
+
+ return _gnumake if gnumake else _automake
+
+def tests_makefile(path, config, explicit, database, modules, mkedits, testing):
+ """Generate tests Makefile.am file."""
+ _type_assert("path", path, str)
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("explicit", explicit, _ITERABLES)
+ _type_assert("database", database, _Database)
+ _type_assert("modules", modules, _ITERABLES)
+ _type_assert("mkedits", mkedits, _ITERABLES)
+ _type_assert("testing", testing, bool)
+
+ if testing and not config.single_configure:
+ modules = sorted(filter(lambda module: module.test, modules))
+
+ date = _datetime.now()
+ tests_base = config.tests_base
+ source_base = config.source_base
+ m4_base = config.m4_base
+ macro_prefix = config.macro_prefix
+ witness_c_macro = config.witness_c_macro
+ tests_base_inverse = "/".join(".." for _ in config.tests_base.split(_os.path.sep))
+ (libname, libext) = (config.libname, "la" if config.libtool else "a")
+ kwargs = {
+ "libname": config.libname,
+ "macro_prefix": config.macro_prefix,
+ "libext": "la" if config.libtool else "a",
+ "perhaps_LT": "LT" if config.libtool else "",
+ }
+ assign = "+=" if config.gnumake or "makefile_name" in explicit else "="
+ eliminate_LDFLAGS = True if config.libtool else False
+
+ # When creating a package for testing: Attempt to provoke failures,
+ # especially link errors, already during "make" rather than during
+ # "make check", because "make check" is not possible in a cross-compiling
+ # situation. Turn check_PROGRAMS into noinst_PROGRAMS.
+ transform_check_PROGRAMS = True if testing else False
+
+ yield "## DO NOT EDIT! GENERATED AUTOMATICALLY!"
+ yield "## Process this file with automake to produce Makefile.in."
+ yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
+ for line in __DISCLAIMER[1:]:
+ yield line
+ yield ""
+
+ callback = _tests_makefile_callback(config.gnumake)
+ def _snippet():
+ main = []
+ longrunning = []
+ subdirs = False
+ for module in modules:
+ lines = []
+ snippet = module.automake_snippet
+ snippet = snippet.replace("lib_LIBRARIES", "lib%_LIBRARIES")
+ snippet = snippet.replace("lib_LTLIBRARIES", "lib%_LTLIBRARIES")
+ if eliminate_LDFLAGS:
+ snippet = __MAKEFILE_LDFLAGS.sub("", snippet)
+ snippet = __MAKEFILE_LIBNAME.sub("libtests_a_\\1", snippet)
+ snippet = snippet.replace("lib%_LIBRARIES", "lib_LIBRARIES")
+ snippet = snippet.replace("lib%_LTLIBRARIES", "lib_LTLIBRARIES")
+ if transform_check_PROGRAMS:
+ snippet = snippet.replace("check_PROGRAMS", "noinst_PROGRAMS")
+ snippet = snippet.replace(r"${gl_include_guard_prefix}", config.include_guard_prefix)
+ if database.libtests and module.name == "alloca":
+ lines += ["libtests_a_LIBADD += @ALLOCA@"]
+ lines += ["libtests_a_DEPENDENCIES += @ALLOCA@"]
+ subdirs |= any(__MAKEFILE_SUBDIRS.match(file) for file in module.files)
+ if snippet.strip():
+ lines.append("## begin gnulib module {}".format(module.name))
+ lines += list(callback(module, snippet))
+ lines.append("## end gnulib module {}".format(module.name))
+ lines.append("")
+ if module.longrunning_test:
+ longrunning += lines
+ else:
+ main += lines
+ lines = (main + longrunning)
+ return (subdirs, lines)
+
+ (subdirs, lines) = _snippet()
+
+ # Generate dependencies here, since it eases the debugging of test failures.
+ # If there are source files in subdirectories, prevent collision of the
+ # object files (example: hash.c and libxml/hash.c).
+ subdir_options = " subdir-objects" if subdirs else ""
+ yield f"AUTOMAKE_OPTIONS = 1.9.6 foreign{subdir_options}"
+ yield ""
+ if testing and not single_configure:
+ yield f"ACLOCAL_AMFLAGS = -I {tests_base_inverse}/{m4_base}"
yield ""
- yield "# This macro should be invoked from {}, in the section".format(config.ac_file)
- yield "# \"Check for header files, types and library functions\"."
- yield "AC_DEFUN([{}_INIT],".format(macro_prefix)
- yield "["
- if config.libtool:
- yield " AM_CONDITIONAL([GL_COND_LIBTOOL], [true])"
- yield " gl_cond_libtool=true"
- else:
- yield " AM_CONDITIONAL([GL_COND_LIBTOOL], [false])"
- yield " gl_cond_libtool=false"
- yield " gl_libdeps="
- yield " gl_ltlibdeps="
- yield " gl_m4_base='{}'".format(config.m4_base)
- for line in InitMacroHeaderGenerator(config, macro_prefix):
- yield line
- yield " gl_source_base='{}'".format(config.source_base)
- if "witness_c_macro" in explicit:
- yield " m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [{}])".format(config.witness_c_macro)
- for line in AutoconfMultisnippetGenerator(config, database, main_modules, True, False, True, macro_prefix):
- yield line
- if "witness_c_macro" in explicit:
- yield " m4_popdef([gl_MODULE_INDICATOR_CONDITION])"
- yield " # End of code from modules"
- for line in InitMacroFooterGenerator(config, macro_prefix):
- yield line
- yield " gltests_libdeps="
- yield " gltests_ltlibdeps="
- for line in InitMacroHeaderGenerator(config, (macro_prefix + "tests")):
- yield line
- yield " gl_source_base='{}'".format(config.tests_base)
- # Define a tests witness macro that depends on the package.
- # PACKAGE is defined by AM_INIT_AUTOMAKE, PACKAGE_TARNAME is defined by AC_INIT.
- # See <http://lists.gnu.org/archive/html/automake/2009-05/msg00145.html>.
- yield "changequote(,)dnl"
- yield "".join((
- " {}tests_WITNESS=IN_`".format(macro_prefix),
- "echo \"${PACKAGE-$PACKAGE_TARNAME}\"",
- " | ",
- "LC_ALL=C tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- " | ",
- "LC_ALL=C sed -e 's/[^A-Z0-9_]/_/g'",
- "`_GNULIB_TESTS",
- ))
- yield "changequote([, ])dnl"
- yield " AC_SUBST([{}tests_WITNESS])".format(macro_prefix)
- yield " gl_module_indicator_condition=${}tests_WITNESS".format(macro_prefix)
- yield " m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [$gl_module_indicator_condition])"
- for line in AutoconfMultisnippetGenerator(config, database, test_modules, True, True, True, macro_prefix):
- yield line
- yield " m4_popdef([gl_MODULE_INDICATOR_CONDITION])"
- for line in InitMacroFooterGenerator(config, (macro_prefix + "tests")):
- yield line
- # _LIBDEPS and _LTLIBDEPS variables are not needed if this library is
- # created using libtool, because libtool already handles the dependencies.
- if not config.libtool:
- libname = config.libname.upper()
- yield " {}_LIBDEPS=\"$gl_libdeps\"".format(libname)
- yield " AC_SUBST([{}_LIBDEPS])".format(libname)
- yield " {}_LTLIBDEPS=\"$gl_ltlibdeps\"".format(libname)
- yield " AC_SUBST([{}_LTLIBDEPS])".format(libname)
- if database.libtests:
- yield " LIBTESTS_LIBDEPS=\"$gltests_libdeps\""
- yield " AC_SUBST([LIBTESTS_LIBDEPS])"
- yield "])"
- for line in InitMacroDoneGenerator(config, source_base=config.source_base, macro_prefix=macro_prefix):
- yield line
- for line in InitMacroDoneGenerator(config, source_base=config.tests_base, macro_prefix=(macro_prefix + "tests")):
- yield line
+ # Nothing is being added to SUBDIRS; nevertheless the existence of this
+ # variable is needed to avoid an error from automake:
+ # "AM_GNU_GETTEXT used but SUBDIRS not defined"
+ yield "SUBDIRS = ."
+ yield "TESTS ="
+ yield "XFAIL_TESTS ="
+ yield "TESTS_ENVIRONMENT ="
+ yield "noinst_PROGRAMS ="
+ if not testing:
+ yield "check_PROGRAMS ="
+ yield "EXTRA_PROGRAMS ="
+ yield "noinst_HEADERS ="
+ yield "noinst_LIBRARIES ="
+ if database.libtests:
+ if testing:
+ yield "noinst_LIBRARIES += libtests.a"
+ else:
+ yield "check_LIBRARIES = libtests.a"
+
+ # Automake versions < 1.11.4 create an empty pkgdatadir at
+ # installation time if you specify pkgdata_DATA to empty.
+ # See automake bugs #10997 and #11030:
+ # * http://debbugs.gnu.org/10997
+ # * http://debbugs.gnu.org/11030
+ # So we need this workaround.
+ if __MAKEFILE_PKGDATA.match("\n".join(lines)):
+ yield "pkgdata_DATA ="
+
+ yield "EXTRA_DIST ="
+ yield "BUILT_SOURCES ="
+ yield "SUFFIXES ="
+ yield "MOSTLYCLEANFILES = core *.stackdump"
+ yield "MOSTLYCLEANDIRS ="
+ yield "CLEANFILES ="
+ yield "DISTCLEANFILES ="
+ yield "MAINTAINERCLEANFILES ="
+
+ # Execute edits that apply to the Makefile.am being generated.
+ for (directory, key, value) in mkedits:
+ if key and _os.path.join(directory, "Makefile.am") == path:
+ del (directory, key, value)
+ yield f"{key} += {value}"
+
+ yield ""
+ yield "AM_CPPFLAGS = \\"
+ if testing:
+ yield " -DGNULIB_STRICT_CHECKING=1 \\"
+ if "witness_c_macro" in explicit:
+ yield " -D{witness_c_macro}=1 \\"
+ yield " -D@{witness_c_macro}@=1 \\"
+ yield f" -I. -I$(srcdir) \\"
+ yield f" -I{tests_base_inverse} -I$(srcdir)/{tests_base_inverse} \\"
+ yield f" -I{tests_base_inverse}/{source_base} -I$(srcdir)/{tests_base_inverse}/{source_base}"
+ yield f""
+
+ # All test programs need to be linked with libtests.a.
+ # It needs to be passed to the linker before ${libname}.${libext}, since
+ # the tests-related modules depend on the main modules.
+ # It also needs to be passed to the linker after ${libname}.${libext}
+ # because the latter might contain incomplete modules (such as the 'error'
+ # module whose dependency to 'progname' is voluntarily omitted).
+ # The LIBTESTS_LIBDEPS can be passed to the linker once or twice, it does
+ # not matter.
+ local_ldadd_before = " libtests.a" if database.libtests else ""
+ local_ldadd_after = " libtests.a $(LIBTESTS_LIBDEPS)" if database.libtests else ""
+ yield f"LDADD ={local_ldadd_before} {tests_base_inverse}/{source_base}/{libname}.{libext}{local_ldadd_after}"
+ yield ""
+
+ if database.libtests:
+ yield "libtests_a_SOURCES ="
+ # Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
+ # automake during its analysis looks for $(LIBOBJS), not for @LIBOBJS@.
+ yield f"libtests_a_LIBADD = $({macro_prefix}tests_LIBOBJS)"
+ yield f"libtests_a_DEPENDENCIES = $({macro_prefix}tests_LIBOBJS)"
+ yield "EXTRA_libtests_a_SOURCES ="
+ # The circular dependency in LDADD requires this.
+ yield "AM_LIBTOOLFLAGS = --preserve-dup-deps"
yield ""
- yield "# This macro records the list of files which have been installed by"
- yield "# gnulib-tool and may be removed by future gnulib-tool invocations."
- yield "AC_DEFUN([{}_FILE_LIST], [".format(macro_prefix)
- for file in sorted(set(database.main_files + database.test_files)):
- yield " {}".format(file)
- yield "])"
+
+ # Many test scripts use ${EXEEXT} or ${srcdir}.
+ # EXEEXT is defined by AC_PROG_CC through autoconf.
+ # srcdir is defined by autoconf and automake.
+ yield "TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'"
+ yield ""
+
+ for line in lines:
+ src = "$(top_srcdir)/build-aux/"
+ dst = _os.path.join("$(top_srcdir)", config.auxdir)
+ yield line.replace(src, dst)
+ yield ""
+ yield "# Clean up after Solaris cc."
+ yield "clean-local:"
+ yield "\trm -rf SunWS_cache"
+ yield ""
+ yield "mostlyclean-local: mostlyclean-generic"
+ yield "\t@for dir in '' $(MOSTLYCLEANDIRS); do \\"
+ yield "\t if test -n \"$$dir\" && test -d $$dir; then \\"
+ yield "\t echo \"rmdir $$dir\"; rmdir $$dir; \\"
+ yield "\t fi; \\"
+ yield "\tdone; \\"
+ yield "\t:"
+
+
+
+__GNULIB_CACHE_OPTIONS = (
+ ("obsolete", "gl_WITH_OBSOLETE"),
+ ("cxx_tests", "gl_WITH_CXX_TESTS"),
+ ("longrunning", "gl_WITH_LONGRUNNING_TESTS"),
+ ("privileged", "gl_WITH_PRIVILEGED_TESTS"),
+)
+
+def gnulib_cache(config):
+ """
+ Generate gnulib-cache.m4 file.
+ """
+ _type_assert("config", config, _BaseConfig)
+
+ date = _datetime.now()
+ yield "## DO NOT EDIT! GENERATED AUTOMATICALLY!"
+ yield "## Process this file with automake to produce Makefile.in."
+ yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
+ for line in __DISCLAIMER:
+ yield line
+ yield "#"
+ yield "# This file represents the specification of how gnulib-tool is used."
+ yield "# It acts as a cache: It is written and read by gnulib-tool."
+ yield "# In projects that use version control, this file is meant to be put under"
+ yield "# version control, like the configure.ac and various Makefile.am files."
+ yield ""
+ yield ""
+ yield "# Specification in the form of a command-line invocation:"
+ yield "gl_LOCAL_DIR([$relative_local_gnulib_path])"
+ yield "gl_MODULES(["
+ for module in sorted(config.modules):
+ yield " {}".format(module)
+ yield "])"
+ for key in ("obsolete", "cxx_tests", "longrunning_tests", "privileged_tests", "unportable_tests"):
+ if config[key]:
+ yield "gl_WITH_{}".format(key.upper())
+ if config.all_tests:
+ yield "gl_WITH_ALL_TESTS"
+ yield "gl_AVOID([{}])".format(" ".join(sorted(config.avoids)))
+ yield "gl_SOURCE_BASE([{}])".format(config.source_base)
+ yield "gl_M4_BASE([{}])".format(config.m4_base)
+ yield "gl_PO_BASE([{}])".format(config.po_base)
+ yield "gl_DOC_BASE([{}])".format(config.doc_base)
+ yield "gl_TESTS_BASE([{}])".format(config.tests_base)
+ if config.tests:
+ yield "gl_WITH_TESTS"
+ yield "gl_LIB([{}])".format(config.libname)
+ if config.licenses in _LGPL:
+ lgpl = _LGPL[config.licenses]
+ yield "gl_LGPL([{}])".format(lgpl) if lgpl != "yes" else "gl_LGPL"
+ yield "gl_MAKEFILE_NAME([{}])".format(config.makefile_name)
+ if config.conditionals:
+ yield "gl_CONDITIONAL_DEPENDENCIES"
+ if config.libtool:
+ yield "gl_LIBTOOL"
+ yield "gl_MACRO_PREFIX([{}])".format(config.macro_prefix)
+ yield "gl_PO_DOMAIN([{}])".format(config.po_domain)
+ yield "gl_WITNESS_C_MACRO([{}])".format(config.witness_c_macro)
+ if config.vc_files:
+ yield "gl_VC_FILES([{}])".format(" ".join(sorted(config.vc_files)))
+
+
+
+def gnulib_comp(config, explicit, database, subdirs, **override):
+ """gnulib-comp.m4 generator"""
+ _type_assert("config", config, _BaseConfig)
+ _type_assert("explicit", explicit, _ITERABLES)
+ _type_assert("database", database, _Database)
+ config = _BaseConfig(**config)
+ for (key, value) in override.items():
+ config[key] = value
+ macro_prefix = config.macro_prefix
+ main_modules = database.main_modules
+ test_modules = database.test_modules
+
+ date = _datetime.now()
+ yield "# DO NOT EDIT! GENERATED AUTOMATICALLY!"
+ yield "# Copyright (C) 2002-{} Free Software Foundation, Inc.".format(date.year)
+ for line in __DISCLAIMER[1:]:
+ yield line
+
+ yield "#"
+ yield "# This file represents the compiled summary of the specification in"
+ yield "# gnulib-cache.m4. It lists the computed macro invocations that need"
+ yield "# to be invoked from configure.ac."
+ yield "# In projects that use version control, this file can be treated like"
+ yield "# other built files."
+ yield ""
+ yield ""
+ yield "# This macro should be invoked from {}, in the section".format(config.ac_file)
+ yield "# \"Checks for programs\", right after AC_PROG_CC, and certainly before"
+ yield "# any checks for libraries, header files, types and library functions."
+ yield "AC_DEFUN([{}_EARLY],".format(config.macro_prefix)
+ yield "["
+ yield " m4_pattern_forbid([^gl_[A-Z]])dnl the gnulib macro namespace"
+ yield " m4_pattern_allow([^gl_ES$])dnl a valid locale name"
+ yield " m4_pattern_allow([^gl_LIBOBJS$])dnl a variable"
+ yield " m4_pattern_allow([^gl_LTLIBOBJS$])dnl a variable"
+ yield ""
+ yield " # Pre-early section."
+ if "externsions" not in (module.name for module in database.final_modules):
+ yield " AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])"
+ yield " AC_REQUIRE([gl_PROG_AR_RANLIB])"
+ yield ""
+ if not config.gnumake and subdirs:
+ yield " AC_REQUIRE([AM_PROG_CC_C_O])"
+ for module in database.final_modules:
+ yield " # Code from module {}:".format(module.name)
+ lines = module.early_autoconf_snippet.split("\n")
+ for line in filter(lambda line: line.strip(), lines):
+ yield " {}".format(line)
+ yield "])"
+ yield ""
+ yield "# This macro should be invoked from {}, in the section".format(config.ac_file)
+ yield "# \"Check for header files, types and library functions\"."
+ yield "AC_DEFUN([{}_INIT],".format(macro_prefix)
+ yield "["
+ if config.libtool:
+ yield " AM_CONDITIONAL([GL_COND_LIBTOOL], [true])"
+ yield " gl_cond_libtool=true"
+ else:
+ yield " AM_CONDITIONAL([GL_COND_LIBTOOL], [false])"
+ yield " gl_cond_libtool=false"
+ yield " gl_libdeps="
+ yield " gl_ltlibdeps="
+ yield " gl_m4_base='{}'".format(config.m4_base)
+ for line in init_macro_header(config, macro_prefix=macro_prefix):
+ yield line
+ yield " gl_source_base='{}'".format(config.source_base)
+ if "witness_c_macro" in explicit:
+ yield " m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [{}])".format(config.witness_c_macro)
+ for line in autoconf_snippet_sequence(config, database, main_modules, True, False, True, macro_prefix=macro_prefix):
+ yield line
+ if "witness_c_macro" in explicit:
+ yield " m4_popdef([gl_MODULE_INDICATOR_CONDITION])"
+ yield " # End of code from modules"
+ for line in init_macro_footer(config, macro_prefix=macro_prefix):
+ yield line
+ yield " gltests_libdeps="
+ yield " gltests_ltlibdeps="
+ for line in init_macro_header(config, macro_prefix=(macro_prefix + "tests")):
+ yield line
+ yield " gl_source_base='{}'".format(config.tests_base)
+ # Define a tests witness macro that depends on the package.
+ # PACKAGE is defined by AM_INIT_AUTOMAKE, PACKAGE_TARNAME is defined by AC_INIT.
+ # See <http://lists.gnu.org/archive/html/automake/2009-05/msg00145.html>.
+ yield "changequote(,)dnl"
+ yield "".join((
+ " {}tests_WITNESS=IN_`".format(macro_prefix),
+ "echo \"${PACKAGE-$PACKAGE_TARNAME}\"",
+ " | ",
+ "LC_ALL=C tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ " | ",
+ "LC_ALL=C sed -e 's/[^A-Z0-9_]/_/g'",
+ "`_GNULIB_TESTS",
+ ))
+ yield "changequote([, ])dnl"
+ yield " AC_SUBST([{}tests_WITNESS])".format(macro_prefix)
+ yield " gl_module_indicator_condition=${}tests_WITNESS".format(macro_prefix)
+ yield " m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [$gl_module_indicator_condition])"
+ for line in autoconf_snippet_sequence(config, database, test_modules, True, True, True, macro_prefix=macro_prefix):
+ yield line
+ yield " m4_popdef([gl_MODULE_INDICATOR_CONDITION])"
+ for line in init_macro_footer(config, macro_prefix=(macro_prefix + "tests")):
+ yield line
+
+ # _LIBDEPS and _LTLIBDEPS variables are not needed if this library is
+ # created using libtool, because libtool already handles the dependencies.
+ if not config.libtool:
+ libname = config.libname.upper()
+ yield " {}_LIBDEPS=\"$gl_libdeps\"".format(libname)
+ yield " AC_SUBST([{}_LIBDEPS])".format(libname)
+ yield " {}_LTLIBDEPS=\"$gl_ltlibdeps\"".format(libname)
+ yield " AC_SUBST([{}_LTLIBDEPS])".format(libname)
+ if database.libtests:
+ yield " LIBTESTS_LIBDEPS=\"$gltests_libdeps\""
+ yield " AC_SUBST([LIBTESTS_LIBDEPS])"
+ yield "])"
+ for line in init_macro_done(config, source_base=config.source_base, macro_prefix=macro_prefix):
+ yield line
+ for line in init_macro_done(config, source_base=config.tests_base, macro_prefix=(macro_prefix + "tests")):
+ yield line
+ yield ""
+ yield "# This macro records the list of files which have been installed by"
+ yield "# gnulib-tool and may be removed by future gnulib-tool invocations."
+ yield "AC_DEFUN([{}_FILE_LIST], [".format(macro_prefix)
+ for file in sorted(set(database.main_files + database.test_files)):
+ yield " {}".format(file)
+ yield "])"
diff --git a/pygnulib/module.py b/pygnulib/module.py
index 6b029f536e..7e15427fe7 100644
--- a/pygnulib/module.py
+++ b/pygnulib/module.py
@@ -347,9 +347,9 @@ class BaseModule:
if self.test:
# *-tests module live in tests/, not lib/.
# Synthesize an EXTRA_DIST augmentation.
- test_files = {file for file in files if file.startswith("tests/")}
+ test_files = tuple(file[len("tests/"):] for file in files if file.startswith("tests/"))
if test_files:
- result += ("EXTRA_DIST += {}".format(" ".join(sorted(test_files))) + "\n")
+ result += ("EXTRA_DIST += {}".format(" ".join(test_files)) + "\n")
return result
snippet = self.conditional_automake_snippet
lib_SOURCES = False
@@ -376,7 +376,7 @@ class BaseModule:
lib_files = tuple(file[len("lib/"):] for file in all_files if file.startswith("lib/"))
extra_files = tuple(file for file in lib_files if file not in mentioned_files)
if extra_files:
- result += ("EXTRA_DIST += {}".format(" ".join(sorted(extra_files))) + "\n")
+ result += ("EXTRA_DIST += {}".format(" ".join(extra_files)) + "\n")
# Synthesize also an EXTRA_lib_SOURCES augmentation.
# This is necessary so that automake can generate the right list of
@@ -406,7 +406,7 @@ class BaseModule:
@property
def automake_snippet(self):
"""full automake snippet (conditional + unconditional parts)"""
- return self.conditional_automake_snippet + self.unconditional_automake_snippet
+ return "\n".join((self.conditional_automake_snippet, self.unconditional_automake_snippet))
@property
@@ -706,7 +706,7 @@ class TransitiveClosure:
pass # ignore non-existent tests
for (dependency, condition) in demander.dependencies:
dependency = lookup(dependency)
- if config.gnumake and condition.startswith("if "):
+ if config.gnumake and condition and condition.startswith("if "):
# A module whose Makefile.am snippet contains a reference to an
# automake conditional. If we were to use it conditionally, we
# would get an error
@@ -903,7 +903,7 @@ class Database:
test_files = set()
for file in _files(test_modules):
if file.startswith("lib/"):
- file = ("lib=tests/" + file[len("lib/"):])
+ file = ("tests=lib/" + file[len("lib/"):])
test_files.add(file)
self.__libtests = libtests
diff --git a/pygnulib/tools.py b/pygnulib/tools.py
new file mode 100644
index 0000000000..a169393c0a
--- /dev/null
+++ b/pygnulib/tools.py
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+# encoding: UTF-8
+"""gnulib command-line tools"""
+
+
+
+import os as _os
+import subprocess as _sp
+
+
+from .error import type_assert as _type_assert
+
+
+
+class _PipeMeta(type):
+ __INSTANCE = None
+ def __call__(cls, *args, **kwargs):
+ if _PipeMeta.__INSTANCE is None:
+ _PipeMeta.__INSTANCE = super(_PipeMeta, cls).__call__(*args, **kwargs)
+ return _PipeMeta.__INSTANCE
+
+
+class Pipe(metaclass=_PipeMeta):
+ """pipe handle singleton"""
+ pass
+
+
+
+class Executable:
+ """command-line program or script"""
+ def __init__(self, name, path=None, encoding=None):
+ _type_assert("name", name, str)
+ if path is not None:
+ _type_assert("path", path, str)
+ if encoding is not None:
+ _type_assert("encoding", encoding, str)
+ self.__name = name
+ self.__path = path
+ self.__encoding = encoding
+
+
+ @property
+ def name(self):
+ """executable name"""
+ return self.__name
+
+
+ @property
+ def path(self):
+ """executable path"""
+ return self.__path if self.__path else self.name
+
+
+ def __call__(self, *args, **kwargs):
+ """
+ Invoke command-line tool with the given arguments.
+ Upon execution subprocess.Popen instance is returned.
+ """
+ args = ([self.path] + list(args))
+ for key in ("stdin", "stdout", "stderr"):
+ if isinstance(kwargs.get(key, Pipe()), Pipe):
+ kwargs[key] = _sp.PIPE
+ kwargs.setdefault("encoding", self.__encoding)
+ return _sp.Popen(args, **kwargs)
diff --git a/pygnulib/vfs.py b/pygnulib/vfs.py
index a0dc16fc3e..537cea2e98 100644
--- a/pygnulib/vfs.py
+++ b/pygnulib/vfs.py
@@ -56,10 +56,10 @@ class BaseVFS:
_type_assert("name", name, str)
parts = []
replaced = False
- path = _os.path.normpath(name)
- if _os.path.isabs(path):
+ name = _os.path.normpath(name)
+ if _os.path.isabs(name):
raise ValueError("name cannot be an absolute path")
- for part in path.split(_os.path.sep):
+ for part in name.split(_os.path.sep):
if part == "..":
parts += [part]
continue
@@ -67,8 +67,18 @@ class BaseVFS:
part = self.__table[part]
replaced = True
parts += [part]
- path = _os.path.sep.join(parts)
- return _os.path.normpath(path)
+ name = _os.path.sep.join(parts)
+ return _os.path.normpath(name)
+
+
+ def __setitem__(self, src, dst):
+ for name in (src, dst):
+ _type_assert("name", name, str)
+ if _os.path.isabs(name):
+ raise ValueError("name cannot be an absoule path")
+ src = _os.path.normpath(src)
+ dst = _os.path.normpath(dst)
+ self.__table[src] = dst
@property
@@ -291,7 +301,7 @@ class GnulibGitVFS(BaseVFS):
def __init__(self, prefix, **table):
super().__init__(prefix, **table)
- self.__cache = {}
+ self.__cache = {"dummy": _DummyModule()}
if not _os.path.exists(self.absolute):
raise FileNotFoundError(self.absolute)
if not _os.path.isdir(self.absolute):
@@ -307,10 +317,7 @@ class GnulibGitVFS(BaseVFS):
return self.__cache[name]
path = _os.path.join(self.absolute, self["modules"], name)
try:
- if name != "dummy":
- self.__cache[name] = _GnulibModule(path=path, name=name)
- else:
- self.__cache[name] = _DummyModule()
+ self.__cache[name] = _GnulibModule(path=path, name=name)
return self.__cache[name]
except FileNotFoundError:
raise _UnknownModuleError(name)