I came across a section in the Automake manual describing problems with
Makefile rules with multiple outputs.

https://www.gnu.org/software/automake/manual/html_node/Multiple-Outputs.html

We have such rules in several places for building texi2any.  For example,
in tta/C/Makefile.am:

$(srcdir)/main/command_data.c $(srcdir)/main/command_ids.h 
$(srcdir)/main/global_multi_commands_case.c 
$(srcdir)/main/global_unique_commands_case.c 
$(srcdir)/main/global_commands_types.h: ../data/command_data.txt 
main/command_data.awk
        $(GAWK) -v srcdir=$(srcdir)/main -f $(srcdir)/main/command_data.awk \
             $(srcdir)/../data/command_data.txt

The problem is supposed to be with parallel builds, in that the rule could
run multiple times at the same time.

For example, if under tta/C, I run "touch ../data/command_data.txt" and
then run "make", the output starts:

------------
/bin/bash '/home/g/src/texinfo/GIT/tta/build-aux/missing' gawk -v srcdir=./main 
-f ./main/command_data.awk \
     ./../data/command_data.txt
/usr/bin/perl ./../maintain/generate_code_commands_values.pl \
      ./../data/commands_values.txt C \
      ./main/cmd_text.c \
      ./main/cmd_unicode.c \
      ./main/cmd_structuring.c \
      ./convert/cmd_converter.c \
      ./main/command_data.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/generate_code_convert_data.pl \
        < ./main/command_data.c \
            ./../data/default_css_element_class_styles.csv \
            ./../data/default_direction_strings.csv \
            ./../data/default_special_unit_info.csv \
            ./../data/html_style_commands_element.csv \
            C ./main/html_conversion_data.c \
            ./main/html_conversion_data.h
REMARK: 'Space': no description
make  all-am
make[1]: Entering directory '/home/g/src/texinfo/GIT/tta/C'
x86_64-linux-gnu-gcc -DHAVE_CONFIG_H -I.  -I./parsetexi -I./convert -I./main 
-I./structuring_transfo -I. -DDATADIR=\"/usr/local/share\" 
-DSYSCONFDIR=\"/usr/local/etc\" -I../gnulib/lib -I../gnulib/lib 
-DPATH_SEP=\":\" -DEMBED_PERL    -MT ctexi2any-texi2any.o -MD -MP -MF 
.deps/ctexi2any-texi2any.Tpo -c -o ctexi2any-texi2any.o `test -f 'texi2any.c' 
|| echo './'`texi2any.c
------------

- but if I run "make -j4" instead, the output starts:

------------
/bin/bash '/home/g/src/texinfo/GIT/tta/build-aux/missing' gawk -v srcdir=./main 
-f ./main/command_data.awk \
     ./../data/command_data.txt
/bin/bash '/home/g/src/texinfo/GIT/tta/build-aux/missing' gawk -v srcdir=./main 
-f ./main/command_data.awk \
     ./../data/command_data.txt
/bin/bash '/home/g/src/texinfo/GIT/tta/build-aux/missing' gawk -v srcdir=./main 
-f ./main/command_data.awk \
     ./../data/command_data.txt
/bin/bash '/home/g/src/texinfo/GIT/tta/build-aux/missing' gawk -v srcdir=./main 
-f ./main/command_data.awk \
     ./../data/command_data.txt
/usr/bin/perl ./../maintain/generate_code_commands_values.pl \
      ./../data/commands_values.txt C \
      ./main/cmd_text.c \
      ./main/cmd_unicode.c \
      ./main/cmd_structuring.c \
      ./convert/cmd_converter.c \
      ./main/command_data.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/generate_code_commands_values.pl \
      ./../data/commands_values.txt C \
      ./main/cmd_text.c \
      ./main/cmd_unicode.c \
      ./main/cmd_structuring.c \
      ./convert/cmd_converter.c \
      ./main/command_data.c
