Files
RedBear-OS/local/recipes/dev/libtool/source/gnulib/pygnulib/GLEmiter.py
T

1253 lines
62 KiB
Python

# Copyright (C) 2002-2024 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from __future__ import annotations
#===============================================================================
# Define global imports
#===============================================================================
import os
import re
import subprocess as sp
from collections.abc import Callable
from .constants import (
UTILS,
joinpath,
lines_to_multiline,
combine_lines_matching,
substart,
relinverse,
)
from .GLInfo import GLInfo
from .GLConfig import GLConfig
from .GLModuleSystem import GLModule
from .GLModuleSystem import GLModuleTable
from .GLMakefileTable import GLMakefileTable
# Regular expressions used to convert Automake conditionals to GNU Make syntax.
# Each tuple is the arguments given to re.sub in the correct order.
_CONVERT_TO_GNU_MAKE = [
(re.compile(r'^if (.*)', re.MULTILINE), r'ifneq (,$(\1_CONDITION))'),
(re.compile(r'%reldir%/'), r''),
(re.compile(r'%reldir%'), r'.')
]
def _convert_to_gnu_make(snippet: str) -> str:
'''Convert a Automake snippet to GNU Make syntax.'''
if type(snippet) is not str:
raise TypeError(f'snippet must be a str, not {type(snippet).__name__}')
for regexp in _CONVERT_TO_GNU_MAKE:
snippet = re.sub(regexp[0], regexp[1], snippet)
return snippet
def _eliminate_NMD_from_line(line: str, automake_subdir: bool) -> str | None:
'''Eliminate occurrences of @NMD@ and @!NMD@ from the given line. The
modified line is returned or None if the line should be removed.
line is the current line in the snippet being operated on.
automake_subdir is a bool that is True if --automake-subdir is in use,
else False.'''
if automake_subdir:
clean = '@NMD@'
eliminate = '@!NMD@'
else:
clean = '@!NMD@'
eliminate = '@NMD@'
# Check if we should eliminate the line from the output.
if line.startswith(eliminate):
return None
# Check if we should clean the mark but keep the line.
if line.startswith(clean):
return line.replace(clean, '')
return line
def _eliminate_NMD(snippet: str, automake_subdir: bool) -> str:
'''Return the Automake snippet with occurrences of @NMD@ and @!NMD@
removed.
snippet is the Automake snippet being operated on.
automake_subdir is a bool that is True if --automake-subdir is in use,
else False.'''
result = []
for line in snippet.splitlines():
line = _eliminate_NMD_from_line(line, automake_subdir)
if line != None:
result.append(line)
return lines_to_multiline(result)
#===============================================================================
# Define GLEmiter class
#===============================================================================
class GLEmiter:
'''This class is used to emit the contents of necessary files.'''
info: GLInfo
config: GLConfig
def __init__(self, config: GLConfig) -> None:
'''Create GLEmiter instance.'''
self.info = GLInfo()
if type(config) is not GLConfig:
raise TypeError('config must be a GLConfig, not %s'
% type(config).__name__)
self.config = config
def __repr__(self) -> str:
'''x.__repr__() <==> repr(x)'''
result = '<pygnulib.GLEmiter %s>' % hex(id(self))
return result
def copyright_notice(self) -> str:
'''Emit a header for a generated file.'''
emit = '# %s' % self.info.copyright_range()
emit += '''
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception to the GNU General Public License,
# this file may be distributed as part of a program that
# contains a configuration script generated by Autoconf, under
# the same distribution terms as the rest of that program.
#
# Generated by gnulib-tool.\n'''
return emit
def shellvars_init(self, gentests: bool, base: str) -> str:
'''Emits some shell variable assignments.
gentests is a bool that is True if a tests Makefile.am is being
generated, False otherwise.
base is a string representing the base directory relative to the
top-level directory.'''
if type(gentests) is not bool:
raise TypeError(f'gentests must be a bool, not {type(gentests).__name__}')
if type(base) is not str:
raise TypeError(f'base must be a str, not {type(base).__name__}')
sourcebase = self.config['sourcebase']
testsbase = self.config['testsbase']
automake_subdir = self.config['automake_subdir']
automake_subdir_tests = self.config['automake_subdir_tests']
# Define the base directory, relative to the top-level directory.
emit = f' gl_source_base=\'{base}\'\n'
# Define the prefix for the file name of generated files.
if gentests and automake_subdir_tests:
# When tests share the same Makefile as the whole project, they
# share the same base prefix.
if base == testsbase:
emit += f' gl_source_base_prefix=\'$(top_build_prefix){sourcebase}/\'\n'
else:
emit += f' gl_source_base_prefix=\'$(top_build_prefix){base}/\'\n'
elif not gentests and automake_subdir:
emit += f' gl_source_base_prefix=\'$(top_build_prefix){base}/\'\n'
else:
emit += ' gl_source_base_prefix=\n'
return emit
def autoconfSnippet(self, module: GLModule, toplevel: bool, disable_libtool: bool,
disable_gettext: bool, replace_auxdir: bool, indentation: str) -> str:
'''Emit the autoconf snippet of a module.
GLConfig: include_guard_prefix.
module is a GLModule instance, which is processed.
toplevel is a bool variable, False means a subordinate use of pygnulib.
disable_libtool is a bool variable; it tells whether to disable libtool
handling even if it has been specified through the GLConfig class.
disable_gettext is a bool variable; it tells whether to disable
AM_GNU_GETTEXT invocations.
replace_auxdir is a bool variable; it tells whether to replace
'build-aux' directory in AC_CONFIG_FILES.
indentation is a string which contain spaces to prepend on each line.'''
if type(module) is not GLModule:
raise TypeError('module must be a GLModule, not %s'
% type(module).__name__)
if type(toplevel) is not bool:
raise TypeError('toplevel must be a bool, not %s'
% type(toplevel).__name__)
if type(disable_libtool) is not bool:
raise TypeError('disable_libtool must be a bool, not %s'
% type(disable_libtool).__name__)
if type(disable_gettext) is not bool:
raise TypeError('disable_gettext must be a bool, not %s'
% type(disable_gettext).__name__)
if type(indentation) is not str:
raise TypeError('indentation must be a string, not %s'
% type(indentation).__name__)
if not indentation.isspace():
raise ValueError('indentation must contain only whitespaces')
auxdir = self.config['auxdir']
libtool = self.config['libtool']
include_guard_prefix = self.config['include_guard_prefix']
emit = ''
if module.name in ['gnumakefile', 'maintainer-makefile']:
# These modules are meant to be used only in the top-level directory.
flag = toplevel
else: # if module.name not in ['gnumakefile', 'maintainer-makefile']
flag = True
if flag:
snippet = module.getAutoconfSnippet()
snippet = snippet.replace('${gl_include_guard_prefix}',
include_guard_prefix)
lines = [ f'{indentation}{line}'
for line in snippet.split('\n')
if line.strip() ]
snippet = lines_to_multiline(lines)
if disable_libtool:
snippet = snippet.replace('$gl_cond_libtool', 'false')
snippet = snippet.replace('gl_libdeps', 'gltests_libdeps')
snippet = snippet.replace('gl_ltlibdeps', 'gltests_ltlibdeps')
if disable_gettext:
snippet = snippet.replace('AM_GNU_GETTEXT([external])',
'dnl you must add AM_GNU_GETTEXT([external]) or similar to configure.ac.')
else:
# Don't indent AM_GNU_GETTEXT_VERSION line, as that confuses
# autopoint through at least GNU gettext version 0.18.2.
snippet = re.compile(r'^ *AM_GNU_GETTEXT_VERSION', re.M).sub(r'AM_GNU_GETTEXT_VERSION', snippet)
emit += snippet
if module.name == 'alloca' and libtool and not disable_libtool:
emit += 'changequote(,)dnl\n'
emit += "LTALLOCA=`echo \"$ALLOCA\" | sed -e 's/\\.[^.]* /.lo /g;s/\\.[^.]*$/.lo/'`\n"
emit += 'changequote([, ])dnl\n'
emit += 'AC_SUBST([LTALLOCA])'
if replace_auxdir:
regex = r'AC_CONFIG_FILES\(\[(.*)\:build-aux/(.*)\]\)'
repl = r'AC_CONFIG_FILES([\1:%s/\2])' % auxdir
pattern = re.compile(regex, re.M)
emit = pattern.sub(repl, emit)
lines = [ line
for line in emit.split('\n')
if line.strip() ]
emit = lines_to_multiline(lines)
return emit
def autoconfSnippets(self, modules: list[GLModule], referenceable_modules: list[GLModule],
moduletable: GLModuleTable, module_filter: Callable[[GLModule], bool], toplevel: bool,
disable_libtool: bool, disable_gettext: bool, replace_auxdir: bool) -> str:
'''Collect and emit the autoconf snippets of a set of modules.
GLConfig: conddeps.
basemodules argument represents list of modules; every module in this list
must be a GLModule instance; this list of modules is used to sort all
modules after they were processed.
modules argument represents list of modules; every module in this list must
be a GLModule instance.
referenceable_modules is the list of modules which may be referenced as
dependencies.
moduletable is a GLModuleTable instance, which contains necessary
information about dependencies of the modules.
module_filter is a function that accepts a GLModule and returns a bool describing
whether or not Autoconf snippets should be emitted for it.
toplevel is a bool variable, False means a subordinate use of pygnulib.
disable_libtool is a bool variable; it tells whether to disable libtool
handling even if it has been specified through the GLConfig class.
disable_gettext is a bool variable; it tells whether to disable
AM_GNU_GETTEXT invocations.
replace_auxdir is a bool variable; it tells whether to replace
'build-aux' directory in AC_CONFIG_FILES.'''
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
for module in referenceable_modules:
if type(module) is not GLModule:
raise TypeError('each referenceable module must be a GLModule instance')
if type(moduletable) is not GLModuleTable:
raise TypeError('moduletable must be a GLModuleTable, not %s'
% type(moduletable).__name__)
if not callable(module_filter):
raise TypeError('module_filter must be a function, not %s'
% type(module_filter).__name__)
if type(toplevel) is not bool:
raise TypeError('toplevel must be a bool, not %s'
% type(toplevel).__name__)
if type(disable_libtool) is not bool:
raise TypeError('disable_libtool must be a bool, not %s'
% type(disable_libtool).__name__)
if type(disable_gettext) is not bool:
raise TypeError('disable_gettext must be a bool, not %s'
% type(disable_gettext).__name__)
if type(replace_auxdir) is not bool:
raise TypeError('replace_auxdir must be a bool, not %s'
% type(replace_auxdir).__name__)
conddeps = self.config['conddeps']
macro_prefix = self.config['macro_prefix']
emit = ''
if not conddeps:
# Ignore the conditions, and enable all modules unconditionally.
for module in modules:
if module_filter(module):
emit += self.autoconfSnippet(module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, ' ')
else: # if conddeps
# Emit the autoconf code for the unconditional modules.
for module in modules:
if module_filter(module):
if not moduletable.isConditional(module):
emit += self.autoconfSnippet(module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, ' ')
# Initialize the shell variables indicating that the modules are enabled.
for module in modules:
if module_filter(module):
if moduletable.isConditional(module):
emit += ' %s=false\n' % module.getShellVar()
# Emit the autoconf code for the conditional modules, each in a separate
# function. This makes it possible to support cycles among conditional
# modules.
for module in modules:
if module_filter(module):
if moduletable.isConditional(module):
shellfunc = module.getShellFunc()
shellvar = module.getShellVar()
emit += ' %s ()\n' % shellfunc
emit += ' {\n'
emit += ' if $%s; then :; else\n' % shellvar
emit += self.autoconfSnippet(module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, ' ')
emit += ' %s=true\n' % shellvar
depmodules = module.getDependenciesWithoutConditions()
# Intersect dependencies with the modules list.
depmodules = sorted(set(depmodules).intersection(referenceable_modules))
for depmodule in depmodules:
if moduletable.isConditional(depmodule):
shellfunc = depmodule.getShellFunc()
condition = moduletable.getCondition(module, depmodule)
if condition != None and condition != True:
emit += ' if %s; then\n' % condition
emit += ' %s\n' % shellfunc
emit += ' fi\n'
else: # if condition == None or condition == True
emit += ' %s\n' % shellfunc
# if not moduletable.isConditional(depmodule)
else:
# The autoconf code for $dep has already been emitted above and
# therefore is already executed when this code is run.
pass
emit += ' fi\n'
emit += ' }\n'
# Emit the dependencies from the unconditional to the conditional modules.
for module in modules:
if module_filter(module):
if not moduletable.isConditional(module):
depmodules = module.getDependenciesWithoutConditions()
# Intersect dependencies with the modules list.
depmodules = sorted(set(depmodules).intersection(referenceable_modules))
for depmodule in depmodules:
if moduletable.isConditional(depmodule):
shellfunc = depmodule.getShellFunc()
condition = moduletable.getCondition(module, depmodule)
if condition != None and condition != True:
emit += ' if %s; then\n' % condition
emit += ' %s\n' % shellfunc
emit += ' fi\n'
else: # if condition == None or condition == True
emit += ' %s\n' % shellfunc
# if not moduletable.isConditional(depmodule)
else:
# The autoconf code for $dep has already been emitted above and
# therefore is already executed when this code is run.
pass
# Define the Automake conditionals.
emit += ' m4_pattern_allow([^%s_GNULIB_ENABLED_])\n' % macro_prefix
for module in modules:
if module_filter(module):
if moduletable.isConditional(module):
condname = module.getConditionalName()
shellvar = module.getShellVar()
emit += ' AM_CONDITIONAL([%s], [$%s])\n' % (condname, shellvar)
lines = [ line
for line in emit.split('\n')
if line.strip() ]
emit = lines_to_multiline(lines)
return emit
def preEarlyMacros(self, require: bool, indentation: str, modules: list[GLModule]) -> str:
'''Collect and emit the pre-early section.
require parameter can be True (AC_REQUIRE) or False (direct call).
indentation parameter is a string.
modules argument represents list of modules; every module in this list must
be a GLModule instance.'''
emit = '\n' + indentation + '# Pre-early section.\n'
# We need to call gl_USE_SYSTEM_EXTENSIONS before gl_PROG_AR_RANLIB.
# Doing AC_REQUIRE in configure-ac.early is not early enough.
if any(module.name == 'extensions' for module in modules):
if require:
emit += indentation + 'AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])\n'
else:
emit += indentation + 'gl_USE_SYSTEM_EXTENSIONS\n'
if require:
emit += indentation + 'AC_REQUIRE([gl_PROG_AR_RANLIB])\n'
else:
emit += indentation + 'gl_PROG_AR_RANLIB\n'
emit += '\n'
return emit
def po_Makevars(self) -> str:
'''Emit the contents of po/ makefile parameterization.
GLConfig: pobase, podomain.'''
pobase = self.config['pobase']
podomain = self.config['podomain']
emit = ''
emit += '## DO NOT EDIT! GENERATED AUTOMATICALLY!\n'
emit += '%s\n' % self.copyright_notice()
emit += '# Usually the message domain is the same as the package name.\n'
emit += "# But here it has a '-gnulib' suffix.\n"
emit += 'DOMAIN = %s-gnulib\n\n' % podomain
emit += '# These two variables depend on the location of this directory.\n'
emit += 'subdir = %s\n' % pobase
emit += 'top_builddir = %s\n' % relinverse(pobase)
emit += '''
# 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_lite: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\n'''
return emit
def po_POTFILES_in(self, files: list[str]) -> str:
'''Emit the file list to be passed to xgettext.
GLConfig: sourcebase.'''
sourcebase = self.config['sourcebase'] + os.path.sep
emit = ''
emit += '## DO NOT EDIT! GENERATED AUTOMATICALLY!\n'
emit += '%s\n' % self.copyright_notice()
emit += '# List of files which contain translatable strings.\n'
for file in files:
if file.startswith('lib/'):
emit += '%s\n' % substart('lib/', sourcebase, file)
return emit
def initmacro_start(self, macro_prefix_arg: str, gentests: bool) -> str:
'''Emit the first few statements of the gl_INIT macro.
macro_prefix_arg is the prefix of gl_EARLY and gl_INIT macros to use.
gentests is True if a tests Makefile.am is being generated, False
otherwise.'''
if type(macro_prefix_arg) is not str:
raise TypeError('macro_prefix_arg must be a string, not %s'
% type(macro_prefix_arg).__name__)
if type(gentests) is not bool:
raise TypeError('gentests must be a bool, not %s'
% type(gentests).__name__)
module_indicator_prefix = self.config.getModuleIndicatorPrefix()
emit = ''
# 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.
emit += ' m4_pushdef([AC_LIBOBJ], m4_defn([%s_LIBOBJ]))\n' % macro_prefix_arg
emit += ' m4_pushdef([AC_REPLACE_FUNCS], m4_defn([%s_REPLACE_FUNCS]))\n' % macro_prefix_arg
# 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.
emit += ' m4_pushdef([AC_LIBSOURCES], m4_defn([%s_LIBSOURCES]))\n' % macro_prefix_arg
# 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.
emit += ' m4_pushdef([%s_LIBSOURCES_LIST], [])\n' % macro_prefix_arg
emit += ' m4_pushdef([%s_LIBSOURCES_DIR], [])\n' % macro_prefix_arg
# Scope for m4 macros.
emit += ' m4_pushdef([GL_MACRO_PREFIX], [%s])\n' % macro_prefix_arg
# Scope the GNULIB_<modulename> variables.
emit += ' m4_pushdef([GL_MODULE_INDICATOR_PREFIX], [%s])\n' % module_indicator_prefix
emit += ' gl_COMMON\n'
if gentests:
emit += ' AC_REQUIRE([gl_CC_ALLOW_WARNINGS])\n'
emit += ' AC_REQUIRE([gl_CXX_ALLOW_WARNINGS])\n'
return emit
def initmacro_end(self, macro_prefix_arg: str, gentests: bool) -> str:
'''Emit the last few statements of the gl_INIT macro.
macro_prefix_arg is the prefix of gl_EARLY, gl_INIT macros to use.
gentests is a bool that is True if a tests Makefile.am is being
generated, False otherwise.'''
if type(macro_prefix_arg) is not str:
raise TypeError('macro_prefix_arg must be a string, not %s'
% type(macro_prefix_arg).__name__)
if type(gentests) is not bool:
raise TypeError('gentests must be a bool, not %s'
% type(gentests).__name__)
sourcebase = self.config['sourcebase']
testsbase = self.config['testsbase']
automake_subdir = self.config['automake_subdir']
automake_subdir_tests = self.config['automake_subdir_tests']
libtool = self.config['libtool']
emit = ''
# 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.
if automake_subdir and not gentests and sourcebase != '' and sourcebase != '.':
subdir = f'{sourcebase}/'
elif automake_subdir_tests and gentests and testsbase != '' and testsbase != '.':
subdir = f'{testsbase}/'
else:
subdir = ''
if libtool:
libobjdeps = f'{macro_prefix_arg}_libobjdeps="${macro_prefix_arg}_libobjdeps {subdir}$i_dir/\\$(DEPDIR)/$i_base.Plo"'
else:
libobjdeps = f'{macro_prefix_arg}_libobjdeps="${macro_prefix_arg}_libobjdeps {subdir}$i_dir/\\$(DEPDIR)/$i_base.Po"'
emit += fr''' m4_ifval({macro_prefix_arg}_LIBSOURCES_LIST, [
m4_syscmd([test ! -d ]m4_defn([{macro_prefix_arg}_LIBSOURCES_DIR])[ ||
for gl_file in ]{macro_prefix_arg}_LIBSOURCES_LIST[ ; do
if test ! -r ]m4_defn([{macro_prefix_arg}_LIBSOURCES_DIR])[/$gl_file ; then
echo "missing file ]m4_defn([{macro_prefix_arg}_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([GL_MODULE_INDICATOR_PREFIX])
m4_popdef([GL_MACRO_PREFIX])
m4_popdef([{macro_prefix_arg}_LIBSOURCES_DIR])
m4_popdef([{macro_prefix_arg}_LIBSOURCES_LIST])
m4_popdef([AC_LIBSOURCES])
m4_popdef([AC_REPLACE_FUNCS])
m4_popdef([AC_LIBOBJ])
AC_CONFIG_COMMANDS_PRE([
{macro_prefix_arg}_libobjs=
{macro_prefix_arg}_ltlibobjs=
{macro_prefix_arg}_libobjdeps=
if test -n "${macro_prefix_arg}_LIBOBJS"; then
# Remove the extension.
changequote(,)dnl
sed_drop_objext='s/\.o$//;s/\.obj$//'
sed_dirname1='s,//*,/,g'
sed_dirname2='s,\(.\)/$,\1,'
sed_dirname3='s,^[^/]*$,.,'
sed_dirname4='s,\(.\)/[^/]*$,\1,'
sed_basename1='s,.*/,,'
changequote([, ])dnl
for i in `for i in ${macro_prefix_arg}_LIBOBJS; do echo "$i"; done | sed -e "$sed_drop_objext" | sort | uniq`; do
{macro_prefix_arg}_libobjs="${macro_prefix_arg}_libobjs {subdir}$i.$ac_objext"
{macro_prefix_arg}_ltlibobjs="${macro_prefix_arg}_ltlibobjs {subdir}$i.lo"
i_dir=`echo "$i" | sed -e "$sed_dirname1" -e "$sed_dirname2" -e "$sed_dirname3" -e "$sed_dirname4"`
i_base=`echo "$i" | sed -e "$sed_basename1"`
{libobjdeps}
done
fi
AC_SUBST([{macro_prefix_arg}_LIBOBJS], [${macro_prefix_arg}_libobjs])
AC_SUBST([{macro_prefix_arg}_LTLIBOBJS], [${macro_prefix_arg}_ltlibobjs])
AC_SUBST([{macro_prefix_arg}_LIBOBJDEPS], [${macro_prefix_arg}_libobjdeps])
])
'''
return emit
def initmacro_done(self, macro_prefix_arg: str, sourcebase_arg: str) -> str:
'''Emit a few statements after the gl_INIT macro.
GLConfig: sourcebase.'''
if type(macro_prefix_arg) is not str:
raise TypeError('macro_prefix_arg must be a string, not %s'
% type(macro_prefix_arg).__name__)
if type(sourcebase_arg) is not str:
raise TypeError('sourcebase_arg must be a string, not %s'
% type(sourcebase_arg).__name__)
emit = ''
emit += '''\
# Like AC_LIBOBJ, except that the module name goes
# into %V1%_LIBOBJS instead of into LIBOBJS.
AC_DEFUN([%V1%_LIBOBJ], [
AS_LITERAL_IF([$1], [%V1%_LIBSOURCES([$1.c])])dnl
%V1%_LIBOBJS="$%V1%_LIBOBJS $1.$ac_objext"
])
# Like AC_REPLACE_FUNCS, except that the module name goes
# into %V1%_LIBOBJS instead of into LIBOBJS.
AC_DEFUN([%V1%_REPLACE_FUNCS], [
m4_foreach_w([gl_NAME], [$1], [AC_LIBSOURCES(gl_NAME[.c])])dnl
AC_CHECK_FUNCS([$1], , [%V1%_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([%V1%_LIBSOURCES], [
m4_foreach([_gl_NAME], [$1], [
m4_if(_gl_NAME, [alloca.c], [], [
m4_define([%V1%_LIBSOURCES_DIR], [%V2%])
m4_append([%V1%_LIBSOURCES_LIST], _gl_NAME, [ ])
])
])
])\n'''
emit = emit.replace('%V1%', macro_prefix_arg)
emit = emit.replace('%V2%', sourcebase_arg)
return emit
def lib_Makefile_am(self, destfile: str, modules: list[GLModule], moduletable: GLModuleTable,
makefiletable: GLMakefileTable, actioncmd: str, for_test: bool) -> str:
'''Emit the contents of the library Makefile. Returns it as a string.
GLConfig: localpath, sourcebase, libname, pobase, auxdir, makefile_name, libtool,
macro_prefix, podomain, conddeps, witness_c_macro.
destfile is a filename relative to destdir of Makefile being generated.
modules is a list of GLModule instances.
moduletable is a GLModuleTable instance.
makefiletable is a GLMakefileTable instance.
actioncmd is a string variable, which represents the actioncmd; it can be
an empty string e.g. when user wants to generate files for GLTestDir.
for_test is a bool variable; it must be set to True if creating a package
for testing, False otherwise.'''
if type(destfile) is not str:
raise TypeError('destfile must be a string, not %s'
% type(destfile).__name__)
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
if type(moduletable) is not GLModuleTable:
raise TypeError('moduletable must be a GLModuleTable, not %s'
% type(moduletable).__name__)
if type(makefiletable) is not GLMakefileTable:
raise TypeError('makefiletable must be a GLMakefileTable, not %s'
% type(makefiletable).__name__)
if type(actioncmd) is not str:
raise TypeError('actioncmd must be a string, not %s'
% type(actioncmd).__name__)
if type(for_test) is not bool:
raise TypeError('for_test must be a bool, not %s'
% type(for_test).__name__)
sourcebase = self.config['sourcebase']
libname = self.config['libname']
pobase = self.config['pobase']
auxdir = self.config['auxdir']
gnu_make = self.config['gnu_make']
makefile_name = self.config['makefile_name']
automake_subdir = self.config['automake_subdir']
libtool = self.config['libtool']
macro_prefix = self.config['macro_prefix']
podomain = self.config['podomain']
conddeps = self.config['conddeps']
witness_c_macro = self.config['witness_c_macro']
include_guard_prefix = self.config['include_guard_prefix']
module_indicator_prefix = self.config.getModuleIndicatorPrefix()
destfile = os.path.normpath(destfile)
emit = ''
# When using GNU make, or when creating an includable Makefile.am snippet,
# augment variables with += instead of assigning them.
if gnu_make or makefile_name:
assign = '+='
else: # if not makefile_name
assign = '='
if libtool:
libext = 'la'
perhapsLT = 'LT'
eliminate_LDFLAGS = False
else: # if not libtool
libext = 'a'
perhapsLT = ''
eliminate_LDFLAGS = True
if for_test:
# 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.
edit_check_PROGRAMS = True
else: # if not for_test
edit_check_PROGRAMS = False
emit += '## DO NOT EDIT! GENERATED AUTOMATICALLY!\n'
if not gnu_make:
emit += '## Process this file with automake to produce Makefile.in.\n'
emit += self.copyright_notice()
if actioncmd:
emit += '# Reproduce by:\n%s\n' % actioncmd
emit += '\n'
uses_subdirs = False
# Compute allsnippets variable.
allsnippets = ''
for module in modules:
if module.isNonTests():
# Get conditional snippet, edit it and save to amsnippet1.
amsnippet1 = module.getAutomakeSnippet_Conditional()
amsnippet1 = amsnippet1.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
if eliminate_LDFLAGS:
pattern = re.compile(r'^(lib_LDFLAGS[\t ]*\+=.*$\n)', re.M)
amsnippet1 = pattern.sub(r'', amsnippet1)
# Replace NMD, so as to remove redundant "$(MKDIR_P) '.'" invocations.
# The logic is similar to how we define gl_source_base_prefix.
amsnippet1 = _eliminate_NMD(amsnippet1, automake_subdir)
pattern = re.compile(r'lib_([A-Z]+)', re.M)
amsnippet1 = pattern.sub(r'%s_%s_\1' % (libname, libext),
amsnippet1)
amsnippet1 = amsnippet1.replace('$(GNULIB_', '$(' + module_indicator_prefix + '_GNULIB_')
amsnippet1 = amsnippet1.replace('lib%_LIBRARIES', 'lib_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib%_LTLIBRARIES', 'lib_LTLIBRARIES')
if edit_check_PROGRAMS:
amsnippet1 = amsnippet1.replace('check_PROGRAMS', 'noinst_PROGRAMS')
amsnippet1 = amsnippet1.replace('${gl_include_guard_prefix}',
include_guard_prefix)
if module.name == 'alloca':
amsnippet1 += '%s_%s_LIBADD += @%sALLOCA@\n' % (libname, libext, perhapsLT)
amsnippet1 += '%s_%s_DEPENDENCIES += @%sALLOCA@\n' % (libname, libext, perhapsLT)
amsnippet1 = combine_lines_matching(re.compile(r'%s_%s_SOURCES' % (libname, libext)),
amsnippet1)
# Get unconditional snippet, edit it and save to amsnippet2.
amsnippet2 = module.getAutomakeSnippet_Unconditional()
pattern = re.compile(r'lib_([A-Z]+)', re.M)
amsnippet2 = pattern.sub(r'%s_%s_\1' % (libname, libext),
amsnippet2)
amsnippet2 = amsnippet2.replace('$(GNULIB_',
'$(' + module_indicator_prefix + '_GNULIB_')
# Skip the contents if it's entirely empty.
if (amsnippet1 + amsnippet2).strip() != '':
allsnippets += '## begin gnulib module %s\n' % module.name
if gnu_make:
allsnippets += 'ifeq (,$(OMIT_GNULIB_MODULE_%s))\n' % module.name
allsnippets += '\n'
if conddeps:
if moduletable.isConditional(module):
name = module.getConditionalName()
if gnu_make:
allsnippets += 'ifneq (,$(%s_CONDITION))\n' % name
else:
allsnippets += 'if %s\n' % name
if gnu_make:
allsnippets += _convert_to_gnu_make(amsnippet1)
else:
allsnippets += amsnippet1
if conddeps:
if moduletable.isConditional(module):
allsnippets += 'endif\n'
if gnu_make:
allsnippets += _convert_to_gnu_make(amsnippet2)
else:
allsnippets += amsnippet2
if gnu_make:
allsnippets += 'endif\n'
allsnippets += '## end gnulib module %s\n\n' % module.name
# Test whether there are some source files in subdirectories.
for file in module.getFiles():
if (file.startswith('lib/')
and file.endswith('.c')
and file.count('/') > 1):
uses_subdirs = True
break
if not makefile_name:
subdir_options = ''
# If there are source files in subdirectories, prevent collision of the
# object files (example: hash.c and libxml/hash.c).
if uses_subdirs:
subdir_options = ' subdir-objects'
emit += 'AUTOMAKE_OPTIONS = 1.14 gnits%s\n' % subdir_options
emit += '\n'
if not makefile_name:
emit += 'SUBDIRS =\n'
emit += 'noinst_HEADERS =\n'
emit += 'noinst_LIBRARIES =\n'
emit += 'noinst_LTLIBRARIES =\n'
emit += 'pkgdata_DATA =\n'
emit += 'EXTRA_DIST =\n'
emit += 'BUILT_SOURCES =\n'
emit += 'SUFFIXES =\n'
emit += 'MOSTLYCLEANFILES %s core *.stackdump\n' % assign
if not makefile_name:
emit += 'MOSTLYCLEANDIRS =\n'
emit += 'CLEANFILES =\n'
emit += 'DISTCLEANFILES =\n'
emit += 'MAINTAINERCLEANFILES =\n'
if gnu_make:
emit += '# Start of GNU Make output.\n'
result = sp.run([UTILS['autoconf'], '-t', 'AC_SUBST:$1 = @$1@',
joinpath(self.config['destdir'], 'configure.ac')],
capture_output=True)
if result.returncode == 0:
# sort -u
emit += lines_to_multiline(sorted({ x.strip()
for x in result.stdout.decode(encoding='utf-8').splitlines() }))
else:
emit += '== gnulib-tool GNU Make output failed as follows ==\n'
emit += ['# stderr: ' + x + '\n' for x in
result.stderr.decode(encoding='utf-8').splitlines()]
emit += '# End of GNU Make output.\n'
else:
emit += '# No GNU Make output.\n'
# Execute edits that apply to the Makefile.am being generated.
for current_edit in range(0, makefiletable.count()):
dictionary = makefiletable[current_edit]
if 'var' in dictionary:
if destfile == joinpath(dictionary['dir'], 'Makefile.am'):
val = dictionary['val']
if dictionary['var'] == 'SUBDIRS' and dictionary['dotfirst']:
# The added subdirectory ${val} needs to be mentioned after '.'.
# Since we don't have '.' among SUBDIRS so far, add it now.
val = f'. {val}'
emit += '%s += %s\n' % (dictionary['var'], val)
del dictionary['var']
# Define two parts of cppflags variable.
cppflags_part1 = ''
if witness_c_macro:
cppflags_part1 = ' -D%s=1' % witness_c_macro
cppflags_part2 = ''
if for_test:
cppflags_part2 = ' -DGNULIB_STRICT_CHECKING=1'
cppflags = '%s%s' % (cppflags_part1, cppflags_part2)
if not makefile_name:
emit += '\n'
emit += 'AM_CPPFLAGS =%s\n' % cppflags
emit += 'AM_CFLAGS =\n'
else: # if makefile_name
if cppflags:
emit += '\n'
emit += 'AM_CPPFLAGS +=%s\n' % cppflags
emit += '\n'
# Test if 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.
# First test if allsnippets already specify an installation location.
lib_gets_installed = False
regex = r'^[a-zA-Z0-9_]*_%sLIBRARIES *\+{0,1}= *%s\.%s' % (perhapsLT, libname, libext)
pattern = re.compile(regex, re.M)
if pattern.findall(allsnippets):
lib_gets_installed = True
else:
# Then test if $sourcebase/Makefile.am (if it exists) specifies it.
if makefile_name:
path = joinpath(sourcebase, 'Makefile.am')
if os.path.isfile(path):
with open(path, mode='r', newline='\n', encoding='utf-8') as file:
data = file.read()
if pattern.findall(data):
lib_gets_installed = True
if not lib_gets_installed:
# By default, the generated library should not be installed.
emit += 'noinst_%sLIBRARIES += %s.%s\n' % (perhapsLT, libname, libext)
emit += '\n'
emit += '%s_%s_SOURCES =\n' % (libname, libext)
if not for_test:
emit += '%s_%s_CFLAGS = $(AM_CFLAGS) $(GL_CFLAG_GNULIB_WARNINGS)\n' % (libname, libext)
# Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
# automake during its analysis looks for $(LIBOBJS), not for @LIBOBJS@.
emit += '%s_%s_LIBADD = $(%s_%sLIBOBJS)\n' % (libname, libext, macro_prefix, perhapsLT)
emit += '%s_%s_DEPENDENCIES = $(%s_%sLIBOBJS)\n' % (libname, libext, macro_prefix, perhapsLT)
emit += 'EXTRA_%s_%s_SOURCES =\n' % (libname, libext)
if libtool:
emit += '%s_%s_LDFLAGS = $(AM_LDFLAGS)\n' % (libname, libext)
emit += '%s_%s_LDFLAGS += -no-undefined\n' % (libname, libext)
# Synthesize an ${libname}_${libext}_LDFLAGS augmentation by combining
# the link dependencies of all modules.
links = [ module.getLink()
for module in modules
if module.isNonTests() ]
lines = [ line
for link in links
for line in link.split('\n')
if line != '' ]
pattern = re.compile(r' when linking with libtool.*')
lines = [ pattern.sub(r'', line)
for line in lines ]
lines = sorted(set(lines))
for line in lines:
emit += '%s_%s_LDFLAGS += %s\n' % (libname, libext, line)
emit += '\n'
if pobase:
emit += 'AM_CPPFLAGS += -DDEFAULT_TEXT_DOMAIN=\\"%s-gnulib\\"\n' % podomain
emit += '\n'
allsnippets = allsnippets.replace('$(top_srcdir)/build-aux/',
'$(top_srcdir)/%s/' % auxdir)
emit += allsnippets
emit += '\n'
emit += 'mostlyclean-local: mostlyclean-generic\n'
emit += '\t@for dir in \'\' $(MOSTLYCLEANDIRS); do \\\n'
emit += '\t if test -n "$$dir" && test -d $$dir; then \\\n'
emit += '\t echo "rmdir $$dir"; rmdir $$dir; \\\n'
emit += '\t fi; \\\n'
emit += '\tdone; \\\n'
emit += '\t:\n'
# Emit rules to erase .Po and .Plo files for AC_LIBOBJ invocations.
# Extend the 'distclean' rule.
emit += 'distclean-local: distclean-gnulib-libobjs\n'
emit += 'distclean-gnulib-libobjs:\n'
emit += '\t-rm -f @%s_LIBOBJDEPS@\n' % (macro_prefix)
# Extend the 'maintainer-clean' rule.
emit += 'maintainer-clean-local: distclean-gnulib-libobjs\n'
return emit
def tests_Makefile_am(self, destfile: str, modules: list[GLModule], moduletable: GLModuleTable,
makefiletable: GLMakefileTable, witness_macro: str, for_test: bool) -> str:
'''Emit the contents of the tests Makefile. Returns it as a string.
GLConfig: localpath, modules, libname, auxdir, makefile_name, libtool,
sourcebase, m4base, testsbase, macro_prefix, witness_c_macro,
single_configure, libtests.
destfile is a filename relative to destdir of Makefile being generated.
witness_macro is a string which represents witness_c_macro with the suffix.
modules is a list of GLModule instances.
moduletable is a GLModuleTable instance.
makefiletable is a GLMakefileTable instance.
actioncmd is a string variable, which represents the actioncmd; it can be
an empty string e.g. when user wants to generate files for GLTestDir.
for_test is a bool variable; it must be set to True if creating a package
for testing, False otherwise.'''
if type(destfile) is not str:
raise TypeError('destfile must be a string, not %s'
% type(destfile).__name__)
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
if type(makefiletable) is not GLMakefileTable:
raise TypeError('makefiletable must be a GLMakefileTable, not %s'
% type(makefiletable).__name__)
if type(witness_macro) is not str:
raise TypeError('witness_macro must be a string, not %s'
% type(witness_macro).__name__)
if type(for_test) is not bool:
raise TypeError('for_test must be a bool, not %s'
% type(for_test).__name__)
auxdir = self.config['auxdir']
sourcebase = self.config['sourcebase']
libname = self.config['libname']
m4base = self.config['m4base']
testsbase = self.config['testsbase']
gnu_make = self.config['gnu_make']
libtool = self.config['libtool']
macro_prefix = self.config['macro_prefix']
conddeps = self.config['conddeps']
witness_c_macro = self.config['witness_c_macro']
include_guard_prefix = self.config['include_guard_prefix']
module_indicator_prefix = self.config.getModuleIndicatorPrefix()
libtests = self.config['libtests']
single_configure = self.config['single_configure']
emit = ''
if libtool:
libext = 'la'
eliminate_LDFLAGS = False
else: # if not libtool
libext = 'a'
eliminate_LDFLAGS = True
if for_test:
# 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.
edit_check_PROGRAMS = True
else: # if not for_test
edit_check_PROGRAMS = False
# Compute testsbase_inverse
testsbase_inverse = relinverse(testsbase)
# Begin the generation.
emit += '## DO NOT EDIT! GENERATED AUTOMATICALLY!\n'
emit += '## Process this file with automake to produce Makefile.in.\n'
emit += '%s\n' % self.copyright_notice()
uses_subdirs = False
main_snippets = ''
longrun_snippets = ''
for module in modules:
if for_test and not single_configure:
if module.repeatModuleInTests():
accept = True
else:
accept = module.isTests()
else: # if for_test and not single_configure
accept = True
if accept:
amsnippet1 = module.getAutomakeSnippet_Conditional()
amsnippet1 = amsnippet1.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
if eliminate_LDFLAGS:
pattern = re.compile(r'^(lib_LDFLAGS[\t ]*\+=.*$\n)', re.M)
amsnippet1 = pattern.sub(r'', amsnippet1)
# Replace NMD, so as to remove redundant "$(MKDIR_P) '.'" invocations.
# The logic is similar to how we define gl_source_base_prefix.
amsnippet1 = _eliminate_NMD(amsnippet1, False)
pattern = re.compile(r'lib_([A-Z]+)', re.M)
amsnippet1 = pattern.sub(r'libtests_a_\1', amsnippet1)
amsnippet1 = amsnippet1.replace('$(GNULIB_', '$(' + module_indicator_prefix + '_GNULIB_')
amsnippet1 = amsnippet1.replace('lib%_LIBRARIES', 'lib_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib%_LTLIBRARIES', 'lib_LTLIBRARIES')
if edit_check_PROGRAMS:
amsnippet1 = amsnippet1.replace('check_PROGRAMS', 'noinst_PROGRAMS')
amsnippet1 = amsnippet1.replace('${gl_include_guard_prefix}',
include_guard_prefix)
# Check if module is 'alloca'.
if libtests and module.name == 'alloca':
amsnippet1 += 'libtests_a_LIBADD += @ALLOCA@\n'
amsnippet1 += 'libtests_a_DEPENDENCIES += @ALLOCA@\n'
amsnippet1 = combine_lines_matching(re.compile(r'libtests_a_SOURCES'),
amsnippet1)
# Get unconditional snippet, edit it and save to amsnippet2.
amsnippet2 = module.getAutomakeSnippet_Unconditional()
pattern = re.compile(r'lib_([A-Z]+)', re.M)
amsnippet2 = pattern.sub(r'libtests_a_\1', amsnippet2)
amsnippet2 = amsnippet2.replace('$(GNULIB_',
'$(' + module_indicator_prefix + '_GNULIB_')
# Skip the contents if it's entirely empty.
if (amsnippet1 + amsnippet2).strip() != '':
snippet = '## begin gnulib module %s\n' % module.name
if gnu_make:
snippet += 'ifeq (,$(OMIT_GNULIB_MODULE_%s))\n' % module.name
snippet += '\n'
if conddeps:
if moduletable.isConditional(module):
name = module.getConditionalName()
if gnu_make:
snippet += 'ifneq (,$(%s_CONDITION))\n' % name
else:
snippet += 'if %s\n' % name
if gnu_make:
snippet += _convert_to_gnu_make(amsnippet1)
else:
snippet += amsnippet1
if conddeps:
if moduletable.isConditional(module):
snippet += 'endif\n'
if gnu_make:
snippet += _convert_to_gnu_make(amsnippet2)
else:
snippet += amsnippet2
if gnu_make:
snippet += 'endif\n'
snippet += '## end gnulib module %s\n\n' % module.name
# Mention long-running tests at the end.
if 'longrunning-test' in module.getStatuses():
longrun_snippets += snippet
else:
main_snippets += snippet
# Test whether there are some source files in subdirectories.
for file in module.getFiles():
if ((file.startswith('lib/') or file.startswith('tests/'))
and file.endswith('.c')
and file.count('/') > 1):
uses_subdirs = True
break
# 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 = ''
if uses_subdirs:
subdir_options = ' subdir-objects'
emit += 'AUTOMAKE_OPTIONS = 1.14 foreign%s\n\n' % subdir_options
if for_test and not single_configure:
emit += 'ACLOCAL_AMFLAGS = -I %s/%s\n\n' % (testsbase_inverse, m4base)
# 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"
emit += 'SUBDIRS = .\n'
emit += 'TESTS =\n'
emit += 'XFAIL_TESTS =\n'
emit += 'TESTS_ENVIRONMENT =\n'
emit += 'noinst_PROGRAMS =\n'
if not for_test:
emit += 'check_PROGRAMS =\n'
emit += 'EXTRA_PROGRAMS =\n'
emit += 'noinst_HEADERS =\n'
emit += 'noinst_LIBRARIES =\n'
if libtests:
if for_test:
emit += 'noinst_LIBRARIES += libtests.a\n'
else: # if not for_test
emit += 'check_LIBRARIES = libtests.a\n'
emit += 'pkgdata_DATA =\n'
emit += 'EXTRA_DIST =\n'
emit += 'BUILT_SOURCES =\n'
emit += 'SUFFIXES =\n'
emit += 'MOSTLYCLEANFILES = core *.stackdump\n'
emit += 'MOSTLYCLEANDIRS =\n'
emit += 'CLEANFILES =\n'
emit += 'DISTCLEANFILES =\n'
emit += 'MAINTAINERCLEANFILES =\n'
# Execute edits that apply to the Makefile.am being generated.
for current_edit in range(0, makefiletable.count()):
dictionary = makefiletable[current_edit]
if 'var' in dictionary:
if destfile == joinpath(dictionary['dir'], 'Makefile.am'):
val = dictionary['val']
if dictionary['var'] == 'SUBDIRS' and dictionary['dotfirst']:
# The added subdirectory ${val} needs to be mentioned after '.'.
# But we have '.' among SUBDIRS already, so do nothing.
pass
emit += '%s += %s\n' % (dictionary['var'], val)
del dictionary['var']
emit += '\n'
# Insert a '-Wno-error' option in the compilation commands emitted by
# Automake, between $(AM_CPPFLAGS) and before the reference to @CFLAGS@.
# Why?
# 1) Because parts of the Gnulib tests exercise corner cases (invalid
# arguments, endless recursions, etc.) that a compiler may warn about,
# even with just the normal '-Wall' option.
# 2) Because every package maintainer has their preferred set of warnings
# that they may want to enforce in the main source code of their package.
# But Gnulib tests are maintained in Gnulib and don't end up in binaries
# that that package installs; therefore it does not make sense for
# package maintainers to enforce the absence of warnings on these tests.
# Why before @CFLAGS@?
# - Because "the user is always right": If a user adds '-Werror' to their
# CFLAGS, they have asked for errors, they will get errors. But they have
# no right to complain about these errors, because Gnulib does not support
# '-Werror'.
cflags_for_gnulib_code = ''
if not for_test:
# Enable or disable warnings as suitable for the Gnulib coding style.
cflags_for_gnulib_code = ' $(GL_CFLAG_GNULIB_WARNINGS)'
emit += 'CFLAGS = @GL_CFLAG_ALLOW_WARNINGS@%s @CFLAGS@\n' % (cflags_for_gnulib_code)
emit += 'CXXFLAGS = @GL_CXXFLAG_ALLOW_WARNINGS@ @CXXFLAGS@\n'
emit += '\n'
emit += 'AM_CPPFLAGS = \\\n'
if for_test:
emit += ' -DGNULIB_STRICT_CHECKING=1 \\\n'
if witness_c_macro:
emit += ' -D%s=1 \\\n' % witness_c_macro
if witness_macro:
emit += ' -D@%s@=1 \\\n' % witness_macro
emit += ' -I. -I$(srcdir) \\\n'
emit += ' -I%s -I$(srcdir)/%s \\\n' % (testsbase_inverse, testsbase_inverse)
emit += ' -I%s/%s -I$(srcdir)/%s/%s\n' % (testsbase_inverse, sourcebase, testsbase_inverse, sourcebase)
emit += '\n'
if libtests:
# 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
# 'version-etc' module whose dependency to 'version-etc-fsf' is
# voluntarily omitted).
# The LIBTESTS_LIBDEPS can be passed to the linker once or twice, it
# does not matter.
emit += ('LDADD = libtests.a %s/%s/%s.%s libtests.a %s/%s/%s.%s libtests.a $(LIBTESTS_LIBDEPS)\n'
% (testsbase_inverse, sourcebase, libname, libext,
testsbase_inverse, sourcebase, libname, libext))
else:
emit += ('LDADD = %s/%s/%s.%s\n'
% (testsbase_inverse, sourcebase, libname, libext))
emit += '\n'
if libtests:
emit += 'libtests_a_SOURCES =\n'
# Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
# automake during its analysis looks for $(LIBOBJS), not for @LIBOBJS@.
emit += 'libtests_a_LIBADD = $(%stests_LIBOBJS)\n' % macro_prefix
emit += 'libtests_a_DEPENDENCIES = $(%stests_LIBOBJS)\n' % macro_prefix
emit += 'EXTRA_libtests_a_SOURCES =\n'
# The circular dependency in LDADD requires this.
emit += 'AM_LIBTOOLFLAGS = --preserve-dup-deps\n\n'
# Many test scripts use ${EXEEXT} or ${srcdir}.
# EXEEXT is defined by AC_PROG_CC through autoconf.
# srcdir is defined by autoconf and automake.
emit += "TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'\n"
# Omit logs of skipped tests from test-suite.log, if Automake ≥ 1.17 is used.
emit += 'IGNORE_SKIPPED_LOGS = 1\n\n'
all_snippets = main_snippets + longrun_snippets
all_snippets = all_snippets.replace('$(top_srcdir)/build-aux/',
'$(top_srcdir)/%s/' % auxdir)
emit += all_snippets
# Arrange to print a message before compiling the files in this directory.
emit += 'all: all-notice\n'
emit += 'all-notice:\n'
emit += '\t@echo \'## ---------------------------------------------------- ##\'\n'
emit += '\t@echo \'## ------------------- Gnulib tests ------------------- ##\'\n'
emit += '\t@echo \'## You can ignore compiler warnings in this directory. ##\'\n'
emit += '\t@echo \'## ---------------------------------------------------- ##\'\n'
emit += '\n'
# Arrange to print a message before executing the tests in this directory.
emit += 'check-am: check-notice\n'
emit += 'check-notice:\n'
emit += '\t@echo \'## ---------------------------------------------------------------------- ##\'\n'
emit += '\t@echo \'## ---------------------------- Gnulib tests ---------------------------- ##\'\n'
emit += '\t@echo \'## Please report test failures in this directory to <bug-gnulib@gnu.org>. ##\'\n'
emit += '\t@echo \'## ---------------------------------------------------------------------- ##\'\n'
emit += '\n'
emit += '# Clean up after Solaris cc.\n'
emit += 'clean-local:\n'
emit += '\trm -rf SunWS_cache\n\n'
emit += 'mostlyclean-local: mostlyclean-generic\n'
emit += '\t@for dir in \'\' $(MOSTLYCLEANDIRS); do \\\n'
emit += '\t if test -n "$$dir" && test -d $$dir; then \\\n'
emit += '\t echo "rmdir $$dir"; rmdir $$dir; \\\n'
emit += '\t fi; \\\n'
emit += '\tdone; \\\n'
emit += '\t:\n'
return emit