Hi Peter, others,

* Ralf Wildenhues wrote on Wed, May 11, 2005 at 04:59:33PM CEST:
> * Peter O'Gorman wrote on Wed, May 11, 2005 at 04:33:52PM CEST:
> > Ralf Wildenhues wrote:
> 
> > | My patches break one assumption held in libtool so far:  that --dry-run
> > | will cause no file changes.
> > 
> > I understand your reasons for breaking this, but it freaks me out a little
> > bit.
> 
> Why?

How may I convince you?

> > Have you reported the quadratic behavior to the bash maintainers?
> > We need to file bugs with them about this too.
> 
> No, but I will do so.  It's not just bash, however, but virtually any
> shell I could find.

Done: http://lists.gnu.org/archive/html/bug-bash/2005-05/msg00611.html

> > Note that some of your FIXMEs in the patches below are in my opinion
> > not needed, if libtool got the argument list and -objectlist was not
> > used then the kernel limit was not exceeded and $ECHO is fine.
> 
> Oh yes, you are right.  I started adding these mechanically to all
> dependent variables instead of only the ones where the object list gets
> expanded.  Will post an updated patch.

Here's a list of updated patches.  Changes to previous proposed patches:

- bugfix: in rename, we need to conserve the leading space in `$oldobjs'.
- reword doubled status output about reloadable output.
- output rename status output with func_echo for `libtool: link:' prefix.
- Remove all irrelevant FIXMEs as pointed out by Peter.
- New m4 macro OUTPUT_LONG_LIST:
It may be used to output a list which may be longer than the command
line limit.  It is fast for the good cases (either builtin $ECHO and/or
command line shorter than limit), and gets pretty slow for the worst
case.  I chose a macro as a cheap `inline' rather than a shell function
for this because the shell function call uses a significant amount of
time (in the fast case, obviously :).  If the resulting about 1% size
increase of `libtool' bugs anyone, we can change this.  This macro is
used to fix all the relevant FIXMEs added in the previous proposed
patches.

Right now, OUTPUT_LONG_LIST is defined right in ltmain.m4sh, which is
probably against Libtool macro definition policies.  Where should it go?
If outside of ltmain.m4sh, it would probably need to be namespace-clean..

Outstanding issues:
- As of now, each user of OUTPUT_LONG_LIST creates a separate scratch
  file within our scratch directory, for testing purposes.
- What to do for MinGW which does not have all necessary tools?  Keep
  the old renaming loop as a workaround in that case?
- A good testsuite test will now really have to exceed the system
  command line length.
- No error checking for write failures (full disk, etc.).  I actually
  don't know whether it can be done portably in shell code without much
  hassle.  Does anybody think this is worthwhile/necessary to pursue?
- I don't know how to implement OUTPUT_LONG_LIST without a temp file.
  This is a question to think of for an eventual branch-2-0 backport of
  the fixme patch, in case you disapprove of temp files for it.

The ranlib change will be in another patch and mail.

OK to apply this to HEAD?

Regards,
Ralf
        * m4/libtool.m4 (_LT_CHECK_POSIX_SORT, _LT_CHECK_READ_R): New macros to
        test sort(1) and read variations, define and use $posix_sort, $read_r.
        (_LT_SETUP): m4_require them.
        * config/ltmain.m4sh (func_generate_dlsyms): Use $posix_sort.

--- m4/libtool.m4       2005-04-29 20:17:22.000000000 +0200
+++ m4/libtool.m4       2005-05-09 20:41:10.000000000 +0200
@@ -134,6 +134,8 @@
 _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
 dnl
 m4_require([_LT_CHECK_XSI_SHELL])dnl
+m4_require([_LT_CHECK_POSIX_SORT])dnl
+m4_require([_LT_CHECK_READ_R])dnl
 m4_require([_LT_CMD_RELOAD])dnl
 m4_require([_LT_CHECK_MAGIC_METHOD])dnl
 m4_require([_LT_CMD_OLD_ARCHIVE])dnl
@@ -6238,3 +6308,28 @@
 _LT_EOF
 esac
 ])
