Hi Bruno,

On 3/19/24 2:23 AM, Bruno Haible wrote:
> One point needs attention, still: In gnulib-tool.sh the code looks at
> configure.ac and, if that does not exist, at configure.in:
> 
>     # Prefer configure.ac to configure.in.
>     if test -f "$destdir"/configure.ac; then
>       configure_ac="$destdir/configure.ac"
>     else
>       if test -f "$destdir"/configure.in; then
>         configure_ac="$destdir/configure.in"
>       else
>         func_fatal_error "cannot find $destdir/configure.ac - make sure you 
> run gnulib-tool from within your package's directory"
>       fi
>     fi
> 
> Whereas in main.py configure.in is not looked at:
> 
>         # Analyze configure.ac.
>         with open(joinpath(destdir, 'configure.ac'), 'r', encoding='utf-8') 
> as file:
>             configure_ac_data = file.read()

Sorry it took me a while to get around to doing this. I got caught up
fixing the other issues. In many of the test cases:

$ diff -u ./test-oath-toolkit-5.result/pskctool/gl/m4/gnulib-comp.m4 
tmp101056-result/pskctool/gl/m4/gnulib-comp.m4
--- ./test-oath-toolkit-5.result/pskctool/gl/m4/gnulib-comp.m4  2024-03-24 
03:30:48.602074864 -0700
+++ tmp101056-result/pskctool/gl/m4/gnulib-comp.m4      2024-03-25 
18:21:57.480903863 -0700
@@ -28,7 +28,7 @@
 # other built files.
 
 
-# This macro should be invoked from ./configure.ac, in the section
+# This macro should be invoked from configure.ac, in the section
 # "Checks for programs", right after AC_PROG_CC, and certainly before
 # any checks for libraries, header files, types and library functions.
 AC_DEFUN([gl_EARLY],
@@ -122,7 +122,7 @@
   # Code from module xalloc-oversized:
 ])
 
