Today's changes:
2022-08-09 Bruno Haible <[email protected]>
gnulib-tool.py: Finish implementing option --conditional-dependencies.
* gnulib-tool.py (main) Accept options --conditional-dependencies,
--no-conditional-dependencies.
* pygnulib/GLModuleSystem.py (GLModuleTable.addConditional): Use
str(module), not module, as key. Fix logic bug.
(GLModuleTable.getCondition): Simplify.
(GLModuleTable.transitive_closure): Show a warning when there are
duplicate dependencies. Fix logic bug.
(GLModuleTable.transitive_closure_separately): Simplify.
(GLModuleTable.add_dummy): Ignore tests modules. Cope with multiple
lib_SOURCES augmentation lines. Cope with comments at the end of a
lib_SOURCES augmentation line. Add the dummy module at the end of the
modules list.
* pygnulib/GLTestDir.py (GLTestDir.execute): Remove the code that forces
the dummy module to the end of the list.
* pygnulib/GLEmiter.py (GLEmiter.autoconfSnippets): Add code to
terminate the shell functions. Add code for the dependencies from the
unconditional to the conditional modules. Don't emit AM_CONDITIONAL for
unconditional modules.
gnulib-tool.py: Don't do license replacements in the autoconf snippets.
* pygnulib/GLEmiter.py (GLEmiter.autoconfSnippet): Remove fileassistant
argument. Don't invoke the 'aux' transformer here. Don't produce Windows
CR-LFs on Windows.
(GLEmiter.autoconfSnippets): Remove fileassistant argument.
* pygnulib/GLImport.py (GLImport.gnulib_comp): Update all callers.
* pygnulib/GLTestDir.py (GLTestDir.execute): Likewise.
gnulib-tool.py: Fix some code generation details.
* pygnulib/GLEmiter.py (GLEmiter.lib_Makefile_am): When removing a
lib_LDFLAGS line, remove also the newline. Fix regex that matches
lib_SOMETHING. Add a newline after each '## begin gnulib module' line.
Don't emit 'endif' lines without corresponding 'if'. When emitting a
'+=' augmentation, make sure it does not get emitted a second time.
Don't emit a blank line when there is no AM_CPPFLAGS augmentation.
Update after getLink() changed. In the value of DEFAULT_TEXT_DOMAIN,
backslash-escape the double-quotes. Don't produce Windows CR-LFs on
Windows. Simplify.
(GLEmiter.tests_Makefile_am): When removing a lib_LDFLAGS line, remove
also the newline. Fix regex that matches lib_SOMETHING. Don't remove a
blank line before EXTRA_DIST. Add a newline after each
'## begin gnulib module' line. Set uses_subdirs also when there is a .c
file in a subdir of tests/. When emitting a '+=' augmentation, make sure
it does not get emitted a second time. Don't produce Windows CR-LFs on
Windows. Simplify.
* pygnulib/GLImport.py (GLImport.execute): Update after getLink()
changed.
gnulib-tool.py: Fixes for conditional dependencies.
* pygnulib/GLModuleSystem.py (GLModule.shell_id_chars): New constant.
(GLModule.getShellFunc): Don't use md5 just because of an '_' character.
(GLModule.getShellVar): Likewise.
(GLModule.getConditionalName): Include a newline in the md5 input.
* pygnulib/constants.py (ALPHANUMERIC): Remove constant.
gnulib-tool.py: Refactor.
* pygnulib/GLModuleSystem.py (GLModule.getLicense): Separate the warning
logic from the result logic.
>From d0e094317bbf34413e458f9551543335b6eb8cef Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Mon, 8 Aug 2022 18:42:45 +0200
Subject: [PATCH 1/5] gnulib-tool.py: Refactor.
* pygnulib/GLModuleSystem.py (GLModule.getLicense): Separate the warning
logic from the result logic.
---
ChangeLog | 6 ++++++
pygnulib/GLModuleSystem.py | 21 +++++++++++----------
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5dc57dc4f8..596f629316 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2022-08-09 Bruno Haible <[email protected]>
+
+ gnulib-tool.py: Refactor.
+ * pygnulib/GLModuleSystem.py (GLModule.getLicense): Separate the warning
+ logic from the result logic.
+
2022-08-09 Paul Eggert <[email protected]>
largefile, year2038: simplify if Autoconf 2.72
diff --git a/pygnulib/GLModuleSystem.py b/pygnulib/GLModuleSystem.py
index 19d13d213b..13d6a72231 100644
--- a/pygnulib/GLModuleSystem.py
+++ b/pygnulib/GLModuleSystem.py
@@ -651,23 +651,24 @@ class GLModule(object):
Get license and warn user if module lacks a license.'''
if 'license' not in self.cache:
- result = None
+ license = self.getLicense_Raw().strip()
+ # Warn if the License field is missing.
+ if not self.isTests():
+ if not license:
+ if self.config['errors']:
+ raise GLError(18, str(self))
+ else: # if not self.config['errors']
+ sys.stderr.write('gnulib-tool: warning: module %s lacks a License\n' % str(self))
if str(self) == 'parse-datetime':
# This module is under a weaker license only for the purpose of some
# users who hand-edit it and don't use gnulib-tool. For the regular
# gnulib users they are under a stricter license.
result = 'GPL'
else:
- license = self.getLicense_Raw().strip()
- if not self.isTests():
- if not license:
- if self.config['errors']:
- raise GLError(18, str(self))
- else: # if not self.config['errors']
- sys.stderr.write('gnulib-tool: warning: module %s lacks a license\n' % str(self))
- if not license:
- license = 'GPL'
result = license
+ # The default is GPL.
+ if not result:
+ result = 'GPL'
self.cache['license'] = result
return self.cache['license']
--
2.34.1
>From 501feeb5d595d8b4cea9a1a8e404277c27d2f5bf Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Mon, 8 Aug 2022 21:22:15 +0200
Subject: [PATCH 2/5] gnulib-tool.py: Fixes for conditional dependencies.
* pygnulib/GLModuleSystem.py (GLModule.shell_id_chars): New constant.
(GLModule.getShellFunc): Don't use md5 just because of an '_' character.
(GLModule.getShellVar): Likewise.
(GLModule.getConditionalName): Include a newline in the md5 input.
* pygnulib/constants.py (ALPHANUMERIC): Remove constant.
---
ChangeLog | 7 ++++
pygnulib/GLModuleSystem.py | 70 ++++++++++++++++++++------------------
pygnulib/constants.py | 3 --
3 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 596f629316..091af1f974 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2022-08-09 Bruno Haible <[email protected]>
+ gnulib-tool.py: Fixes for conditional dependencies.
+ * pygnulib/GLModuleSystem.py (GLModule.shell_id_chars): New constant.
+ (GLModule.getShellFunc): Don't use md5 just because of an '_' character.
+ (GLModule.getShellVar): Likewise.
+ (GLModule.getConditionalName): Include a newline in the md5 input.
+ * pygnulib/constants.py (ALPHANUMERIC): Remove constant.
+
gnulib-tool.py: Refactor.
* pygnulib/GLModuleSystem.py (GLModule.getLicense): Separate the warning
logic from the result logic.
diff --git a/pygnulib/GLModuleSystem.py b/pygnulib/GLModuleSystem.py
index 13d6a72231..9bfd5bd266 100644
--- a/pygnulib/GLModuleSystem.py
+++ b/pygnulib/GLModuleSystem.py
@@ -183,6 +183,9 @@ class GLModule(object):
+ 'Makefile\\.am|Include|Link|License|Maintainer):$',
re.M)
+ # List of characters allowed in shell identifiers.
+ shell_id_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_'
+
def __init__(self, config, path, patched=False):
'''GLModule.__init__(config, path[, patched]) -> GLModule
@@ -329,20 +332,19 @@ class GLModule(object):
Computes the shell function name that will contain the m4 macros for the
module.'''
- isalnum = True
macro_prefix = self.config['macro_prefix']
- for char in str(module):
- if char not in constants.ALPHANUMERIC:
- isalnum = False
+ valid_shell_id = True
+ for char in self.getName():
+ if char not in GLModule.shell_id_chars:
+ valid_shell_id = False
break
- if isalnum:
- module = str(self)
- else: # if not isalnum
- module = '%s\n' % str(self)
- if type(module) is str:
- module = module.encode(ENCS['default'])
- module = hashlib.md5(module).hexdigest()
- result = 'func_%s_gnulib_m4code_%s' % (macro_prefix, module)
+ identifier = None
+ if valid_shell_id:
+ identifier = self.getName()
+ else:
+ hash_input = '%s\n' % self.getName()
+ identifier = hashlib.md5(hash_input.encode(ENCS['default'])).hexdigest()
+ result = 'func_%s_gnulib_m4code_%s' % (macro_prefix, identifier)
return result
def getShellVar(self):
@@ -350,20 +352,19 @@ class GLModule(object):
Compute the shell variable name the will be set to true once the m4 macros
for the module have been executed.'''
- isalnum = True
macro_prefix = self.config['macro_prefix']
- for char in str(module):
- if char not in constants.ALPHANUMERIC:
- isalnum = False
+ valid_shell_id = True
+ for char in self.getName():
+ if char not in GLModule.shell_id_chars:
+ valid_shell_id = False
break
- if isalnum:
- module = str(self)
- else: # if not isalnum
- module = '%s\n' % str(self)
- if type(module) is str:
- module = module.encode(ENCS['default'])
- module = hashlib.md5(module).hexdigest()
- result = '%s_gnulib_enabled_%s' % (macro_prefix, module)
+ identifier = None
+ if valid_shell_id:
+ identifier = self.getName()
+ else:
+ hash_input = '%s\n' % self.getName()
+ identifier = hashlib.md5(hash_input.encode(ENCS['default'])).hexdigest()
+ result = '%s_gnulib_enabled_%s' % (macro_prefix, identifier)
return result
def getConditionalName(self):
@@ -372,15 +373,18 @@ class GLModule(object):
Return the automake conditional name.
GLConfig: macro_prefix.'''
macro_prefix = self.config['macro_prefix']
- nonascii = [ char
- for char in self.getName()
- if char not in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' ]
- if nonascii:
- name = self.getName().encode(ENCS['default'])
- name = hashlib.md5(name).hexdigest()
- conditional = '%s_GNULIB_ENABLED_%s' % (macro_prefix, name)
- else: # if not nonascii
- result = '%s_GNULIB_ENABLED_%s' % (macro_prefix, name)
+ valid_shell_id = True
+ for char in self.getName():
+ if char not in GLModule.shell_id_chars:
+ valid_shell_id = False
+ break
+ identifier = None
+ if valid_shell_id:
+ identifier = self.getName()
+ else:
+ hash_input = '%s\n' % self.getName()
+ identifier = hashlib.md5(hash_input.encode(ENCS['default'])).hexdigest()
+ result = '%s_GNULIB_ENABLED_%s' % (macro_prefix, identifier)
return result
def getDescription(self):
diff --git a/pygnulib/constants.py b/pygnulib/constants.py
index ba0ebc9942..ae27d8d41a 100644
--- a/pygnulib/constants.py
+++ b/pygnulib/constants.py
@@ -57,9 +57,6 @@ MODES = dict() # Modes
TESTS = dict() # Tests
NL = '''
''' # Newline character
-ALPHANUMERIC = 'abcdefghijklmnopqrstuvwxyz\
-ABCDEFGHIJKLMNOPQRSTUVWXYZ\
-0123456789' # Alphanumeric characters
# Set ENCS dictionary
if not hasattr(interpreter, '__file__'):
--
2.34.1
>From 98e7ca354a1108b0b99236e29bedbc6bfbd8593e Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 9 Aug 2022 16:11:09 +0200
Subject: [PATCH 3/5] gnulib-tool.py: Fix some code generation details.
* pygnulib/GLEmiter.py (GLEmiter.lib_Makefile_am): When removing a
lib_LDFLAGS line, remove also the newline. Fix regex that matches
lib_SOMETHING. Add a newline after each '## begin gnulib module' line.
Don't emit 'endif' lines without corresponding 'if'. When emitting a
'+=' augmentation, make sure it does not get emitted a second time.
Don't emit a blank line when there is no AM_CPPFLAGS augmentation.
Update after getLink() changed. In the value of DEFAULT_TEXT_DOMAIN,
backslash-escape the double-quotes. Don't produce Windows CR-LFs on
Windows. Simplify.
(GLEmiter.tests_Makefile_am): When removing a lib_LDFLAGS line, remove
also the newline. Fix regex that matches lib_SOMETHING. Don't remove a
blank line before EXTRA_DIST. Add a newline after each
'## begin gnulib module' line. Set uses_subdirs also when there is a .c
file in a subdir of tests/. When emitting a '+=' augmentation, make sure
it does not get emitted a second time. Don't produce Windows CR-LFs on
Windows. Simplify.
* pygnulib/GLImport.py (GLImport.execute): Update after getLink()
changed.
---
ChangeLog | 20 +++++
pygnulib/GLEmiter.py | 203 +++++++++++++++++++++----------------------
pygnulib/GLImport.py | 16 ++--
3 files changed, 125 insertions(+), 114 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 091af1f974..50ef82d525 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2022-08-09 Bruno Haible <[email protected]>
+ gnulib-tool.py: Fix some code generation details.
+ * pygnulib/GLEmiter.py (GLEmiter.lib_Makefile_am): When removing a
+ lib_LDFLAGS line, remove also the newline. Fix regex that matches
+ lib_SOMETHING. Add a newline after each '## begin gnulib module' line.
+ Don't emit 'endif' lines without corresponding 'if'. When emitting a
+ '+=' augmentation, make sure it does not get emitted a second time.
+ Don't emit a blank line when there is no AM_CPPFLAGS augmentation.
+ Update after getLink() changed. In the value of DEFAULT_TEXT_DOMAIN,
+ backslash-escape the double-quotes. Don't produce Windows CR-LFs on
+ Windows. Simplify.
+ (GLEmiter.tests_Makefile_am): When removing a lib_LDFLAGS line, remove
+ also the newline. Fix regex that matches lib_SOMETHING. Don't remove a
+ blank line before EXTRA_DIST. Add a newline after each
+ '## begin gnulib module' line. Set uses_subdirs also when there is a .c
+ file in a subdir of tests/. When emitting a '+=' augmentation, make sure
+ it does not get emitted a second time. Don't produce Windows CR-LFs on
+ Windows. Simplify.
+ * pygnulib/GLImport.py (GLImport.execute): Update after getLink()
+ changed.
+
gnulib-tool.py: Fixes for conditional dependencies.
* pygnulib/GLModuleSystem.py (GLModule.shell_id_chars): New constant.
(GLModule.getShellFunc): Don't use md5 just because of an '_' character.
diff --git a/pygnulib/GLEmiter.py b/pygnulib/GLEmiter.py
index a02b44bdd5..1a15fc4918 100644
--- a/pygnulib/GLEmiter.py
+++ b/pygnulib/GLEmiter.py
@@ -655,29 +655,34 @@ AC_DEFUN([%V1%_LIBSOURCES], [
if libtool:
libext = 'la'
perhapsLT = 'LT'
- LD_flags = False
+ eliminate_LDFLAGS = False
else: # if not libtool
libext = 'a'
perhapsLT = ''
- LD_flags = True
+ 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.
- check_PROGRAMS = True
+ edit_check_PROGRAMS = True
else: # if not for_test
- check_PROGRAMS = False
+ edit_check_PROGRAMS = False
emit += "## DO NOT EDIT! GENERATED AUTOMATICALLY!\n"
emit += "## Process this file with automake to produce Makefile.in.\n"
emit += self.copyright_notice()
if actioncmd:
+ # 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.
if len(actioncmd) <= 3000:
emit += "# Reproduce by: %s\n" % actioncmd
emit += '\n'
uses_subdirs = False
- # Modify allsnippets variable.
+ # Compute allsnippets variable.
allsnippets = ''
for module in modules:
if not module.isTests():
@@ -685,16 +690,16 @@ AC_DEFUN([%V1%_LIBSOURCES], [
amsnippet1 = module.getAutomakeSnippet_Conditional()
amsnippet1 = amsnippet1.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
amsnippet1 = amsnippet1.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
- if LD_flags:
- pattern = re.compile('lib_LDFLAGS[\t ]*\\+=(.*)$', re.M)
+ if eliminate_LDFLAGS:
+ pattern = re.compile('^(lib_LDFLAGS[\t ]*\\+=.*$\n)', re.M)
amsnippet1 = pattern.sub('', amsnippet1)
- pattern = re.compile('lib_([A-Z][A-Z](?:.*))', re.M)
+ pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
amsnippet1 = pattern.sub('%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 check_PROGRAMS:
+ if edit_check_PROGRAMS:
amsnippet1 = amsnippet1.replace('check_PROGRAMS', 'noinst_PROGRAMS')
amsnippet1 = amsnippet1.replace('${gl_include_guard_prefix}',
include_guard_prefix)
@@ -706,29 +711,33 @@ AC_DEFUN([%V1%_LIBSOURCES], [
# Get unconditional snippet, edit it and save to amsnippet2.
amsnippet2 = module.getAutomakeSnippet_Unconditional()
- pattern = re.compile('lib_([A-Z][A-Z](?:.*))', re.M)
+ pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
amsnippet2 = pattern.sub('%s_%s_\\1' % (libname, libext),
amsnippet2)
amsnippet2 = amsnippet2.replace('$(GNULIB_',
'$(' + module_indicator_prefix + '_GNULIB_')
+ # Skip the contents if it's entirely empty.
if not (amsnippet1 + amsnippet2).isspace():
- allsnippets += '## begin gnulib module %s\n' % str(module)
+ allsnippets += '## begin gnulib module %s\n\n' % str(module)
if conddeps:
if moduletable.isConditional(module):
name = module.getConditionalName()
allsnippets += 'if %s\n' % name
allsnippets += amsnippet1
if conddeps:
- allsnippets += 'endif\n'
+ if moduletable.isConditional(module):
+ allsnippets += 'endif\n'
allsnippets += amsnippet2
allsnippets += '## end gnulib module %s\n\n' % str(module)
# Test whether there are some source files in subdirectories.
for file in module.getFiles():
- if (file.startswith('lib/') and file.endswith('.c')
+ 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
@@ -762,53 +771,50 @@ AC_DEFUN([%V1%_LIBSOURCES], [
emit += 'MAINTAINERCLEANFILES =\n'
# Execute edits that apply to the Makefile.am being generated.
- current_edit = int()
- makefile_am_edits = makefiletable.count()
- while current_edit != makefile_am_edits:
+ for current_edit in range(0, makefiletable.count()):
dictionary = makefiletable[current_edit]
if dictionary['var']:
- paths = list()
- paths += [joinpath(dictionary['dir'], 'Makefile.am')]
- paths += [os.path.normpath('./%s/Makefile.am' % dictionary['dir'])]
- paths = sorted(set(paths))
- if destfile in paths:
- emit += '%s += %s\n' % (dictionary['var'],
- dictionary['val'])
- current_edit += 1
+ if destfile == joinpath(dictionary['dir'], 'Makefile.am'):
+ emit += '%s += %s\n' % (dictionary['var'], dictionary['val'])
+ dictionary.pop('var')
# Define two parts of cppflags variable.
- emit += '\n'
cppflags_part1 = ''
- cppflags_part2 = ''
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'
- # One of the snippets or the user's Makefile.am already specifies an
+ # 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.
- insnippets = False
- inmakefile = False
+ lib_gets_installed = False
regex = '^[a-zA-Z0-9_]*_%sLIBRARIES *\\+{0,1}= *%s\\.%s' % (perhapsLT, libname, libext)
pattern = re.compile(regex, re.M)
- insnippets = bool(pattern.findall(allsnippets))
- # Then test if $sourcebase/Makefile.am (if it exists) specifies it.
- path = joinpath(sourcebase, 'Makefile.am')
- if makefile_name and isfile(path):
- with codecs.open(path, 'rb', 'UTF-8') as file:
- data = file.read()
- inmakefile = bool(pattern.findall(data))
- if not any([insnippets, inmakefile]):
+ 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 isfile(path):
+ with codecs.open(path, 'rb', '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)
@@ -824,22 +830,22 @@ AC_DEFUN([%V1%_LIBSOURCES], [
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 not module.isTests()]
- ulinks = list()
- for link in links:
- for lib in link:
- lib = constants.nlremove(lib)
- position = lib.find(' when linking with libtool')
- if position != -1:
- lib = lib[:position]
- ulinks += [lib]
- ulinks = sorted(set(ulinks))
- for link in ulinks:
- emit += '%s_%s_LDFLAGS += %s\n' % (libname, libext, link)
+ links = [ module.getLink()
+ for module in modules
+ if not module.isTests() ]
+ lines = [ line
+ for link in links
+ for line in link.split('\n')
+ if line != '' ]
+ pattern = re.compile(' when linking with libtool.*')
+ lines = [ pattern.sub('', 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 += 'AM_CPPFLAGS += -DDEFAULT_TEXT_DOMAIN=\\"%s-gnulib\\"\n' % podomain
emit += '\n'
allsnippets = allsnippets.replace('$(top_srcdir)/build-aux/',
'$(top_srcdir)/%s/' % auxdir)
@@ -852,7 +858,6 @@ AC_DEFUN([%V1%_LIBSOURCES], [
emit += '\t fi; \\\n'
emit += '\tdone; \\\n'
emit += '\t:\n'
- emit = constants.nlconvert(emit)
result = tuple([emit, uses_subdirs])
return result
@@ -913,19 +918,19 @@ AC_DEFUN([%V1%_LIBSOURCES], [
if libtool:
libext = 'la'
perhapsLT = 'LT'
- LD_flags = False
+ eliminate_LDFLAGS = False
else: # if not libtool
libext = 'a'
perhapsLT = ''
- LD_flags = True
+ 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.
- check_PROGRAMS = True
+ edit_check_PROGRAMS = True
else: # if not for_test
- check_PROGRAMS = False
+ edit_check_PROGRAMS = False
# Calculate testsbase_inverse
counter = int()
@@ -945,22 +950,22 @@ AC_DEFUN([%V1%_LIBSOURCES], [
longrun_snippets = ''
for module in modules:
if for_test and not single_configure:
- flag = module.isTests()
+ accept = module.isTests()
else: # if for_test and not single_configure
- flag = True
- if flag:
+ accept = True
+ if accept:
snippet = module.getAutomakeSnippet()
snippet = snippet.replace('lib_LIBRARIES', 'lib%_LIBRARIES')
snippet = snippet.replace('lib_LTLIBRARIES', 'lib%_LTLIBRARIES')
- if LD_flags:
- pattern = re.compile('lib_LDFLAGS[\t ]*\\+=(.*)$', re.M)
- snippet = pattern.sub('', snippet)
- pattern = re.compile('lib_([A-Z][A-Z](?:.*))', re.M)
+ if eliminate_LDFLAGS:
+ pattern = re.compile('^(lib_LDFLAGS[\t ]*\\+=.*$\n)', re.M)
+ amsnippet1 = pattern.sub('', snippet)
+ pattern = re.compile('lib_([A-Z][A-Z]*)', re.M)
snippet = pattern.sub('libtests_a_\\1', snippet)
snippet = snippet.replace('$(GNULIB_', '$(' + module_indicator_prefix + '_GNULIB_')
snippet = snippet.replace('lib%_LIBRARIES', 'lib_LIBRARIES')
snippet = snippet.replace('lib%_LTLIBRARIES', 'lib_LTLIBRARIES')
- if check_PROGRAMS:
+ if edit_check_PROGRAMS:
snippet = snippet.replace('check_PROGRAMS', 'noinst_PROGRAMS')
snippet = snippet.replace('${gl_include_guard_prefix}',
include_guard_prefix)
@@ -970,28 +975,20 @@ AC_DEFUN([%V1%_LIBSOURCES], [
snippet += 'libtests_a_DEPENDENCIES += @%sALLOCA@\n' % perhapsLT
# Skip the contents if it's entirely empty.
- if snippet.strip():
- # Check status of the module.
- statuses = module.getStatuses()
- islongrun = False
- for word in statuses:
- if word == 'longrunning-test':
- islongrun = True
- break
- if not islongrun:
- snippet = snippet.replace('\n\nEXTRA_DIST', '\nEXTRA_DIST')
- main_snippets += '## begin gnulib module %s\n' % str(module)
- main_snippets += snippet
- main_snippets += '## end gnulib module %s\n\n' % str(module)
- else: # if islongrunning
- snippet = snippet.replace('\n\nEXTRA_DIST', '\nEXTRA_DIST')
- longrun_snippets += '## begin gnulib module %s\n' % str(module)
+ if not snippet.isspace():
+ snippet = ('## begin gnulib module %s\n\n' % str(module)
+ + snippet
+ + '## end gnulib module %s\n\n' % str(module))
+ # Mention long-running tests at the end.
+ if 'longrunning-test' in module.getStatuses():
longrun_snippets += snippet
- longrun_snippets += '## end gnulib module %s\n' % str(module)
+ else:
+ main_snippets += snippet
# Test whether there are some source files in subdirectories.
for file in module.getFiles():
- if (file.startswith('lib/') and file.endswith('.c')
+ if ((file.startswith('lib/') or file.startswith('tests/'))
+ and file.endswith('.c')
and file.count('/') > 1):
uses_subdirs = True
break
@@ -1031,7 +1028,7 @@ AC_DEFUN([%V1%_LIBSOURCES], [
# * https://debbugs.gnu.org/11030
# So we need this workaround.
pattern = re.compile('^pkgdata_DATA *\\+=', re.M)
- if bool(pattern.findall(main_snippets)) or bool(pattern.findall(longrun_snippets)):
+ if pattern.findall(main_snippets) or pattern.findall(longrun_snippets):
emit += 'pkgdata_DATA =\n'
emit += 'EXTRA_DIST =\n'
@@ -1044,20 +1041,12 @@ AC_DEFUN([%V1%_LIBSOURCES], [
emit += 'MAINTAINERCLEANFILES =\n'
# Execute edits that apply to the Makefile.am being generated.
- # Execute edits that apply to the Makefile.am being generated.
- current_edit = int()
- makefile_am_edits = makefiletable.count()
- while current_edit != makefile_am_edits:
+ for current_edit in range(0, makefiletable.count()):
dictionary = makefiletable[current_edit]
if dictionary['var']:
- paths = list()
- paths += [joinpath(dictionary['dir'], 'Makefile.am')]
- paths += [os.path.normpath('./%s/Makefile.am' % dictionary['dir'])]
- paths = sorted(set(paths))
- if destfile in paths:
- emit += '%s += %s\n' % (dictionary['var'],
- dictionary['val'])
- current_edit += 1
+ if destfile == joinpath(dictionary['dir'], 'Makefile.am'):
+ emit += '%s += %s\n' % (dictionary['var'], dictionary['val'])
+ dictionary.pop('var')
emit += '\nAM_CPPFLAGS = \\\n'
if for_test:
@@ -1071,6 +1060,8 @@ AC_DEFUN([%V1%_LIBSOURCES], [
emit += ' -I%s/%s -I$(srcdir)/%s/%s\n' % (testsbase_inverse, sourcebase, testsbase_inverse, sourcebase)
emit += '\n'
+ ldadd_before = ''
+ ldadd_after = ''
if libtests:
# All test programs need to be linked with libtests.a.
# It needs to be passed to the linker before ${libname}.${libext},
@@ -1081,11 +1072,13 @@ AC_DEFUN([%V1%_LIBSOURCES], [
# 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\n' \
- % (testsbase_inverse, sourcebase, libname, libext,
- testsbase_inverse, sourcebase, libname, libext)
- else:
- emit += 'LDADD = %s/%s/%s.%s\n\n' % (testsbase_inverse, sourcebase, libname, libext)
+ ldadd_before = ' libtests.a'
+ ldadd_after = ' libtests.a $(LIBTESTS_LIBDEPS)'
+ emit += 'LDADD =%s %s/%s/%s.%s libtests.a %s/%s/%s.%s%s\n\n' \
+ % (ldadd_before,
+ testsbase_inverse, sourcebase, libname, libext,
+ testsbase_inverse, sourcebase, libname, libext,
+ ldadd_after)
if libtests:
emit += 'libtests_a_SOURCES =\n'
# Here we use $(LIBOBJS), not @LIBOBJS@. The value is the same. However,
@@ -1099,11 +1092,10 @@ AC_DEFUN([%V1%_LIBSOURCES], [
# EXEEXT is defined by AC_PROG_CC through autoconf.
# srcdir is defined by autoconf and automake.
emit += "TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'\n\n"
- main_snippets = main_snippets.replace('$(top_srcdir)/build-aux/',
- '$(top_srcdir)/%s/' % auxdir)
- longrun_snippets = longrun_snippets.replace('$(top_srcdir)/build-aux/',
- '$(top_srcdir)/%s/' % auxdir)
- emit += main_snippets + longrun_snippets
+ all_snippets = main_snippets + longrun_snippets
+ all_snippets = all_snippets.replace('$(top_srcdir)/build-aux/',
+ '$(top_srcdir)/%s/' % auxdir)
+ emit += all_snippets
emit += '# Clean up after Solaris cc.\n'
emit += 'clean-local:\n'
emit += '\trm -rf SunWS_cache\n\n'
@@ -1114,6 +1106,5 @@ AC_DEFUN([%V1%_LIBSOURCES], [
emit += '\t fi; \\\n'
emit += '\tdone; \\\n'
emit += '\t:\n'
- emit = constants.nlconvert(emit)
result = tuple([emit, uses_subdirs])
return result
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index 87d85c5181..0197e0671d 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -1398,18 +1398,18 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix
# Get link directives.
links = [ module.getLink()
for module in self.moduletable['main'] ]
- ulinks = list()
- for link in links:
- for lib in link:
- ulinks += [lib]
- ulinks = sorted(set(ulinks))
- if ulinks:
+ lines = [ line
+ for link in links
+ for line in link.split('\n')
+ if line != '' ]
+ lines = sorted(set(lines))
+ if lines:
print('''
You may need to use the following Makefile variables when linking.
Use them in <program>_LDADD when linking a program, or
in <library>_a_LDFLAGS or <library>_la_LDFLAGS when linking a library.''')
- for link in ulinks:
- print(' %s' % link)
+ for line in lines:
+ print(' %s' % line)
# Print reminders.
print('')
--
2.34.1
>From bc3d94bb2df6fa0c766f6226814c2fc2a55ee049 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 9 Aug 2022 23:59:40 +0200
Subject: [PATCH 4/5] gnulib-tool.py: Don't do license replacements in the
autoconf snippets.
* pygnulib/GLEmiter.py (GLEmiter.autoconfSnippet): Remove fileassistant
argument. Don't invoke the 'aux' transformer here. Don't produce Windows
CR-LFs on Windows.
(GLEmiter.autoconfSnippets): Remove fileassistant argument.
* pygnulib/GLImport.py (GLImport.gnulib_comp): Update all callers.
* pygnulib/GLTestDir.py (GLTestDir.execute): Likewise.
---
ChangeLog | 8 +++++++
pygnulib/GLEmiter.py | 51 ++++++++++++-------------------------------
pygnulib/GLImport.py | 4 ++--
pygnulib/GLTestDir.py | 10 ++++-----
4 files changed, 29 insertions(+), 44 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 50ef82d525..642a7363e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
2022-08-09 Bruno Haible <[email protected]>
+ gnulib-tool.py: Don't do license replacements in the autoconf snippets.
+ * pygnulib/GLEmiter.py (GLEmiter.autoconfSnippet): Remove fileassistant
+ argument. Don't invoke the 'aux' transformer here. Don't produce Windows
+ CR-LFs on Windows.
+ (GLEmiter.autoconfSnippets): Remove fileassistant argument.
+ * pygnulib/GLImport.py (GLImport.gnulib_comp): Update all callers.
+ * pygnulib/GLTestDir.py (GLTestDir.execute): Likewise.
+
gnulib-tool.py: Fix some code generation details.
* pygnulib/GLEmiter.py (GLEmiter.lib_Makefile_am): When removing a
lib_LDFLAGS line, remove also the newline. Fix regex that matches
diff --git a/pygnulib/GLEmiter.py b/pygnulib/GLEmiter.py
index 1a15fc4918..9b54d5009e 100644
--- a/pygnulib/GLEmiter.py
+++ b/pygnulib/GLEmiter.py
@@ -95,18 +95,15 @@ class GLEmiter(object):
# Generated by gnulib-tool.\n"""
return constants.nlconvert(emit)
- def autoconfSnippet(self, module, fileassistant, toplevel,
+ def autoconfSnippet(self, module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, indentation):
'''GLEmiter.autoconfSnippet(module, toplevel,
- disable_libtool, disable_gettext, replace_auxdir,
- indentation) -> str
+ disable_libtool, disable_gettext, replace_auxdir, indentation) -> str
Emit the autoconf snippet of a module.
GLConfig: include_guard_prefix.
module is a GLModule instance, which is processed.
- fileassistant is a GLFileAssistant instance, which is used to get temporary
- directories and sed transformer.
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.
@@ -115,13 +112,9 @@ class GLEmiter(object):
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.'''
- emit = ''
if type(module) is not GLModule:
raise TypeError('module must be a GLModule, not %s'
% type(module).__name__)
- if type(fileassistant) is not GLFileAssistant:
- raise TypeError('fileassistant must be a GLFileAssistant, not %s'
- % type(fileassistant).__name__)
if type(toplevel) is not bool:
raise TypeError('toplevel must be a bool, not %s'
% type(toplevel).__name__)
@@ -139,6 +132,7 @@ class GLEmiter(object):
auxdir = self.config['auxdir']
libtool = self.config['libtool']
include_guard_prefix = self.config['include_guard_prefix']
+ emit = ''
if str(module) in ['gnumakefile', 'maintainer-makefile']:
# These modules are meant to be used only in the top-level directory.
flag = toplevel
@@ -152,18 +146,8 @@ class GLEmiter(object):
for line in snippet.split('\n')
if line.strip() ]
snippet = '%s\n' % '\n'.join(lines)
- transformer = fileassistant.transformers.get('aux', '')
pattern = re.compile('^(.*)$', re.M)
snippet = pattern.sub('%s\\1' % indentation, snippet)
- if transformer:
- args = ['sed', '-e', transformer]
- path = fileassistant.tmpfilename('snippet')
- with codecs.open(path, 'wb', 'UTF-8') as file:
- file.write(snippet)
- stdin = codecs.open(path, 'rb', 'UTF-8')
- snippet = sp.check_output(args, stdin=stdin, shell=False)
- snippet = snippet.decode("UTF-8")
- os.remove(path)
if disable_libtool:
snippet = snippet.replace('$gl_cond_libtool', 'false')
snippet = snippet.replace('gl_libdeps', 'gltests_libdeps')
@@ -181,23 +165,21 @@ class GLEmiter(object):
emit += "LTALLOCA=`echo \"$ALLOCA\" | sed -e 's/\\.[^.]* /.lo /g;s/\\.[^.]*$/.lo/'`\n"
emit += 'changequote([, ])dnl\n'
emit += 'AC_SUBST([LTALLOCA])'
- if replace_auxdir:
- regex = 'AC_CONFIG_FILES\\(\\[(.*)\\:build-aux/(.*)\\]\\)'
- repl = 'AC_CONFIG_FILES([\\1:%s/\\2])' % auxdir
- pattern = re.compile(regex, re.M)
- emit = pattern.sub(repl, emit)
+ if replace_auxdir:
+ regex = 'AC_CONFIG_FILES\\(\\[(.*)\\:build-aux/(.*)\\]\\)'
+ repl = '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 = '%s\n' % '\n'.join(lines)
- emit = constants.nlconvert(emit)
return emit
- def autoconfSnippets(self, modules, moduletable, fileassistant,
+ def autoconfSnippets(self, modules, moduletable,
verifier, toplevel, disable_libtool, disable_gettext, replace_auxdir):
- '''GLEmiter.autoconfSnippets(modules, fileassistant,
- verifier, toplevel, disable_libtool, disable_gettext,
- replace_auxdir) -> str
+ '''GLEmiter.autoconfSnippets(modules,
+ verifier, toplevel, disable_libtool, disable_gettext, replace_auxdir) -> str
Collect and emit the autoconf snippets of a set of modules.
GLConfig: conddeps.
@@ -209,8 +191,6 @@ class GLEmiter(object):
be a GLModule instance.
moduletable is a GLModuleTable instance, which contains necessary
information about dependencies of the modules.
- fileassistant is a GLFileAssistant instance, which is used to get temporary
- directories and sed transformers.
verifier is an integer, which can be 0, 1 or 2.
if verifier == 0, then process every module;
if verifier == 1, then process only non-tests modules;
@@ -229,9 +209,6 @@ class GLEmiter(object):
if type(moduletable) is not GLModuleTable:
raise TypeError('moduletable must be a GLFileAssistant, not %s'
% type(moduletable).__name__)
- if type(fileassistant) is not GLFileAssistant:
- raise TypeError('fileassistant must be a GLFileAssistant, not %s'
- % type(fileassistant).__name__)
if type(verifier) is not int:
raise TypeError('verifier must be an int, not %s'
% type(verifier).__name__)
@@ -262,7 +239,7 @@ class GLEmiter(object):
elif verifier == 2:
solution = module.isTests()
if solution:
- emit += self.autoconfSnippet(module, fileassistant, toplevel,
+ emit += self.autoconfSnippet(module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, ' ')
else: # if conddeps
# Emit the autoconf code for the unconditional modules.
@@ -275,7 +252,7 @@ class GLEmiter(object):
solution = module.isTests()
if solution:
if not moduletable.isConditional(module):
- emit += self.autoconfSnippet(module, fileassistant, toplevel,
+ 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:
@@ -306,7 +283,7 @@ class GLEmiter(object):
emit += ' %s ()\n' % shellfunc
emit += ' {\n'
emit += ' if ! $%s; then\n' % shellvar
- emit += self.autoconfSnippet(module, fileassistant, toplevel,
+ emit += self.autoconfSnippet(module, toplevel,
disable_libtool, disable_gettext, replace_auxdir, ' ')
emit += ' %s=true\n' % shellvar
depmodules = module.getDependenciesWithoutConditions()
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index 0197e0671d..114605dd8a 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -636,7 +636,7 @@ AC_DEFUN([%s_INIT],
emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], [%s])\n' % witness_c_macro
# Emit main autoconf snippets.
emit += self.emiter.autoconfSnippets(moduletable['main'],
- moduletable, assistant, 0, True, False, True, replace_auxdir)
+ moduletable, 0, True, False, True, replace_auxdir)
if witness_c_macro:
emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n'
emit += ' # End of code from modules\n'
@@ -659,7 +659,7 @@ AC_DEFUN([%s_INIT],
emit += '[$gl_module_indicator_condition])\n'
# Emit tests autoconf snippets.
emit += self.emiter.autoconfSnippets(moduletable['tests'],
- moduletable, assistant, 0, True, True, True, replace_auxdir)
+ moduletable, 0, True, True, True, replace_auxdir)
emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n'
emit += self.emiter.initmacro_end('%stests' % macro_prefix)
# _LIBDEPS and _LTLIBDEPS variables are not needed if this library is
diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py
index 746b815b49..3c4ad0b9dc 100644
--- a/pygnulib/GLTestDir.py
+++ b/pygnulib/GLTestDir.py
@@ -496,11 +496,11 @@ class GLTestDir(object):
# those of the tests.
emit += "gl_source_base='../%s'\n" % sourcebase
emit += self.emiter.autoconfSnippets(modules,
- moduletable, self.assistant, 1, False, False, False,
+ moduletable, 1, False, False, False,
replace_auxdir)
emit += "gl_source_base='.'"
emit += self.emiter.autoconfSnippets(modules,
- moduletable, self.assistant, 2, False, False, False,
+ moduletable, 2, False, False, False,
replace_auxdir)
emit += self.emiter.initmacro_end(macro_prefix)
# _LIBDEPS and _LTLIBDEPS variables are not needed if this library is
@@ -614,10 +614,10 @@ class GLTestDir(object):
emit += 'gl_source_base=\'%s\'\n' % sourcebase
if single_configure:
emit += self.emiter.autoconfSnippets(main_modules, moduletable,
- self.assistant, 0, False, False, False, replace_auxdir)
+ 0, False, False, False, replace_auxdir)
else: # if not single_configure
emit += self.emiter.autoconfSnippets(modules, moduletable,
- self.assistant, 1, False, False, False, replace_auxdir)
+ 1, False, False, False, replace_auxdir)
emit += self.emiter.initmacro_end(macro_prefix)
if single_configure:
emit += ' gltests_libdeps=\n'
@@ -631,7 +631,7 @@ class GLTestDir(object):
emit += ' m4_pushdef([gl_MODULE_INDICATOR_CONDITION], '
emit += '[$gl_module_indicator_condition])\n'
snippets = self.emiter.autoconfSnippets(tests_modules, moduletable,
- self.assistant, 1, True, False, False, replace_auxdir)
+ 1, True, False, False, replace_auxdir)
emit += snippets.strip()
emit += ' m4_popdef([gl_MODULE_INDICATOR_CONDITION])\n'
emit += self.emiter.initmacro_end('%stests' % macro_prefix)
--
2.34.1
>From 62fa8fc7b2c9db14d8c24d6ec5beedecb27b4802 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Wed, 10 Aug 2022 00:51:59 +0200
Subject: [PATCH 5/5] gnulib-tool.py: Finish implementing option
--conditional-dependencies.
* gnulib-tool.py (main) Accept options --conditional-dependencies,
--no-conditional-dependencies.
* pygnulib/GLModuleSystem.py (GLModuleTable.addConditional): Use
str(module), not module, as key. Fix logic bug.
(GLModuleTable.getCondition): Simplify.
(GLModuleTable.transitive_closure): Show a warning when there are
duplicate dependencies. Fix logic bug.
(GLModuleTable.transitive_closure_separately): Simplify.
(GLModuleTable.add_dummy): Ignore tests modules. Cope with multiple
lib_SOURCES augmentation lines. Cope with comments at the end of a
lib_SOURCES augmentation line. Add the dummy module at the end of the
modules list.
* pygnulib/GLTestDir.py (GLTestDir.execute): Remove the code that forces
the dummy module to the end of the list.
* pygnulib/GLEmiter.py (GLEmiter.autoconfSnippets): Add code to
terminate the shell functions. Add code for the dependencies from the
unconditional to the conditional modules. Don't emit AM_CONDITIONAL for
unconditional modules.
---
ChangeLog | 20 ++++++++
gnulib-tool.py | 13 ++++-
gnulib-tool.py.TODO | 7 +--
pygnulib/GLEmiter.py | 44 +++++++++++++---
pygnulib/GLImport.py | 3 +-
pygnulib/GLModuleSystem.py | 100 +++++++++++++++++++++++++++----------
pygnulib/GLTestDir.py | 24 +--------
7 files changed, 148 insertions(+), 63 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 642a7363e3..0dfcb7cdd7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2022-08-09 Bruno Haible <[email protected]>
+ gnulib-tool.py: Finish implementing option --conditional-dependencies.
+ * gnulib-tool.py (main) Accept options --conditional-dependencies,
+ --no-conditional-dependencies.
+ * pygnulib/GLModuleSystem.py (GLModuleTable.addConditional): Use
+ str(module), not module, as key. Fix logic bug.
+ (GLModuleTable.getCondition): Simplify.
+ (GLModuleTable.transitive_closure): Show a warning when there are
+ duplicate dependencies. Fix logic bug.
+ (GLModuleTable.transitive_closure_separately): Simplify.
+ (GLModuleTable.add_dummy): Ignore tests modules. Cope with multiple
+ lib_SOURCES augmentation lines. Cope with comments at the end of a
+ lib_SOURCES augmentation line. Add the dummy module at the end of the
+ modules list.
+ * pygnulib/GLTestDir.py (GLTestDir.execute): Remove the code that forces
+ the dummy module to the end of the list.
+ * pygnulib/GLEmiter.py (GLEmiter.autoconfSnippets): Add code to
+ terminate the shell functions. Add code for the dependencies from the
+ unconditional to the conditional modules. Don't emit AM_CONDITIONAL for
+ unconditional modules.
+
gnulib-tool.py: Don't do license replacements in the autoconf snippets.
* pygnulib/GLEmiter.py (GLEmiter.autoconfSnippet): Remove fileassistant
argument. Don't invoke the 'aux' transformer here. Don't produce Windows
diff --git a/gnulib-tool.py b/gnulib-tool.py
index 9988c84de9..71ef1c4f2c 100755
--- a/gnulib-tool.py
+++ b/gnulib-tool.py
@@ -298,6 +298,15 @@ def main():
default=None,
action='append',
nargs=1)
+ # conditional-dependencies
+ parser.add_argument('--conditional-dependencies',
+ dest='cond_dependencies',
+ default=None,
+ action="store_true")
+ parser.add_argument('--no-conditional-dependencies',
+ dest='cond_dependencies',
+ default=None,
+ action="store_false")
# libtool
parser.add_argument('--libtool',
dest='libtool',
@@ -659,6 +668,7 @@ def main():
lgpl = lgpl[-1]
if lgpl == None:
lgpl = True
+ cond_dependencies = cmdargs.cond_dependencies
libtool = cmdargs.libtool
makefile_name = cmdargs.makefile_name
if makefile_name != None:
@@ -682,7 +692,6 @@ def main():
lsymlink = cmdargs.lsymlink == True
single_configure = cmdargs.single_configure
docbase = None
- conddeps = None
# Create pygnulib configuration.
config = classes.GLConfig(
@@ -702,7 +711,7 @@ def main():
lgpl=lgpl,
makefile_name=makefile_name,
libtool=libtool,
- conddeps=conddeps,
+ conddeps=cond_dependencies,
macro_prefix=macro_prefix,
podomain=podomain,
witness_c_macro=witness_c_macro,
diff --git a/gnulib-tool.py.TODO b/gnulib-tool.py.TODO
index be6a2e2b10..da6df2ab90 100644
--- a/gnulib-tool.py.TODO
+++ b/gnulib-tool.py.TODO
@@ -15,15 +15,9 @@ The following commits to gnulib-tool have not yet been reflected in
--------------------------------------------------------------------------------
-Inline all 'sed' invocations.
-
---------------------------------------------------------------------------------
-
Implement the options:
--extract-recursive-dependencies
--extract-recursive-link-directive
- --conditional-dependencies
- --no-conditional-dependencies
--gnu-make
--tests-makefile-name
--automake-subdir
@@ -37,6 +31,7 @@ Remove exit() in GLImport.py.
Optimize:
- os.chdir around subprocess creation -> cwd=... argument instead.
+ - Inline all 'sed' invocations.
--------------------------------------------------------------------------------
diff --git a/pygnulib/GLEmiter.py b/pygnulib/GLEmiter.py
index 9b54d5009e..c0fd053077 100644
--- a/pygnulib/GLEmiter.py
+++ b/pygnulib/GLEmiter.py
@@ -202,7 +202,6 @@ class GLEmiter(object):
AM_GNU_GETTEXT invocations.
replace_auxdir is a bool variable; it tells whether to replace
'build-aux' directory in AC_CONFIG_FILES.'''
- emit = ''
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
@@ -229,6 +228,7 @@ class GLEmiter(object):
auxdir = self.config['auxdir']
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:
@@ -290,7 +290,39 @@ class GLEmiter(object):
# Intersect dependencies with the modules list.
depmodules = [ dep
for dep in depmodules
- if dep in modules ]
+ if dep in modules ] # TODO should this be basemodules or modules?
+ for depmodule in depmodules:
+ if moduletable.isConditional(depmodule):
+ shellfunc = depmodule.getShellFunc()
+ condition = moduletable.getCondition(module, depmodule)
+ if condition != None:
+ emit += ' if %s; then\n' % condition
+ emit += ' %s\n' % shellfunc
+ emit += ' fi\n'
+ else: # if condition == None
+ 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 verifier == 0:
+ solution = True
+ elif verifier == 1:
+ solution = module.isNonTests()
+ elif verifier == 2:
+ solution = module.isTests()
+ if solution:
+ if not moduletable.isConditional(module):
+ depmodules = module.getDependenciesWithoutConditions()
+ # Intersect dependencies with the modules list.
+ depmodules = [ dep
+ for dep in depmodules
+ if dep in modules ] # TODO should this be basemodules or modules?
for depmodule in depmodules:
if moduletable.isConditional(depmodule):
shellfunc = depmodule.getShellFunc()
@@ -316,14 +348,14 @@ class GLEmiter(object):
elif verifier == 2:
solution = module.isTests()
if solution:
- condname = module.getConditionalName()
- shellvar = module.getShellVar()
- emit += ' AM_CONDITIONAL([%s], [$%s])\n' % (condname, shellvar)
+ 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 = '%s\n' % '\n'.join(lines)
- emit = constants.nlconvert(emit)
return emit
def preEarlyMacros(self, require, indentation, modules):
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index 114605dd8a..5dd73fa8bd 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -831,9 +831,10 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix
if libtests:
self.config.setLibtests(True)
- # Add dummy package if it is needed.
+ # Add the dummy module to the main module list if needed.
main_modules = self.moduletable.add_dummy(main_modules)
if libtests: # if we need to use libtests.a
+ # Add the dummy module to the tests-related module list if needed.
tests_modules = self.moduletable.add_dummy(tests_modules)
# Check license incompatibilities.
diff --git a/pygnulib/GLModuleSystem.py b/pygnulib/GLModuleSystem.py
index 9bfd5bd266..f9b47a64a5 100644
--- a/pygnulib/GLModuleSystem.py
+++ b/pygnulib/GLModuleSystem.py
@@ -705,6 +705,18 @@ class GLModuleTable(object):
inc_all_indirect_tests = True if all kinds of problematic unit tests
among the unit tests of the dependencies
should be included
+
+ Methods for conditional dependencies:
+ - addUnconditional(B)
+ notes the presence of B as an unconditional module.
+ - addConditional(A, B. cond)
+ notes the presence of a conditional dependency from module A to module B,
+ subject to the condition that A is enabled and cond is true.
+ - isConditional(B)
+ tests whether module B is conditional.
+ - getCondition(A, B)
+ returns the condition when B should be enabled as a dependency of A,
+ once the m4 code for A has been executed.
'''
self.dependers = dict() # Dependencies
self.conditionals = dict() # Conditional modules
@@ -765,9 +777,11 @@ class GLModuleTable(object):
raise TypeError('condition must be a string or True, not %s'
% type(condition).__name__)
if not str(module) in self.unconditionals:
+ # No unconditional dependency to the given module is known at this point.
if str(module) not in self.dependers:
- self.dependers[module] = list()
- self.dependers[module] += [module]
+ self.dependers[str(module)] = list()
+ if str(parent) not in self.dependers[str(module)]:
+ self.dependers[str(module)].append(str(parent))
key = '%s---%s' % (str(parent), str(module))
self.conditionals[key] = condition
@@ -778,9 +792,9 @@ class GLModuleTable(object):
if type(module) is not GLModule:
raise TypeError('module must be a GLModule, not %s'
% type(module).__name__)
+ self.unconditionals[str(module)] = True
if str(module) in self.dependers:
self.dependers.pop(str(module))
- self.unconditionals[str(module)] = True
def isConditional(self, module):
'''GLModuleTable.isConditional(module) -> bool
@@ -804,9 +818,7 @@ class GLModuleTable(object):
raise TypeError('module must be a GLModule, not %s'
% type(module).__name__)
key = '%s---%s' % (str(parent), str(module))
- result = None
- if key in self.conditionals:
- result = self.conditionals[key]
+ result = self.conditionals.get(key, None)
return result
def transitive_closure(self, modules):
@@ -823,6 +835,11 @@ class GLModuleTable(object):
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
+ # In order to process every module only once (for speed), process an
+ # "input list" of modules, producing an "output list" of modules. During
+ # each round, more modules can be queued in the input list. Once a
+ # module on the input list has been processed, it is added to the
+ # "handled list", so we can avoid to process it again.
inc_all_tests = self.inc_all_direct_tests
handledmodules = list()
inmodules = modules
@@ -833,7 +850,7 @@ class GLModuleTable(object):
self.addUnconditional(module)
while inmodules:
inmodules_this_round = inmodules
- inmodules = list()
+ inmodules = list() # Accumulator, queue for next round
for module in inmodules_this_round:
if module not in self.avoids:
outmodules += [module]
@@ -842,6 +859,13 @@ class GLModuleTable(object):
module.getAutomakeSnippet_Conditional()
pattern = re.compile('^if', re.M)
if not pattern.findall(automake_snippet):
+ # 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
+ # configure: error: conditional "..." was never defined.
+ # because automake 1.11.1 does not handle nested
+ # conditionals correctly. As a workaround, make the
+ # module unconditional.
self.addUnconditional(module)
conditional = self.isConditional(module)
dependencies = module.getDependenciesWithConditions()
@@ -849,6 +873,16 @@ class GLModuleTable(object):
for pair in dependencies ]
conditions = [ pair[1]
for pair in dependencies ]
+ # Duplicate dependencies are harmless, but Jim wants a warning.
+ duplicate_depmodules = [ depmodule
+ for depmodule in set(depmodules)
+ if depmodules.count(depmodule) > 1 ]
+ if duplicate_depmodules:
+ duplicate_depmodule_names = [ str(depmodule)
+ for depmodule in duplicate_depmodules ]
+ message = ('gnulib-tool: warning: module %s has duplicated dependencies: %s\n'
+ % (module, duplicate_depmodule_names))
+ sys.stderr.write(message)
if self.config.checkInclTestCategory(TESTS['tests']):
testsname = module.getTestsName()
if self.modulesystem.exists(testsname):
@@ -856,6 +890,7 @@ class GLModuleTable(object):
depmodules += [testsmodule]
conditions += [None]
for depmodule in depmodules:
+ # Determine whether to include the dependency or tests module.
include = True
statuses = depmodule.getStatuses()
for word in statuses:
@@ -890,15 +925,15 @@ class GLModuleTable(object):
if self.config['conddeps']:
index = depmodules.index(depmodule)
condition = conditions[index]
+ if condition == True:
+ condition = None
if condition:
self.addConditional(module, depmodule, condition)
else: # if condition
if conditional:
self.addConditional(module, depmodule, True)
else: # if not conditional
- self.addUnconditional(module)
- listing = list() # Create empty list
- inmodules = sorted(set(inmodules))
+ self.addUnconditional(depmodule)
handledmodules = sorted(set(handledmodules + inmodules_this_round))
# Remove handledmodules from inmodules.
inmodules = [module
@@ -934,17 +969,24 @@ class GLModuleTable(object):
for module in finalmodules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
+ # Determine main module list.
saved_inctests = self.config.checkInclTestCategory(TESTS['tests'])
self.config.disableInclTestCategory(TESTS['tests'])
main_modules = self.transitive_closure(basemodules)
self.config.setInclTestCategory(TESTS['tests'], saved_inctests)
+ # Determine tests-related module list.
tests_modules = \
[ m
for m in finalmodules
- if m not in main_modules ] \
- + [ m
- for m in main_modules
- if m.getApplicability() != 'main' ]
+ if not (m in main_modules and m.getApplicability() == 'main') ]
+ # Note: Since main_modules is (hopefully) a subset of finalmodules, this
+ # ought to be the same as
+ # [ m
+ # for m in finalmodules
+ # if m not in main_modules ] \
+ # + [ m
+ # for m in main_modules
+ # if m.getApplicability() != 'main' ]
tests_modules = sorted(set(tests_modules))
result = tuple([main_modules, tests_modules])
return result
@@ -957,24 +999,30 @@ class GLModuleTable(object):
GLConfig: auxdir, ac_version.'''
auxdir = self.config['auxdir']
ac_version = self.config['ac_version']
- have_lib_sources = False
for module in modules:
if type(module) is not GLModule:
raise TypeError('each module must be a GLModule instance')
- snippet = module.getAutomakeSnippet()
- snippet = constants.remove_backslash_newline(snippet)
- pattern = re.compile('^lib_SOURCES[\t ]*\\+=[\t ]*(.*)$', re.M)
- files = pattern.findall(snippet)
- if files: # if source files were found
- files = files[-1].split(' ')
- for file in files:
- if not file.endswith('.h'):
- have_lib_sources = True
- break
+ # Determine whether any module provides a lib_SOURCES augmentation.
+ have_lib_sources = False
+ for module in modules:
+ if not module.isTests():
+ snippet = module.getAutomakeSnippet()
+ # Extract the value of "lib_SOURCES += ...".
+ snippet = constants.remove_backslash_newline(snippet)
+ pattern = re.compile('^lib_SOURCES[\t ]*\\+=([^#]*).*$', re.M)
+ for matching_rhs in pattern.findall(snippet):
+ files = matching_rhs.split(' ')
+ for file in files:
+ # Ignore .h files since they are not compiled.
+ if not file.endswith('.h'):
+ have_lib_sources = True
+ break
+ # Add the dummy module, to make sure the library will be non-empty.
if not have_lib_sources:
dummy = self.modulesystem.find('dummy')
if dummy not in self.avoids:
- modules = sorted(set(modules + [dummy]))
+ if dummy not in modules:
+ modules = sorted(set(modules)) + [dummy]
return list(modules)
def filelist(self, modules):
diff --git a/pygnulib/GLTestDir.py b/pygnulib/GLTestDir.py
index 3c4ad0b9dc..bf00099283 100644
--- a/pygnulib/GLTestDir.py
+++ b/pygnulib/GLTestDir.py
@@ -265,33 +265,13 @@ class GLTestDir(object):
self.config.setLibtests(True)
if single_configure:
- # Add dummy package if it is needed.
+ # Add the dummy module to the main module list if needed.
main_modules = moduletable.add_dummy(main_modules)
- if 'dummy' in [ str(module)
- for module in main_modules ]:
- main_modules = [ m
- for m in main_modules
- if str(m) != 'dummy' ]
- dummy = self.modulesystem.find('dummy')
- main_modules = sorted(set(main_modules)) + [dummy]
if libtests: # if we need to use libtests.a
+ # Add the dummy module to the tests-related module list if needed.
tests_modules = moduletable.add_dummy(tests_modules)
- if 'dummy' in [ str(module)
- for module in tests_modules ]:
- tests_modules = [ m
- for m in tests_modules
- if str(m) != 'dummy' ]
- dummy = self.modulesystem.find('dummy')
- tests_modules = sorted(set(tests_modules)) + [dummy]
else: # if not single_configure
modules = moduletable.add_dummy(modules)
- if 'dummy' in [ str(module)
- for module in modules ]:
- modules = [ m
- for m in modules
- if str(m) != 'dummy' ]
- dummy = self.modulesystem.find('dummy')
- modules = sorted(set(modules)) + [dummy]
# Show banner notice of every module.
if single_configure:
--
2.34.1