+
+# _LT_CHECK_POSIX_SORT
+# --------------------
+# Whether sort(1) uses -kCOL or +COLM1, where COLM1 = COL - 1.
+m4_defun([_LT_CHECK_POSIX_SORT],
+[if sort -k3 </dev/null >/dev/null 2>&1; then
+  posix_sort=:
+else
+  posix_sort=false
+fi
+_LT_DECL([], posix_sort, 1, [Whether sort(1) understands "-k"])
+])# _LT_CHECK_POSIX_SORT
+
+# _LT_CHECK_READ_R
+# --------------------
+# Try to find out whether read understands "-r"
+m4_defun([_LT_CHECK_READ_R],
+[if echo bt | tr b '\\' | { read -r line; test "X$line" = 'X\t'; } 2>/dev/null
+then
+  read_r='read -r'
+else
+  read_r=read
+fi
+_LT_DECL([], read_r, 1, [read -r])
+])# _LT_CHECK_READ_R
--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -850,11 +850,7 @@
 
          # Try sorting and uniquifying the output.
          if $GREP -v "^: " < "$nlist" |
-             if sort -k 3 </dev/null >/dev/null 2>&1; then
-               sort -k 3
-             else
-               sort +2
-             fi |
+             if $posix_sort; then sort -k 3; else sort +2; fi |
              uniq > "$nlist"S; then
            :
          else
        * config/ltmain.m4sh (OUTPUT_LONG_LIST): New macro to output
        lists which may exceed the command line length.
        (func_mode_link): Use OUTPUT_LONG_LIST.

Index: config/ltmain.m4sh
===================================================================
RCS file: /cvsroot/libtool/libtool/config/ltmain.m4sh,v
retrieving revision 1.66
diff -u -r1.66 ltmain.m4sh
--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -2143,6 +2139,30 @@
 }
 
 
+dnl OUTPUT_LONG_LIST(LIST, TEMPFILE, [SEDSCRIPT])
+dnl ---------------------------------------------
+dnl Output LIST, which may be longer than the command line length,
+dnl one item per line.  LIST should be a whitespace-separates list.
+dnl Leading, trailing, and multiple spaces will be removed.
+dnl Optional post-processing may be done with SEDSCRIPT.
+dnl This macro may need to use TEMPFILE as a temporary scratch space.
+dnl The output is on STDOUT by default and may be redirected.
+dnl May be used within backquotes, but not double-quoted backquotes.
+dnl This macro is fast with a builtin $ECHO and/or a short list.
+dnl
+m4_define([OUTPUT_LONG_LIST],
+[if $ECHO "X$1" >$2 2>/dev/null
+then 
+  $SP2NL <$2 | $Xsed -e '/^$/d' m4_if([$3],,, [-e $3])
+else
+dnl You will appreciate the minutes spent in this loop..
+  for tmp_elem in $1
+  do
+    $ECHO "X$tmp_elem"
+  done | $SED -e 's/^X//' m4_if([$3],,, [-e $3])
+fi])dnl
+
+
 # func_mode_link arg...
 func_mode_link ()
 {
@@ -4484,7 +4538,8 @@
        oldlibs="$oldlibs $output_objdir/$libname.$libext"
 
        # Transform .lo files to .o files.
-       oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e 
'/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+       oldobjs="$objs "`OUTPUT_LONG_LIST([$libobjs], 
["$always_gentop/scratch1"],
+                                         ["/\\.${libext}\$/d;$lo2o"]) | $NL2SP`
       fi
 
       # Eliminate all temporary directories.
@@ -4977,7 +5032,10 @@
        done
 
        # Use standard objects if they are pic
-       test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e 
"$lo2o" | $NL2SP`
+       test -z "$pic_flag" && {
+         libobjs=`OUTPUT_LONG_LIST([$libobjs], ["$always_gentop/scratch2"],
+                                   ["$lo2o"]) | $NL2SP`
+       }
 
        # Prepare the list of exported symbols
        if test -z "$export_symbols"; then
@@ -5346,8 +5397,10 @@
       fi
 
       # Create the old-style object.
