This is the mail archive of the
automake@gnu.org
mailing list for the automake project.
non-recursive proof-of-concept
- To: automake at gnu dot org
- Subject: non-recursive proof-of-concept
- From: Robert Collins <robert dot collins at itdomain dot com dot au>
- Date: 15 Aug 2001 23:35:14 +1000
- List-Id: Discussion list for automake <automake.gnu.org>
I don't claim to be a perl programmer - at all :]
Some of what I've done is duplicate code and should probably be done by
extending the existing function, making the existing cases a call with a
prepend of ''.
I haven't covered all the automake targets or macros.
I haven't attempted full normalisation.
However, a simple project, using this will pass make distcheck, and will
build every directory in parallel.
See the Makefile.am's created by the distcheck test for examples of use.
Rob
#!/bin/sh
# Test for PR automake/220.
. $srcdir/defs || exit 1
subdirs="foo"
for i in $subdirs; do
mkdir $i
cat >$i/$i-a.c <<EOF
int maina() { return 0; }
EOF
cat >$i/$i-b.c <<EOF
int mainb() { return 0; }
EOF
cat >$i/Makefile.rules <<EOF
bin_PROGRAMS = ${i}bin
${i}bin_SOURCES = \$(top_srcdir)/main.c $i-a.c $i-b.c
EOF
cat >$i/Makefile.am <<EOF
include \$(srcdir)/Makefile.rules
EOF
done
cat >main.c <<EOF
int main() { return 0; }
EOF
# echo "SUBDIRS = $subdirs" > Makefile.am
cat >Makefile.am <<EOF
#AUTOMAKE_OPTIONS = subdir-objects
DIST_SUBDIRS = $subdirs
subdir_include \$(srcdir)/foo/Makefile.rules
EOF
cat >configure.in <<EOF
AC_INIT(foo/foo-a.c)
AC_CONFIG_AUX_DIR(.)
AM_INIT_AUTOMAKE(test_am, 1.0)
AC_PROG_CC
#AM_PROG_CC_C_O
AC_OUTPUT(Makefile foo/Makefile)
EOF
# Fail gracefully if no autoconf.
$needs_autoconf
# Likewise for gcc.
(gcc -v) > /dev/null 2>&1 || exit 77
touch README NEWS AUTHORS ChangeLog
mkdir build
# We use gcc and not gcc -traditional as the latter fails on some
# Linux boxes (Red Hat 5.1 in particular).
$ACLOCAL \
&& $AUTOCONF \
&& $AUTOMAKE -a || exit 1
cd build \
&& CC='gcc' ../configure \
&& $MAKE || exit 1
#!/bin/sh
# Test for PR automake/220.
. $srcdir/defs || exit 1
subdirs="foo"
for i in $subdirs; do
mkdir $i
cat >$i/$i-a.c <<EOF
int maina() { return 0; }
EOF
cat >$i/$i-b.c <<EOF
int mainb() { return 0; }
EOF
cat >$i/Makefile.rules <<EOF
bin_PROGRAMS = ${i}bin
${i}bin_SOURCES = ../main.c $i-a.c $i-b.c
EOF
cat >$i/Makefile.am <<EOF
#EXTRA_DIST=Makefile.rules
include \$(srcdir)/Makefile.rules
EOF
done
cat >main.c <<EOF
int main() { return 0; }
EOF
# echo "SUBDIRS = $subdirs" > Makefile.am
cat >Makefile.am <<EOF
#AUTOMAKE_OPTIONS = subdir-objects
DIST_SUBDIRS = $subdirs
SUBDIRS =
subdir_include \$(srcdir)/foo/Makefile.rules
EOF
cat >configure.in <<EOF
AC_INIT(foo/foo-a.c)
AC_CONFIG_AUX_DIR(.)
AM_INIT_AUTOMAKE(test_am, 1.0)
AC_PROG_CC
#AM_PROG_CC_C_O
AC_OUTPUT(Makefile foo/Makefile)
EOF
# Fail gracefully if no autoconf.
$needs_autoconf
# Likewise for gcc.
(gcc -v) > /dev/null 2>&1 || exit 77
touch README NEWS AUTHORS ChangeLog
mkdir build
# We use gcc and not gcc -traditional as the latter fails on some
# Linux boxes (Red Hat 5.1 in particular).
$ACLOCAL \
&& $AUTOCONF \
&& $AUTOMAKE -a || exit 1
cd build \
&& CC='gcc' ../configure \
&& $MAKE distcheck || exit 1
Index: automake.in
===================================================================
RCS file: /cvs/automake/automake/automake.in,v
retrieving revision 1.1171
diff -u -p -r1.1171 automake.in
--- automake.in 2001/08/13 09:37:49 1.1171
+++ automake.in 2001/08/15 13:30:06
@@ -159,6 +159,11 @@ my $INCLUDE_PATTERN = ('^include\s+'
. '|(\$\(srcdir\)/' . $PATH_PATTERN . ')'
. '|([^/\$]' . $PATH_PATTERN. '))\s*(#.*)?$');
+my $SUBDIR_INCLUDE_PATTERN = ('^subdir_include\s+'
+ . '((\$\(top_srcdir\)/' . $PATH_PATTERN . ')'
+ . '|(\$\(srcdir\)/' . $PATH_PATTERN . ')'
+ . '|([^/\$]' . $PATH_PATTERN. '))\s*(#.*)?$');
+
# Some regular expressions. One reason to put them here is that it
# makes indentation work better in Emacs.
my $AC_CONFIG_AUX_DIR_PATTERN = 'AC_CONFIG_AUX_DIR\(([^)]+)\)';
@@ -212,7 +217,9 @@ my @common_files =
# ltconfig appears here for compatibility with old versions
# of libtool.
'ylwrap', 'acinclude.m4', @libtoolize_files, @libtoolize_sometimes,
- 'missing', 'depcomp', 'compile', 'py-compile'
+ 'missing', 'depcomp', 'compile', 'py-compile',
+ # We need a standard name for the rules that are present in each dir
+ 'Makefile.rules'
);
# Commonly used files we auto-include, but only sometimes.
@@ -2032,6 +2039,39 @@ sub handle_single_transform_list ($$$$@)
return @result;
}
+# $VALUE
+# transform_file_list ($PREPEND, @FILES)
+# ----------------------------------------
+# insert $PREPEND before every file path that is not absolute
+#
+sub transform_file_list ($$)
+{
+ my ($prepend, $tmpfiles) = @_;
+ my $result = "";
+ my @files = ();
+ @files = split(/ /, $tmpfiles);
+ while (scalar @files > 0)
+ {
+ $_ = shift @files;
+
+ if ($_ =~ s/^\$\(top_srcdir\)\///)
+ {
+ $result .= " \$\(top_srcdir\)\/" . $_;
+ }
+ elsif ( $_ =~ s/^\$\(srcdir\)\///)
+ {
+ $result .= " \$\(srcdir\)\/$prepend" . $_;
+ }
+ else
+ {
+ $result .= " $prepend" . $_;
+ }
+ }
+ print "result:$result\n";
+ return $result . "\n";
+}
+
+
# $BOOL
# define_objects_from_sources ($VAR, $OBJVAR, $NODEFINE, $ONE_FILE,
# $OBJ, $PARENT, $TOPPARENT)
@@ -2132,6 +2172,8 @@ sub define_objects_from_sources ($$$$$$$
return $needlinker;
}
+
+
# $OBJNAME
# subobjname ($VARNAME)
# ---------------------------------------------------------------------
@@ -2793,7 +2835,7 @@ sub handle_ltlibraries
# Canonicalize names and check for misspellings.
my $xlib = &check_canonical_spelling ($onelib, '_LIBADD', '_LDFLAGS',
'_SOURCES', '_OBJECTS',
- '_DEPENDENCIES');
+ '_DEPENDENCIES', '_CFLAGS');
if (! &variable_defined ($xlib . '_LDFLAGS'))
{
@@ -2801,6 +2843,19 @@ sub handle_ltlibraries
&define_variable ($xlib . '_LDFLAGS', '');
}
+ # Tell the source code what library we are building
+# my $tempvariable = '';
+# if ( &variable_defined ($xlib . '_CFLAGS'))
+# {
+# # Define the lib_CFLAGS variable.
+# $tempvariable .= &variable_value ($xlib . '_CFLAGS');
+# &variable_delete ($xlib . '_CFLAGS');
+# }
+# my $libname_short = $xlib;
+# $libname_short =~ s/_la$// ;
+# $libname_short = uc ($libname_short);
+# &define_variable ($xlib . '_CFLAGS', ' -D' . $libname_short . '_COMPILATION ' . $tempvariable);
+
# Check that the library fits the standard naming convention.
my $libname_rx = "^lib.*\.la";
if ((&variable_defined ($xlib . '_LDFLAGS')
@@ -6657,6 +6712,297 @@ sub target_defined
return defined $targets{$target};
}
+################################################################
+
+# Read Makefile.am and set up %contents. Simultaneously copy lines
+# from Makefile.am into $output_trailer or $output_vars as
+# appropriate. NOTE we put rules in the trailer section. We want
+# user rules to come after our generated stuff.
+#
+# This version translates the file on-the-fly, prepending the leading path to all targets
+
+sub read_am_file_translate
+{
+ my ($amfile, $prepend) = @_;
+
+ my $prepend_macro = $prepend;
+ $prepend_macro =~ s/\//_/;
+
+ my $am_file = new IO::File ("< $amfile");
+ if (! $am_file)
+ {
+ die "$me: couldn't open `$amfile': $!\n";
+ }
+ print "$me: reading $amfile with translation path $prepend\n" if $verbose;
+
+ my $spacing = '';
+ my $comment = '';
+ my $blank = 0;
+
+ while ($_ = $am_file->getline)
+ {
+ if (/$IGNORE_PATTERN/o)
+ {
+ # Merely delete comments beginning with two hashes.
+ }
+ elsif (/$WHITE_PATTERN/o)
+ {
+ # Stick a single white line before the incoming macro or rule.
+ $spacing = "\n";
+ $blank = 1;
+ }
+ elsif (/$COMMENT_PATTERN/o)
+ {
+ # Stick comments before the incoming macro or rule. Make
+ # sure a blank line preceeds first block of comments.
+ $spacing = "\n" unless $blank;
+ $blank = 1;
+ $comment .= $spacing . $_;
+ $spacing = '';
+ }
+ else
+ {
+ last;
+ }
+ }
+
+ $output_vars .= $comment . "\n";
+ $comment = '';
+ $spacing = "\n";
+
+ # We save the conditional stack on entry, and then check to make
+ # sure it is the same on exit. This lets us conditonally include
+ # other files.
+ my @saved_cond_stack = @cond_stack;
+ my $cond = conditional_string (@cond_stack);
+
+ my $saw_bk = 0;
+ my $was_rule = 0;
+ my $last_var_name = '';
+ my $last_var_type = '';
+ my $last_var_value = '';
+ # FIXME: shouldn't use $_ in this loop; it is too big.
+ while ($_)
+ {
+ $_ .= "\n"
+ unless substr ($_, -1, 1) eq "\n";
+
+ # Don't look at MAINTAINER_MODE_TRUE here. That shouldn't be
+ # used by users. @MAINT@ is an anachronism now.
+ $_ =~ s/\@MAINT\@//g
+ unless $seen_maint_mode;
+
+ my $new_saw_bk = /\\$/ && ! /$COMMENT_PATTERN/o;
+
+ if (/$IGNORE_PATTERN/o)
+ {
+ # Merely delete comments beginning with two hashes.
+ }
+ elsif (/$WHITE_PATTERN/o)
+ {
+ # Stick a single white line before the incoming macro or rule.
+ $spacing = "\n";
+ &am_line_error ($., "blank line following trailing backslash")
+ if $saw_bk;
+ }
+ elsif (/$COMMENT_PATTERN/o)
+ {
+ # Stick comments before the incoming macro or rule.
+ $comment .= $spacing . $_;
+ $spacing = '';
+ &am_line_error ($., "comment following trailing backslash")
+ if $saw_bk;
+ }
+ elsif ($saw_bk)
+ {
+ if ($was_rule)
+ {
+ $output_trailer .= &make_condition (@cond_stack);
+ $output_trailer .= $_;
+ #unhandled yet
+ &am_error ("can't translate saw-bk, was_rule, $_");
+ }
+ else
+ {
+ $last_var_value .= ' '
+ unless $last_var_value =~ /\s$/;
+ $last_var_value .= $_;
+
+ if (!/\\$/)
+ {
+ $var_comment{$last_var_name} .= "$spacing"
+ if (!defined $var_comment{$last_var_name}
+ || substr ($var_comment{$last_var_name}, -1) ne "\n");
+ $var_comment{$last_var_name} .= "$comment";
+ $comment = $spacing = '';
+ macro_define ($last_var_name, 0,
+ $last_var_type, $cond,
+ $last_var_value, $.)
+ if $cond ne 'FALSE';
+ push (@var_list, $last_var_name);
+ &am_error ("pushlsit $last_var_name, $last_var_value");
+ }
+ }
+ }
+
+ elsif (/$IF_PATTERN/o)
+ {
+ $cond = cond_stack_if ($1, $2, "$amfile:$.");
+ }
+ elsif (/$ELSE_PATTERN/o)
+ {
+ $cond = cond_stack_else ($1, $2, "$amfile:$.");
+ }
+ elsif (/$ENDIF_PATTERN/o)
+ {
+ $cond = cond_stack_endif ($1, $2, "$amfile:$.");
+ }
+
+ elsif (/$RULE_PATTERN/o)
+ {
+ # Found a rule.
+ $was_rule = 1;
+
+ rule_define ($1, 0, $cond, $.);
+ &am_error ("rule define $1");
+
+ $var_line{$1} = $.;
+ $output_trailer .= $comment . $spacing;
+ $output_trailer .= &make_condition (@cond_stack);
+ $output_trailer .= $_;
+ $comment = $spacing = '';
+ }
+ elsif (/$ASSIGNMENT_PATTERN/o)
+ {
+ # Found a macro definition.
+ # Q: when do we translate macro's?
+ $was_rule = 0;
+ $last_var_name = $1;
+ $last_var_type = $2;
+ $last_var_value = $3;
+ # TODO: translate every element in value
+ if ($3 ne '' && substr ($3, -1) eq "\\")
+ {
+ # We preserve the `\' because otherwise the long lines
+ # that are generated will be truncated by broken
+ # `sed's.
+ $last_var_value = $3 . "\n";
+ }
+
+ if (!/\\$/)
+ {
+ # FIXME: this doesn't always work correctly; it will
+ # group all comments for a given variable, no matter
+ # where defined.
+ # Accumulating variables must not be output.
+ $var_comment{$last_var_name} .= "$spacing"
+ if (!defined $var_comment{$last_var_name}
+ || substr ($var_comment{$last_var_name}, -1) ne "\n");
+ $var_comment{$last_var_name} .= "$comment";
+ $comment = $spacing = '';
+
+ # add this definition to the global list
+ #macro_define ($last_var_name, 1, '+', $cond,
+ # $last_var_value, $.) if $cond ne 'FALSE';
+
+ # transform the macro name. PROGRAMS etc transform the value,
+ # Sources etc transform the name and the value.
+
+ # TODO: fixup every element in the macro
+ if (substr($last_var_name, -7) eq "SOURCES" )
+ {
+ macro_define ($last_var_name, 0,
+ $last_var_type, $cond,
+ &transform_file_list($prepend, $last_var_value), $.)
+ if $cond ne 'FALSE';
+ push (@var_list, $last_var_name);
+ }
+ else
+ {
+
+ macro_define ($last_var_name, 0,
+ $last_var_type, $cond,
+ $last_var_value, $.)
+ if $cond ne 'FALSE';
+ push (@var_list, $last_var_name);
+ }
+ print "pushlist 2 $prepend_macro$last_var_name,$last_var_type,$prepend_macro$last_var_value\n";
+
+ }
+ }
+ elsif (/$INCLUDE_PATTERN/o)
+ {
+ # should included includes be translated?
+ my $path = $1;
+
+ if ($path =~ s/^\$\(top_srcdir\)\///)
+ {
+ push (@include_stack, "\$\(top_srcdir\)/$path");
+ }
+ else
+ {
+ $path =~ s/\$\(srcdir\)\///;
+ push (@include_stack, "\$\(srcdir\)/$path");
+ $path = $relative_dir . "/" . $prepend . $path;
+ }
+ &read_am_file ($path);
+ }
+ elsif (/$SUBDIR_INCLUDE_PATTERN/o)
+ {
+ my $path = $1;
+ my $prepend_path = "";
+
+ if ($path =~ s/^\$\(top_srcdir\)\///)
+ {
+ # the same stack used, as all it does is let us add a dependency for Makefile.am
+ push (@include_stack, "\$\(top_srcdir\)/$path");
+ &am_error ("attempt to translate a top_srcdir include file: $path");
+ }
+ else
+ {
+ $path =~ s/\$\(srcdir\)\///;
+ push (@include_stack, "\$\(srcdir\)/$path");
+ $prepend_path = $path;
+ $prepend_path =~ s/[^\/]*$//;
+ $prepend_path = $prepend . $prepend_path;
+ $path = $relative_dir . "/" . $prepend . $path;
+ }
+ &read_am_file_translate ($path, $prepend_path);
+ }
+ else
+ {
+ # This isn't an error; it is probably a continued rule.
+ # In fact, this is what we assume.
+ $was_rule = 1;
+ $output_trailer .= $comment . $spacing;
+ $output_trailer .= &make_condition (@cond_stack);
+ $output_trailer .= $_;
+ $comment = $spacing = '';
+ &am_line_error ($., "`#' comment at start of rule is unportable")
+ if $_ =~ /^\t\s*\#/;
+ }
+
+ $saw_bk = $new_saw_bk;
+ $_ = $am_file->getline;
+ }
+
+ $output_trailer .= $comment;
+
+ if (join (' ', @saved_cond_stack) ne join (' ', @cond_stack))
+ {
+ if (@cond_stack)
+ {
+ &am_error ("unterminated conditionals: @cond_stack");
+ }
+ else
+ {
+ # FIXME: better error message here.
+ &am_error ("conditionals not nested in include file");
+ }
+ }
+}
+
+
################################################################
@@ -6858,6 +7204,27 @@ sub read_am_file
}
&read_am_file ($path);
}
+ elsif (/$SUBDIR_INCLUDE_PATTERN/o)
+ {
+ my $path = $1;
+ my $prepend_path = "";
+
+ if ($path =~ s/^\$\(top_srcdir\)\///)
+ {
+ # the same stack used, as all it does is let us add a dependency for Makefile.am
+ push (@include_stack, "\$\(top_srcdir\)/$path");
+ &am_error ("attempt to translate a top_srcdir include file: $path");
+ }
+ else
+ {
+ $path =~ s/\$\(srcdir\)\///;
+ push (@include_stack, "\$\(srcdir\)/$path");
+ $prepend_path = $path;
+ $prepend_path =~ s/[^\/]*$//;
+ $path = $relative_dir . "/" . $path;
+ }
+ &read_am_file_translate ($path, $prepend_path);
+ }
else
{
# This isn't an error; it is probably a continued rule.
@@ -7129,8 +7496,23 @@ sub file_contents_internal ($$%)
$result_rules .= $rules;
}
}
+
+# library files aren't allowed this directive. # Handle path translated inclusion of other files.
+# elsif (/$SUBDIR_INCLUDE_PATTERN/o)
+# {
+# if ($cond ne 'FALSE')
+# {
+# my $file = ($is_am ? "$libdir/am/" : '') . $1;
+# # N-ary `.=' fails.
+# my ($com, $vars, $rules)
+# = file_contents_internal ($is_am, $file, %transform);
+# $comment .= $com;
+# $result_vars .= $vars;
+# $result_rules .= $rules;
+# }
+# }
- # Handling the conditionals.
+ # Handling the conditionals.
elsif (/$IF_PATTERN/o)
{
$cond = cond_stack_if ($1, $2, $file);
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/automake/automake/tests/Makefile.am,v
retrieving revision 1.344
diff -u -p -r1.344 Makefile.am
--- Makefile.am 2001/08/13 09:37:49 1.344
+++ Makefile.am 2001/08/15 13:30:07
@@ -276,6 +277,8 @@ subdir4.test \
subdir5.test \
subdirbuiltsources.test \
subdircond.test \
+subdir_include.test \
+subdir_include_distcheck.test \
subobj.test \
subobj2.test \
subobj3.test \