-# This macro should be invoked from ./configure.ac, in the section
+# This macro should be invoked from configure.ac, in the section
 # "Check for header files, types and library functions".
 AC_DEFUN([gl_INIT],
 [

This could be solved by joinpath -> os.path.join, but I felt it was a
good time to fix the configure.ac/configure.in issue. Kill two birds
with one stone.

I've also moved the AC_CONFIG_AUX_DIR, A[CM]_PROG_LIBTOOL,
AC_CONFIG_MACRO_DIR, and AC_CONFIG_MACRO_DIRS to main.py, with some
necessary renaming/reordering.

For testing I just created a testdir and put the 'subdir-objects' in
configure.ac and then moved it to Makefile.am. That should be enough
to make sure I didn't accidentally add any unbound variables or
anything.

I'm not sure if you want to add a test case which uses configure.in.
Maybe just checking on clisp or something would be enough?

Collin
From ee1f493fb1c364c232b8d1e0aab194c1cf5dc347 Mon Sep 17 00:00:00 2001
From: Collin Funk <collin.fu...@gmail.com>
Date: Mon, 25 Mar 2024 16:49:58 -0700
Subject: [PATCH] gnulib-tool.py: Only process configure.ac once.

* pygnulib/GLConfig.py (GLConfig.setAutoconfFile): Don't combine the
path with destdir, accept it as given.
* pygnulib/GLImport.py (GLImport.__init__): Don't check
AC_CONFIG_AUX_DIR, A[CM]_PROG_LIBTOOL, AC_PREREQ, and for Automake
'subdir-objects' here since it can happen multiple times.
* pygnulib/main.py (main): Perform the checks here once. Check for both
configure.ac and configure.in, preferring configure.ac. Fix spacing in
error message.
---
 ChangeLog            |  12 +++++
 pygnulib/GLConfig.py |   3 +-
 pygnulib/GLImport.py |  61 -------------------------
 pygnulib/main.py     | 104 +++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 113 insertions(+), 67 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 39d8dd5d60..d72b1ebb82 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2024-03-25  Collin Funk  <collin.fu...@gmail.com>
+
+	gnulib-tool.py: Only process configure.ac once.
+	* pygnulib/GLConfig.py (GLConfig.setAutoconfFile): Don't combine the
+	path with destdir, accept it as given.
+	* pygnulib/GLImport.py (GLImport.__init__): Don't check
+	AC_CONFIG_AUX_DIR, A[CM]_PROG_LIBTOOL, AC_PREREQ, and for Automake
+	'subdir-objects' here since it can happen multiple times.
+	* pygnulib/main.py (main): Perform the checks here once. Check for both
+	configure.ac and configure.in, preferring configure.ac. Fix spacing in
+	error message.
+
 2024-03-25  Bruno Haible  <br...@clisp.org>
 
 	gnulib-tool.py: Print "executing mkdir ..." messages.
diff --git a/pygnulib/GLConfig.py b/pygnulib/GLConfig.py
index b95d2dd613..6d67efea08 100644
--- a/pygnulib/GLConfig.py
+++ b/pygnulib/GLConfig.py
@@ -1006,8 +1006,7 @@ class GLConfig(object):
         '''Specify path of autoconf file relative to destdir.'''
         if type(configure_ac) is str:
             if configure_ac:
-                self.table['configure_ac'] = \
-                    os.path.join(self.table['destdir'], configure_ac)
+                self.table['configure_ac'] = configure_ac
         else:  # if type of configure_ac is not str
             raise TypeError('configure_ac must be a string, not %s'
                             % type(configure_ac).__name__)
diff --git a/pygnulib/GLImport.py b/pygnulib/GLImport.py
index 1a45776f4f..ad458171ec 100644
--- a/pygnulib/GLImport.py
+++ b/pygnulib/GLImport.py
@@ -87,36 +87,6 @@ class GLImport(object):
         self.config = config.copy()
         os.rmdir(self.cache['tempdir'])
 
-        # Get cached auxdir and libtool from configure.ac/in.
-        self.cache.setAuxDir('.')
-        path = joinpath(self.config['destdir'], 'configure.ac')
-        if not isfile(path):
-            path = joinpath(self.config['destdir'], 'configure.in')
-            if not isfile(path):
-                raise GLError(3, path)
-        self.config.setAutoconfFile(path)
-        with codecs.open(path, 'rb', 'UTF-8') as file:
-            data = file.read()
-        pattern = re.compile(r'^AC_CONFIG_AUX_DIR\((.*)\)$', re.M)
-        match = pattern.findall(data)
-        if match:
-            result = cleaner(match)[0]
-            self.cache.setAuxDir(joinpath(self.config['destdir'], result))
-        pattern = re.compile(r'A[CM]_PROG_LIBTOOL', re.M)
-        guessed_libtool = bool(pattern.findall(data))
-        if self.config['auxdir'] == None:
-            self.config.setAuxDir(self.cache['auxdir'])
-
-        # Guess autoconf version.
-        pattern = re.compile(r'.*AC_PREREQ\((.*)\)', re.M)
-        versions = cleaner(pattern.findall(data))
-        if versions:
-            version = sorted(set([ float(version)
-                                   for version in versions ]))[-1]
-            self.config.setAutoconfVersion(version)
-            if version < 2.64:
-                raise GLError(4, version)
-
         # Get other cached variables.
         path = joinpath(self.config['m4base'], 'gnulib-cache.m4')
         if isfile(joinpath(self.config['m4base'], 'gnulib-cache.m4')):
@@ -260,37 +230,6 @@ class GLImport(object):
                     self.config.update_key(config, key)
             self.config.setModules(modules)
 
-        # Determine whether --automake-subdir/--automake-subdir-tests are supported.
-        if self.config['automake_subdir'] or self.config['automake_subdir_tests']:
-            found_subdir_objects = False
-            if self.config['destdir']:
-                with open(self.config['configure_ac'], encoding='utf-8') as file:
-                    data = file.read()
-                pattern = re.compile(r'^.*AM_INIT_AUTOMAKE\([\[ ]*([^\]\)]*).*$', re.MULTILINE)
-                configure_ac_automake_options = pattern.findall(data)
-                if configure_ac_automake_options:
-                    automake_options = { x
-                                         for y in configure_ac_automake_options
-                                         for x in y.split() }
-                    found_subdir_objects = 'subdir-objects' in automake_options
-            if not found_subdir_objects:
-                if self.config['destdir']:
-                    base = self.config['destdir']
-                else:
-                    base = '.'
-                if isfile(joinpath(base, 'Makefile.am')):
-                    with open(joinpath(base, 'Makefile.am'), encoding='utf-8') as file:
-                        data = file.read()
-                    pattern = re.compile(r'^AUTOMAKE_OPTIONS[\t ]*=(.*)$', re.MULTILINE)
-                    automake_options = pattern.findall(data)
-                    if automake_options:
-                        automake_options = { x
-                                             for y in automake_options
-                                             for x in y.split() }
-                        found_subdir_objects = 'subdir-objects' in automake_options
-            if not found_subdir_objects:
-                raise GLError(21, None)
-
         # Define GLImport attributes.
         self.emitter = GLEmiter(self.config)
         self.filesystem = GLFileSystem(self.config)
diff --git a/pygnulib/main.py b/pygnulib/main.py
index c83612d91f..a697c27f2d 100644
--- a/pygnulib/main.py
+++ b/pygnulib/main.py
@@ -722,6 +722,8 @@ def main():
     testsbase = cmdargs.testsbase
     if testsbase != None:
         testsbase = cmdargs.testsbase[0]
+    automake_subdir = cmdargs.automake_subdir == True
+    automake_subdir_tests = cmdargs.automake_subdir_tests == True
     dryrun = cmdargs.dryrun
     verbose = -cmdargs.quiet + cmdargs.verbose
     inctests = cmdargs.inctests
@@ -731,6 +733,71 @@ def main():
             inctests = False
         elif mode in ['create-testdir', 'create-megatestdir', 'test', 'megatest']:
             inctests = True
+    # Now the only possible values of "$inctests" are true and false
+    # (or blank but then it is irrelevant).
+
+    # Determine the minimum supported autoconf version from the project's
+    # configure.ac.
+    configure_ac = ''
+    autoconf_minversion = None
+    if mode in ['import', 'add-import', 'remove-import', 'update'] and destdir != None:
+        if isfile(os.path.join(destdir, 'configure.ac')):
+            configure_ac = os.path.join(destdir, 'configure.ac')
+        elif isfile(os.path.join(destdir, 'configure.in')):
+            configure_ac = os.path.join(destdir, 'configure.in')
+    else:
+        if isfile('configure.ac'):
+            configure_ac = 'configure.ac'
+        elif isfile('configure.in'):
+            configure_ac = 'configure.in'
+    if configure_ac != '':
+        # Use sed, not autoconf --trace, to look for the AC_PREREQ invocation,
+        # because when some m4 files are omitted from a version control repository,
+        # "autoconf --trace=AC_PREREQ" fails with an error message like this:
+        #   m4: aclocal.m4:851: Cannot open m4/absolute-header.m4: No such file or directory
+        #   autom4te: m4 failed with exit status: 1
+        with open(configure_ac, 'r', encoding='utf-8') as file:
+            configure_ac_data = file.read()
+        pattern = re.compile(r'^.*AC_PREREQ\([\[ ]*([^\]\)]*).*$', re.MULTILINE)
+        autoconf_minversion = pattern.search(configure_ac_data)
+        if autoconf_minversion:
+            autoconf_minversion = float(autoconf_minversion.group(1))
+    if autoconf_minversion == None:
+        autoconf_minversion = constants.DEFAULT_AUTOCONF_MINVERSION
+    if autoconf_minversion < 2.64:
+        raise classes.GLError(4, autoconf_minversion)
+
+    # Determine whether --automake-subdir/--automake-subdir-tests are supported.
+    if automake_subdir or automake_subdir_tests:
+        found_subdir_objects = False
+        if configure_ac != '':
+            with open(configure_ac, 'r', encoding='utf-8') as file:
+                data = file.read()
+            pattern = re.compile(r'^.*AM_INIT_AUTOMAKE\([\[ ]*([^\]\)]*).*$', re.MULTILINE)
+            configure_ac_automake_options = pattern.findall(data)
+            if configure_ac_automake_options:
+                automake_options = { x
+                                     for y in configure_ac_automake_options
+                                     for x in y.split() }
+                found_subdir_objects = 'subdir-objects' in automake_options
+        if not found_subdir_objects:
+            if destdir == None:
+                makefile_am = 'Makefile.am'
+            else:
+                makefile_am = os.path.join(destdir, 'Makefile.am')
+            if isfile(makefile_am):
+                with open(makefile_am, 'r', encoding='utf-8') as file:
+                    data = file.read()
+                pattern = re.compile(r'^AUTOMAKE_OPTIONS[\t ]*=(.*)$', re.MULTILINE)
+                automake_options = pattern.findall(data)
+                if automake_options:
+                    automake_options = { x
+                                         for y in automake_options
+                                         for x in y.split() }
+                    found_subdir_objects = 'subdir-objects' in automake_options
+        if not found_subdir_objects:
+            raise classes.GLError(21, None)
+
     incl_test_categories = []
     if inctests:
         incl_test_categories += [constants.TESTS['tests']]
@@ -769,8 +836,6 @@ def main():
     tests_makefile_name = cmdargs.tests_makefile_name
     if tests_makefile_name != None:
         tests_makefile_name = tests_makefile_name[0]
-    automake_subdir = cmdargs.automake_subdir == True
-    automake_subdir_tests = cmdargs.automake_subdir_tests == True
     macro_prefix = cmdargs.macro_prefix
     if macro_prefix != None:
         macro_prefix = macro_prefix[0]
@@ -886,10 +951,41 @@ def main():
             destdir = '.'
         config.setDestDir(destdir)
 
+        # Prefer configure.ac to configure.in.
+        # Use os.path.join instead of joinpath to preserve './' printed in gnulib-comp.m4.
+        if isfile(os.path.join(destdir, 'configure.ac')):
+            configure_ac = os.path.join(destdir, 'configure.ac')
+        elif isfile(os.path.join(destdir, 'configure.in')):
+            configure_ac = os.path.join(destdir, 'configure.in')
+        else:
+            raise classes.GLError(3, os.path.join(destdir, 'configure.ac'))
+
+        # Set the configure.ac file for each GLImport.
+        config.setAutoconfFile(configure_ac)
+
         # Analyze configure.ac.
-        with open(joinpath(destdir, 'configure.ac'), 'r', encoding='utf-8') as file:
+        with open(configure_ac, 'r', encoding='utf-8') as file:
             configure_ac_data = file.read()
 
+        # Guess the auxdir.
+        pattern = re.compile(r'^.*AC_CONFIG_AUX_DIR\([\[ ]*([^\]"\$`\\\)]*).*$', re.MULTILINE)
+        guessed_auxdir = pattern.search(configure_ac_data)
+        if guessed_auxdir:
+            auxdir = guessed_auxdir.group(1)
+        else:
+            auxdir = '.'
+
+        # # Set the build-aux directory for each GLImport.
+        config.setAuxDir(auxdir)
+
+        # Guess if libtool is used.
+        pattern = re.compile(r'A[CM]_PROG_LIBTOOL', re.MULTILINE)
+        guessed_libtool = bool(pattern.search(configure_ac))
+
+        # Set whether we use libtool for each GLImport.
+        config.setLibtool(guessed_libtool)
+
+        # Guess the m4dirs.
         guessed_m4dirs = []
         pattern = re.compile(r'^.*AC_CONFIG_MACRO_DIRS?\([\[ ]*([^\]"\$`\\\)]*).*$', re.MULTILINE)
         match = pattern.findall(configure_ac_data)
@@ -1363,7 +1459,7 @@ if __name__ == '__main__':
                 message += 'cannot find %s - make sure you run gnulib-tool from within your package\'s directory' % errinfo
             elif errno == 4:
                 message += 'minimum supported autoconf version is 2.64. Try adding'
-                message += 'AC_PREREQ([%s])' % constants.DEFAULT_AUTOCONF_MINVERSION
+                message += ' AC_PREREQ([%s])' % constants.DEFAULT_AUTOCONF_MINVERSION
                 message += ' to your configure.ac.'
             elif errno == 5:
                 message += '%s is expected to contain gl_M4_BASE([%s])' % (repr(os.path.join(errinfo, 'gnulib-comp.m4')), repr(errinfo))
-- 
2.44.0

Reply via email to