-      reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e 
'/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### 
testsuite: skip nested quoting test
-
+      reload_objs="$objs$old_deplibs "`OUTPUT_LONG_LIST(
+                       [$libobjs],
+                       ["$always_gentop/scratch4"],
+                       ["/\\.${libext}\$/d;/\\.lib\$/d;$lo2o"]) | $NL2SP`" 
$reload_conv_objs"
       output="$obj"
       cmds=$reload_cmds
       save_ifs="$IFS"; IFS='~'
        * config/ltmain.m4sh (func_mode_link): Eliminate quadratic
        argument parsing with temp files, keep file descriptors
        (FD_LIBTOOL_ARGS, FD_COMPILE_COMMAND, FD_FINALIZE_COMMAND,
        FD_LIBOBJS, FD_NONPIC_OBJS): New.  Use to avoid repeated reopening.
        Slurp in lists after parsing loop, make sure empty lists stay that way.
        (always_gentop): New variable to hold temp dir for scratch.  Will
        be generated for every --mode=link invocation, also in dry run,
        and deleted upon exit.

diff -ru config/ltmain.m4sh config/ltmain.m4sh
--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -2166,10 +2186,32 @@
       allow_undefined=yes
       ;;
     esac
-    libtool_args="$nonopt"
+    # Use files for long option lists, it avoids quadratic string handling.
+    # We need temp files, though, even in dry run
+    always_gentop=`opt_dry_run=false func_mktempdir`
+    trap "${RM}r \"$always_gentop\"" 0
+m4_define([FD_LIBTOOL_ARGS], [5])dnl
+m4_define([FD_COMPILE_COMMAND], [6])dnl
+m4_define([FD_FINALIZE_COMMAND], [7])dnl
+m4_define([FD_LIBOBJS], [8])dnl
+m4_define([FD_NONPIC_OBJS], [9])dnl
+    libtool_args_file=$always_gentop/libtool_args
+    compile_command_file=$always_gentop/compile_command
+    finalize_command_file=$always_gentop/finalize_command
+    libobjs_file=$always_gentop/libobjs
+    non_pic_objs_file=$always_gentop/non_pic_objs
+    exec FD_LIBTOOL_ARGS>"$libtool_args_file" \
+        FD_COMPILE_COMMAND>"$compile_command_file" \
+        FD_FINALIZE_COMMAND>"$finalize_command_file" \
+        FD_LIBOBJS>"$libobjs_file" \
+        FD_NONPIC_OBJS>"$non_pic_objs_file"
+        
+    $ECHO " " >&FD_LIBOBJS
+    $ECHO " " >&FD_NONPIC_OBJS
+    $ECHO " $nonopt" >&FD_LIBTOOL_ARGS
+    $ECHO " $nonopt" >&FD_COMPILE_COMMAND
+    $ECHO " $nonopt" >&FD_FINALIZE_COMMAND
     base_compile="$nonopt $@"
-    compile_command="$nonopt"
-    finalize_command="$nonopt"
 
     compile_rpath=
     finalize_rpath=
@@ -2194,12 +2236,10 @@
     export_symbols=
     export_symbols_regex=
     generated=
-    libobjs=
     ltlibs=
     module=no
     no_install=no
     objs=
-    non_pic_objects=
     precious_files_regex=
     prefer_static_libs=no
     preload=no
@@ -2235,8 +2275,8 @@
          if test -n "$link_static_flag"; then
            dlopen_self=$dlopen_self_static
            # See comment for -static flag below, for more details.
-           compile_command="$compile_command $link_static_flag"
-           finalize_command="$finalize_command $link_static_flag"
+           $ECHO " $link_static_flag" >&FD_COMPILE_COMMAND
+           $ECHO " $link_static_flag" >&FD_FINALIZE_COMMAND
          fi
        else
          if test -z "$pic_flag" && test -n "$link_static_flag"; then
@@ -2260,14 +2300,14 @@
       shift
       func_quote_for_eval "$arg"
       qarg="$func_quote_for_eval_unquoted_result"
-      libtool_args="$libtool_args $func_quote_for_eval_result"
+      $ECHO " $func_quote_for_eval_result" >&FD_LIBTOOL_ARGS
 
       # If the previous option needs an argument, assign it.
       if test -n "$prev"; then
        case $prev in
        output)
-         compile_command="$compile_command @OUTPUT@"
-         finalize_command="$finalize_command @OUTPUT@"
+         $ECHO " @OUTPUT@" >&FD_COMPILE_COMMAND
+         $ECHO " @OUTPUT@" >&FD_FINALIZE_COMMAND
          ;;
        esac
 
@@ -2275,8 +2315,8 @@
        dlfiles|dlprefiles)
          if test "$preload" = no; then
            # Add the symbol object into the linking commands.