/usr/bin/perl ./../maintain/generate_code_commands_values.pl \
      ./../data/commands_values.txt C \
      ./main/cmd_text.c \
      ./main/cmd_unicode.c \
      ./main/cmd_structuring.c \
      ./convert/cmd_converter.c \
      ./main/command_data.c
/usr/bin/perl ./../maintain/generate_code_commands_values.pl \
      ./../data/commands_values.txt C \
      ./main/cmd_text.c \
      ./main/cmd_unicode.c \
      ./main/cmd_structuring.c \
      ./convert/cmd_converter.c \
      ./main/command_data.c
/usr/bin/perl ./../maintain/generate_code_convert_data.pl \
        < ./main/command_data.c \
            ./../data/default_css_element_class_styles.csv \
            ./../data/default_direction_strings.csv \
            ./../data/default_special_unit_info.csv \
            ./../data/html_style_commands_element.csv \
            C ./main/html_conversion_data.c \
            ./main/html_conversion_data.h
/usr/bin/perl ./../maintain/generate_code_convert_data.pl \
        < ./main/command_data.c \
            ./../data/default_css_element_class_styles.csv \
            ./../data/default_direction_strings.csv \
            ./../data/default_special_unit_info.csv \
            ./../data/html_style_commands_element.csv \
            C ./main/html_conversion_data.c \
            ./main/html_conversion_data.h
REMARK: 'Space': no description
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
REMARK: 'Space': no description
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
/usr/bin/perl ./../maintain/regenerate_C_options_info.pl \
        < ./../data/options_data.txt \
              ./main/command_data.c \
              ./../data/converters_defaults.txt \
              ./main/options_init_free.c \
              ./main/options_data.h \
              ./main/options_defaults.c \
              ./main/options_defaults.h \
              ./convert/converters_options.c \
              ./convert/converters_options.h \
              ./main/options_get_perl.c
make  all-am
make[1]: Entering directory '/home/g/src/texinfo/GIT/tta/C'
/bin/bash ../libtool  --tag=CC   --mode=compile x86_64-linux-gnu-gcc 
-DHAVE_CONFIG_H -I.  -I./main -I. -DDATADIR=\"/usr/local/share\" 
-DSYSCONFDIR=\"/usr/local/etc\" -I/usr/lib/x86_64-linux-gnu/perl/5.34/CORE  
-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe 
-I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fPIC  -MT 
main/libtexinfoxs_la-build_perl_info.lo -MD -MP -MF 
main/.deps/libtexinfoxs_la-build_perl_info.Tpo -c -o 
main/libtexinfoxs_la-build_perl_info.lo `test -f 'main/build_perl_info.c' || 
echo './'`main/build_perl_info.c
------------

- as you can see, the rules run multiple times.

The node in the Automake manual does not offer a clear solution that
is correct.  It shows various solutions, some much more complicated than
others.  It's not clear that these solutions actually work and some of them
seem like ideas or proposals rather a recommended solution ("One could
imagine something along the following lines.").

Have we had this problem?  Could we get away with just ignoring it as
the proposed solutions are all atrociously complicated?  Maybe it is harmless
to have multiple processes writing to the generated files at the same
time?

As these files are generated in srcdir and are distributed, then the
rule to rebuild them shouldn't run too often and users of the package
would not have to rebuild them, and would be unlikely to run into
problems with parallel builds.

If we do ignore the problem, we should add a comment stating this in
the Makefile.am files.

I had an idea that "locking" could be done in a separate helper program.
The "make" rule would become something like:

LOCK_ONCE=build_aux/lock-once.sh

$(srcdir)/main/command_data.c $(srcdir)/main/command_ids.h 
$(srcdir)/main/global_multi_commands_case.c 
$(srcdir)/main/global_unique_commands_case.c 
$(srcdir)/main/global_commands_types.h: ../data/command_data.txt 
main/command_data.awk
        $(LOCK_ONCE) $(GAWK) -v srcdir=$(srcdir)/main -f 
$(srcdir)/main/command_data.awk \
             $(srcdir)/../data/command_data.txt


Then all the complexity of checking for signals, clean-up etc. could
go in the separate program.


Reply via email to