-           compile_command="$compile_command @SYMFILE@"
-           finalize_command="$finalize_command @SYMFILE@"
+           $ECHO " @SYMFILE@" >&FD_COMPILE_COMMAND
+           $ECHO " @SYMFILE@" >&FD_FINALIZE_COMMAND
            preload=yes
          fi
          case $arg in
@@ -2398,7 +2438,7 @@
                  fi
 
                  # A PIC object.
-                 libobjs="$libobjs $pic_object"
+                 $ECHO " $pic_object" >&FD_LIBOBJS
                  arg="$pic_object"
                fi
 
@@ -2408,7 +2448,7 @@
                  non_pic_object="$xdir$non_pic_object"
 
                  # A standard non-PIC object
-                 non_pic_objects="$non_pic_objects $non_pic_object"
+                 $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
                  if test -z "$pic_object" || test "$pic_object" = none ; then
                    arg="$non_pic_object"
                  fi
@@ -2416,7 +2456,7 @@
                  # If the PIC object exists, use it instead.
                  # $xdir was prepended to $pic_object above.
                  non_pic_object="$pic_object"
-                 non_pic_objects="$non_pic_objects $non_pic_object"
+                 $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
                fi
              else
                # Only an error if not doing a dry-run.
@@ -2427,8 +2467,8 @@
 
                  pic_object=`$ECHO "X${xdir}${objdir}/${arg}" | $Xsed -e 
"$lo2o"`
                  non_pic_object=`$ECHO "X${xdir}${arg}" | $Xsed -e "$lo2o"`
-                 libobjs="$libobjs $pic_object"
-                 non_pic_objects="$non_pic_objects $non_pic_object"
+                 $ECHO " $pic_object" >&FD_LIBOBJS
+                 $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
                else
                  func_fatal_error "\`$arg' is not a valid libtool object"
                fi
@@ -2487,23 +2527,23 @@
          linker_flags="$linker_flags $qarg"
          compiler_flags="$compiler_flags $qarg"
          prev=
-         compile_command="$compile_command $qarg"
-         finalize_command="$finalize_command $qarg"
+         $ECHO " $qarg" >&FD_COMPILE_COMMAND
+         $ECHO " $qarg" >&FD_FINALIZE_COMMAND
          continue
          ;;
        xcompiler)
          compiler_flags="$compiler_flags $qarg"
          prev=
-         compile_command="$compile_command $qarg"
-         finalize_command="$finalize_command $qarg"
+         $ECHO " $qarg" >&FD_COMPILE_COMMAND
+         $ECHO " $qarg" >&FD_FINALIZE_COMMAND
          continue
          ;;
        xlinker)
          linker_flags="$linker_flags $qarg"
          compiler_flags="$compiler_flags $wl$qarg"
          prev=
-         compile_command="$compile_command $wl$qarg"
-         finalize_command="$finalize_command $wl$qarg"
+         $ECHO " $wl$qarg" >&FD_COMPILE_COMMAND
+         $ECHO " $wl$qarg" >&FD_FINALIZE_COMMAND
          continue
          ;;
        *)
@@ -2574,8 +2614,8 @@
       -L[[A-Z]][[A-Z]]*:*)
        case $with_gcc/$host in
        no/*-*-irix* | /*-*-irix*)
-         compile_command="$compile_command $arg"
-         finalize_command="$finalize_command $arg"
+         $ECHO " $arg" >&FD_COMPILE_COMMAND
+         $ECHO " $arg" >&FD_FINALIZE_COMMAND
          ;;
        esac
        continue
@@ -2657,17 +2697,17 @@
       # Tru64 UNIX uses -model [arg] to determine the layout of C++
       # classes, name mangling, and exception handling.
       -model)
-       compile_command="$compile_command $arg"
        compiler_flags="$compiler_flags $arg"
-       finalize_command="$finalize_command $arg"
+       $ECHO " $arg" >&FD_COMPILE_COMMAND
+       $ECHO " $arg" >&FD_FINALIZE_COMMAND
        prev=xcompiler
        continue
        ;;
 
       -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe)
        compiler_flags="$compiler_flags $arg"
-       compile_command="$compile_command $arg"
-       finalize_command="$finalize_command $arg"
+       $ECHO " $arg" >&FD_COMPILE_COMMAND
+       $ECHO " $arg" >&FD_FINALIZE_COMMAND
        case "$new_inherited_linker_flags " in
            *" $arg "*) ;;
            * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
@@ -2840,8 +2880,8 @@
       -64|-mips[[0-9]]|-r[[0-9]][[0-9]]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*)
         func_quote_for_eval "$arg"
        arg="$func_quote_for_eval_result"
-        compile_command="$compile_command $arg"
-        finalize_command="$finalize_command $arg"
+        $ECHO " $arg" >&FD_COMPILE_COMMAND
+        $ECHO " $arg" >&FD_FINALIZE_COMMAND
         compiler_flags="$compiler_flags $arg"
         continue
         ;;
@@ -2906,7 +2946,7 @@
            fi
 
            # A PIC object.
-           libobjs="$libobjs $pic_object"
+           $ECHO " $pic_object" >&FD_LIBOBJS
            arg="$pic_object"
          fi
 
@@ -2916,7 +2956,7 @@
            non_pic_object="$xdir$non_pic_object"
 
            # A standard non-PIC object
-           non_pic_objects="$non_pic_objects $non_pic_object"
+           $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
            if test -z "$pic_object" || test "$pic_object" = none ; then
              arg="$non_pic_object"
            fi
@@ -2924,7 +2964,7 @@
            # If the PIC object exists, use it instead.
            # $xdir was prepended to $pic_object above.
            non_pic_object="$pic_object"
-           non_pic_objects="$non_pic_objects $non_pic_object"
+           $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
          fi
        else
          # Only an error if not doing a dry-run.
@@ -2935,8 +2975,8 @@
 
            pic_object=`$ECHO "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
            non_pic_object=`$ECHO "X${xdir}${arg}" | $Xsed -e "$lo2o"`
-           libobjs="$libobjs $pic_object"
-           non_pic_objects="$non_pic_objects $non_pic_object"
+           $ECHO " $pic_object" >&FD_LIBOBJS
+           $ECHO " $non_pic_object" >&FD_NONPIC_OBJS
          else
            func_fatal_error "\`$arg' is not a valid libtool object"
          fi
@@ -2978,11 +3018,25 @@
 
       # Now actually substitute the argument into the commands.
       if test -n "$arg"; then
-       compile_command="$compile_command $arg"
-       finalize_command="$finalize_command $arg"
+       $ECHO " $arg" >&FD_COMPILE_COMMAND
+       $ECHO " $arg" >&FD_FINALIZE_COMMAND
       fi
     done # argument parsing loop
 
+    exec FD_LIBTOOL_ARGS>&- \
+        FD_COMPILE_COMMAND>&- \
+        FD_FINALIZE_COMMAND>&- \
+        FD_LIBOBJS>&- \
+        FD_NONPIC_OBJS>&-
+    libtool_args=`$SED 's/^ //' <"$libtool_args_file" | $NL2SP`
+    compile_command=`$SED 's/^ //' <"$compile_command_file" | $NL2SP`
+    finalize_command=`$SED 's/^ //' <"$finalize_command_file" | $NL2SP`
+    libobjs=`$SED 's/^ //' <"$libobjs_file" | $NL2SP`
+    non_pic_objects=`$SED 's/^ //' <"$non_pic_objs_file" | $NL2SP`
+    # Do not let `test -z' fail:
+    case $libobjs in ' ') libobjs=;; esac
+    case $non_pic_objects in ' ') non_pic_objects=;; esac
+
     test -n "$prev" && \
       func_fatal_help "the \`$prevarg' option requires an argument"
 
        * config/ltmain.m4sh (func_mode_link): Drop `expr: command line too
        long' error.
        (func_mode_link) [ gnu, aix ]: Rewrite ld script creation to avoid
        repeated file opening.
        (func_mode_link): Rewrite partial linking to avoid quadratic
        scaling by use of temp files, fold, split, and OUTPUT_LONG_LIST.

--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -5065,14 +5123,14 @@
          fi
        fi
 
-       if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*"` &&
+       if test "X$skipped_export" != "X:" && len=`expr "X$test_cmds" : ".*" 
2>/dev/null` &&
           test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
          :
        else
          # The command line is too long to link in one step, link piecewise
          # or, if using GNU ld and skipped_export is not :, use a linker
          # script.
-         func_echo "creating reloadable object files..."
+         func_echo "command line too long for linking..."
 
          # Save the value of $output and $libobjs because we want to
          # use them later.  If we have whole_archive_flag_spec, we
@@ -5087,70 +5145,63 @@
          fi
          save_output=$output
          output_la=`$ECHO "X$output" | $Xsed -e "$basename"`
-
-         # Clear the reloadable object creation command queue and
-         # initialize k to one.
-         test_cmds=
-         concat_cmds=
-         objlist=
          delfiles=
-         last_robj=
-         k=1
 
          if test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
            output=${output_objdir}/${output_la}.lnkscript
            func_echo "creating GNU ld script: $output"
-           $ECHO 'INPUT (' > $output
-           for obj in $save_libobjs
-           do
-             $ECHO \""$obj"\" >> $output
-           done
-           $ECHO ')' >> $output
+           ( echo 'INPUT ('
+             OUTPUT_LONG_LIST([$save_libobjs], ["$always_gentop/scratch3"], 
['s/^/"/;s/$/"/'])
+             echo ')'
+           ) >"$output"
            delfiles="$delfiles $output"
          elif test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; 
then
            output=${output_objdir}/${output_la}.lnk
            func_echo "creating linker input file list: $output"
-           : > $output
-           for obj in $save_libobjs
-           do
-             $ECHO "$obj" >> $output
-           done
+           OUTPUT_LONG_LIST([$save_libobjs], ["$always_gentop/scratch3"]) 
>"$output"
            delfiles="$delfiles $output"
-           output=\"$file_list_spec$output\"
+           output="$file_list_spec$output"
          else
            func_echo "creating reloadable object files..."
-           output=$output_objdir/$output_la-${k}.$objext
-           # Loop over the list of objects to be linked.
-           for obj in $save_libobjs
+           # Clear the reloadable object creation command queue and
+           # initialize k to one.
+           concat_cmds=
+           objlist=
+           last_robj=
+           save_libobjs_file=$always_gentop/save_libobjs
+           save_libobjs_base=$always_gentop/save_libobjs_sep
+
+           OUTPUT_LONG_LIST([$save_libobjs],
+                            ["$always_gentop/scratch3"]) >"$save_libobjs_file"
+           eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+           len_netto=`expr "X$test_cmds" : ".*"` \
+               || func_fatal_error "too many arguments in \`reload_cmds'"
+           test "$len_netto" -lt "$max_cmd_len" \
+               || func_fatal_error "too many arguments in \`reload_cmds'"
+           len_allowed=`expr "$max_cmd_len" - "$len_netto"`
+           func_show_eval "${RM} \"$save_libobjs_base\"?*"
+           # `fold' accepts long lines, `split' should too.
+           # We have to split, because `read' is limited to text files.
+           ( $NL2SP <"$save_libobjs_file"; echo ) \
+               | fold -b -s -w "$len_allowed" \
+               | split -l 1 - "$save_libobjs_base"
+           k=0
+           kmax=`( set X "$save_libobjs_base"?*; shift; echo $#)`
+           for objfile in $save_libobjs_base?*
            do
-             eval test_cmds=\"$reload_cmds $objlist $last_robj\"
-             if test "X$objlist" = X ||
-                { len=`expr "X$test_cmds" : ".*"` &&
-                  test "$len" -le "$max_cmd_len"; }; then
-               objlist="$objlist $obj"
+             k=`expr $k + 1`
+             output=$output_objdir/$output_la-${k}.$objext
+             objlist=' '`cat "$objfile"`
+             if test "$k" -eq 1 ; then
+               # The first file doesn't have a previous command to add.
+               eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
              else
-               # The command $test_cmds is almost too long, add a
-               # command to the queue.
-               if test "$k" -eq 1 ; then
-                 # The first file doesn't have a previous command to add.
-                 eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
-               else
-                 # All subsequent reloadable object files will link in
-                 # the last one created.
-                 eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist 
$last_robj\"
-               fi
-               last_robj=$output_objdir/$output_la-${k}.$objext
-               k=`expr $k + 1`
-               output=$output_objdir/$output_la-${k}.$objext
-               objlist=$obj
-               len=1
+               # All subsequent reloadable object files will link in
+               # the last one created.
+               eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist 
$last_robj\"
              fi
+             last_robj=$output
            done
-           # Handle the remaining objects by creating one last
-           # reloadable object file.  All subsequent reloadable object
-           # files will link in the last one created.
-           test -z "$concat_cmds" || concat_cmds=$concat_cmds~
-           eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
 
            if ${skipped_export-false}; then
              func_echo "generating symbol list for \`$libname.la'"
@@ -5164,7 +5215,7 @@
            # Set up a command to remove the reloadable object files
            # after they are used.
            i=0
-           while test "$i" -lt "$k"
+           while test "$i" -lt "$kmax"
            do
              i=`expr $i + 1`
              delfiles="$delfiles $output_objdir/$output_la-${i}.$objext"
        * config/ltmain.m4sh (func_mode_link): Rewrite duplicate object
        name renaming to avoid quadratic scaling by use of temp files,
        paste, join, OUTPUT_LONG_LIST.  Breaks if file names contain newlines
        (and, if `read' does not support `-r', also backslashes).
        Hide `expr: argument list too long' error.

diff -u -r1.66 ltmain.m4sh
--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -6298,47 +6351,45 @@
        # static archive out of a convenience library, or when linking
        # the entirety of a libtool archive into another (currently
        # not supported by libtool).
-       if (for obj in $oldobjs
-           do
-             func_basename "$obj"
-             $ECHO "$func_basename_result"
-           done | sort | sort -uc >/dev/null 2>&1); then
-         :
-       else
+       gentop="$output_objdir/${outputname}x"
+       generated="$generated $gentop"
+       func_mkdir_p "$gentop"
+       objs_bnames=$always_gentop/objs_basenames
+       objs_nonuniq=$always_gentop/objs_nonuniq
+       replace_script=$always_gentop/replace_script
+       objs_file=$always_gentop/objs
+       OUTPUT_LONG_LIST([$oldobjs], ["$always_gentop/scratch6"], 
["$basename"]) >"$objs_bnames"
+       sort "$objs_bnames" | uniq -d > "$objs_nonuniq"
+       if test -s "$objs_nonuniq"
+       then
-         $ECHO "copying selected object files to avoid basename conflicts..."
-         gentop="$output_objdir/${outputname}x"
-         generated="$generated $gentop"
-         func_mkdir_p "$gentop"
-         save_oldobjs=$oldobjs
-         oldobjs=
-         counter=1
-         for obj in $save_oldobjs
+         func_echo "copying selected object files to avoid basename 
conflicts..."
+         : >"$replace_script"
+         # Make sure we use unique names: find highest number currently in use.
+         counter=`$SED -n ['/^lt-[0-9][0-9]*/ { s/^lt-//; s/[^0-9].*//; p; }'] 
"$objs_bnames" \
+                      | sort -n | $SED -n '$p'`
+         OUTPUT_LONG_LIST([$oldobjs], ["$always_gentop/scratch7"]) 
>"$objs_file"
+         # Create a list with: line number, object basename, object name.
+         # Sort it by basename, then pick out all lines corresponding to 
conflicts.
+         # The last sort merely cosmetic.
+         sed = "$objs_bnames" |
+             sed 'N;s/\n/      /' |
+             paste - "$objs_file" |
+             if $posix_sort; then sort -k2; else sort +1; fi |
+             join -1 2 - "$objs_nonuniq" |
+             if $posix_sort; then sort -k2n; else sort -n +1; fi |
+             while $read_r objbase line obj
          do
-           func_basename "$obj"
-           objbase="$func_basename_result"
-           case " $oldobjs " in
-           " ") oldobjs=$obj ;;
-           *[[\ /]]"$objbase "*)
-             while :; do
-               # Make sure we don't pick an alternate name that also
-               # overlaps.
-               newobj=lt$counter-$objbase
-               counter=`expr $counter + 1`
-               case " $oldobjs " in
-               *[[\ /]]"$newobj "*) ;;
-               *) if test ! -f "$gentop/$newobj"; then break; fi ;;
-               esac
-             done
-             func_show_eval "ln $obj $gentop/$newobj || cp $obj 
$gentop/$newobj"
-             oldobjs="$oldobjs $gentop/$newobj"
-             ;;
-           *) oldobjs="$oldobjs $obj" ;;
-           esac
+           counter=`expr $counter + 1`
+           newobj=lt$counter-$objbase
+           func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+           $ECHO "$line c\\
+$gentop/$newobj" >>"$replace_script"
          done
+         oldobjs=' '`$SED -f "$replace_script" "$objs_file" | $NL2SP`
        fi
        eval cmds=\"$old_archive_cmds\"
 
-       if len=`expr "X$cmds" : ".*"` &&
+       if len=`expr "X$cmds" : ".*" 2>/dev/null` &&
             test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
          cmds=$old_archive_cmds
        else
        * config/ltmain.m4sh (func_mode_link): Rewrite piecewise old
        archive linking to avoid quadratic loop.  Makes use of fold, split,
        temp files, and OUTPUT_LONG_LIST.
        * tests/pdemo-conf.test: Adjust for the fact that we require
        $old_archive_cmds with empty list of objects to fit in the command line.

diff -u -r1.66 ltmain.m4sh
--- config/ltmain.m4sh  27 Apr 2005 20:30:38 -0000      1.66
+++ config/ltmain.m4sh  19 May 2005 20:18:50 -0000
@@ -6348,38 +6399,35 @@
          RANLIB=:
          objlist=
          concat_cmds=
-         save_oldobjs=$oldobjs
-         # Is there a better way of finding the last object in the list?
-         for obj in $save_oldobjs
-         do
-           last_oldobj=$obj
-         done
-         for obj in $save_oldobjs
+         OUTPUT_LONG_LIST([$oldobjs], ["$always_gentop/scratch8"]) 
>"$objs_file"
+         oldobjs=
+         objs_split_base=$always_gentop/objs_split
+         eval test_cmds=\"$old_archive_cmds\"
+         len_netto=`expr "X$test_cmds" : ".*"` \
+             || func_fatal_error "too many arguments in \`old_archive_cmds'"
+         test "$len_netto" -lt "$max_cmd_len" \
+             || func_fatal_error "too many arguments in \`old_archive_cmds'"
+         len_allowed=`expr "$max_cmd_len" - "$len_netto"`
+         ${RM} "$objs_split_base"?*
+         # `fold' accepts long lines, `split' should too.
+         # We have to split, because `read' is limited to text files.
+         ( $NL2SP <"$objs_file"; echo ) \
+             | fold -b -s -w "$len_allowed" \
+             | split -l 1 - "$objs_split_base"
+         oldobjs=
+         for objfile in "$objs_split_base"?* last
          do
-           oldobjs="$objlist $obj"
-           objlist="$objlist $obj"
-           eval test_cmds=\"$old_archive_cmds\"
-           if len=`expr "X$test_cmds" : ".*"` &&
-              test "$len" -le "$max_cmd_len"; then
-             :
-           else
-             # the above command should be used before it gets too long
-             oldobjs=$objlist
-             if test "$obj" = "$last_oldobj" ; then
-               RANLIB=$save_RANLIB
-             fi
+           case $objfile in last) RANLIB=$save_RANLIB;; esac
+           case $oldobjs in '') ;;
+             *)
              test -z "$concat_cmds" || concat_cmds=$concat_cmds~
              eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
-             objlist=
-           fi
+             ;;
+           esac
+           case $objfile in last) ;; *) oldobjs=' '`cat "$objfile"`;; esac
          done
-         RANLIB=$save_RANLIB
-         oldobjs=$objlist
-         if test "X$oldobjs" = "X" ; then
-           eval cmds=\"\$concat_cmds\"
-         else
-           eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
-         fi
+
+         eval cmds=\"\$concat_cmds\"
        fi
       fi
       save_ifs="$IFS"; IFS='~'
Index: tests/pdemo-conf.test
===================================================================
RCS file: /cvsroot/libtool/libtool/tests/pdemo-conf.test,v
retrieving revision 1.12
diff -u -r1.12 pdemo-conf.test
--- tests/pdemo-conf.test       22 Apr 2005 10:10:30 -0000      1.12
+++ tests/pdemo-conf.test       6 May 2005 16:59:57 -0000
@@ -30,7 +30,7 @@
 func_check_static_shared "yes" "yes"
 
 if test -f ./libtool ; then
-  sed 's/^max_cmd_len=*/max_cmd_len=24 # /g' ./libtool > ltnew
+  sed 's/^max_cmd_len=*/max_cmd_len=96 # /g' ./libtool > ltnew
 else
   exit 1
 fi

Reply via email to