Fix bug #103: allow ifdef, export, and unexport to expand their arguments.
+2002-09-10 Paul D. Smith <psmith@gnu.org>
+
+ * read.c (eval): Expand variable lists given to export and
+ unexport, so that "export $(LIST_OF_VARIABLES)" (etc.) works.
+ (conditional_line): Ditto for "ifdef". Fixes bug #103.
+
+ * doc/make.texi (Variables/Recursion): Document this.
+ (Conditional Syntax): And here.
+
2002-09-09 Paul D. Smith <psmith@gnu.org>
* configure.in: Check for memmove().
+2002-09-07 Paul D. Smith <psmith@gnu.org>
+
+ * configure.in (HAVE_BROKEN_RESTART): Define this on PTX systems;
+ Michael Sterrett <msterret@coat.com> reports that while it has
+ SA_RESTART, it does not work properly.
+
+ * misc.c (atomic_stat): If HAVE_BROKEN_RESTART, create a function
+ that invokes stat() and loops to do it again if it returns EINTR.
+ (atomic_readdir): Ditto, with readdir().
+
+ * make.h (stat, readdir): If HAVE_BROKEN_RESTART, alias stat()
+ and readdir() to atomic_stat() and atomic_readdir().
+
2002-09-04 Paul D. Smith <psmith@gnu.org>
* implicit.c (pattern_search): Daniel <barkalow@reputation.com>
# Tell automake about this, so it can build the right .c files.
AM_CONDITIONAL(USE_LOCAL_GLOB, test "$make_cv_sys_gnu_glob" = no)
+# PTX systems have a broken implementation of SA_RESTART. I know of
+# no way to test for this behavior, so I'll just test for PTX
+
+case "$host" in
+ i386-sequent-sysv4)
+ AC_DEFINE(HAVE_BROKEN_RESTART, 1, [This system has SA_RESTART, but it doesn't work properly.])
+ echo ""
+ echo "WARNING: The SA_RESTART sigaction() flag does not work on PTX."
+ echo " This causes 'make -j' to fail at random times."
+ echo " I am installing a workaround, which is mostly but not 100%"
+ echo " effective. If you see random failures during 'make -j'"
+ echo " you should either contact the bug list, or not use -j."
+ echo "" ;;
+esac
+
# Let the makefile know what our build host is
AC_DEFINE_UNQUOTED(MAKE_HOST,"$host",[Build host information.])
@end example
@noindent
+In both of these forms, the arguments to @code{export} and
+@code{unexport} are expanded, and so could be variables or functions
+which expand to a (list of) variable names to be (un)exported.
+
As a convenience, you can define a variable and export it at the same
time by doing:
If the variable @var{variable-name} has a non-empty value, the
@var{text-if-true} is effective; otherwise, the @var{text-if-false},
if any, is effective. Variables that have never been defined have an
-empty value.
+empty value. The variable @var{variable-name} is itself expanded, so
+it could be a variable or function that expands to the name of a
+variable.
Note that @code{ifdef} only tests whether a variable has a value. It
does not expand the variable to see if that value is nonempty.
#ifdef HAVE_DMALLOC_H
#include <dmalloc.h>
#endif
+
+
+/* If we have broken SA_RESTART support, then wrap stat() and readdir() with
+ versions that handle EINTR. Note that there are still plenty of system
+ calls that can fail with EINTR but this, reportedly, gets the vast
+ majority of failure cases. If you still experience failures you'll need
+ to either get a system where SA_RESTART works, or you need to avoid -j. */
+
+#ifdef HAVE_BROKEN_RESTART
+
+#define stat(_f,_b) atomic_stat ((_f), (_b))
+#define readdir(_d) atomic_readdir (_d)
+
+#endif
return value;
}
#endif
+\f
+
+#ifdef HAVE_BROKEN_RESTART
+
+#undef stat
+#undef readdir
+
+int
+atomic_stat(file, buf)
+ const char *file;
+ struct stat *buf;
+{
+ int r;
+
+ while ((r = stat (file, buf)) < 0)
+ if (errno != EINTR)
+ break;
+
+ return r;
+}
+
+struct dirent *
+atomic_readdir(dir)
+ DIR *file;
+{
+ struct dirent *r;
+
+ while ((r = readdir (file, buf)) == NULL)
+ if (errno != EINTR)
+ break;
+
+ return r;
+}
+
+#endif /* HAVE_BROKEN_RESTART */
|| word1eq ("ifeq") || word1eq ("ifneq")
|| word1eq ("else") || word1eq ("endif")))
{
- int i = conditional_line (p, fstart);
+ int i = conditional_line (p, fstart);
if (i < 0)
fatal (fstart, _("invalid syntax in conditional"));
for (p = find_next_token (&p2, &len); p != 0;
p = find_next_token (&p2, &len))
{
- v = lookup_variable (p, len);
+ char *var;
+ int l;
+
+ /* Expand the thing we're looking up, so we can use
+ indirect and constructed variable names. */
+ p[len] = '\0';
+ var = allocated_variable_expand (p);
+ l = strlen (var);
+
+ v = lookup_variable (var, l);
if (v == 0)
- v = define_variable_loc (p, len, "", o_file, 0,
+ v = define_variable_loc (var, l, "", o_file, 0,
fstart);
v->export = v_export;
+ free (var);
}
}
}
for (p = find_next_token (&p2, &len); p != 0;
p = find_next_token (&p2, &len))
{
- v = lookup_variable (p, len);
+ char *var;
+ int l;
+
+ /* Expand the thing we're looking up, so we can use
+ indirect and constructed variable names. */
+ p[len] = '\0';
+ var = allocated_variable_expand (p);
+ l = strlen (var);
+
+ v = lookup_variable (var, l);
if (v == 0)
- v = define_variable_loc (p, len, "", o_file, 0, fstart);
+ v = define_variable_loc (var, l, "", o_file, 0, fstart);
+
v->export = v_noexport;
+
+ free (var);
}
}
goto rule_complete;
if (cmdname[notdef ? 3 : 2] == 'd')
{
/* "Ifdef" or "ifndef". */
+ char *var;
struct variable *v;
register char *p = end_of_token (line);
i = p - line;
p = next_token (p);
if (*p != '\0')
return -1;
- v = lookup_variable (line, i);
+
+ /* Expand the thing we're looking up, so we can use indirect and
+ constructed variable names. */
+ line[i] = '\0';
+ var = allocated_variable_expand (line);
+
+ v = lookup_variable (var, strlen (var));
conditionals->ignoring[conditionals->if_cmds - 1]
= (v != 0 && *v->value != '\0') == notdef;
+
+ free (var);
}
else
{
+2002-09-10 Paul D. Smith <psmith@gnu.org>
+
+ * scripts/features/export: Created. Add tests for export/unexport
+ capabilities, including exporting/unexporting expanded variables.
+
+ * scripts/features/conditionals: Add a test for expanded variables
+ in ifdef conditionals.
+
2002-09-04 Paul D. Smith <psmith@gnu.org>
* scripts/features/reinvoke: Change touch/sleep combos to utouch
&compare_output($answer,&get_logfile(1));
+
+# Test expansion of variables inside ifdef.
+
+$makefile2 = &get_tmpfile;
+
+open(MAKEFILE, "> $makefile2");
+
+print MAKEFILE <<'EOF';
+
+foo = 1
+
+FOO = foo
+F = f
+
+DEF = no
+DEF2 = no
+
+ifdef $(FOO)
+DEF = yes
+endif
+
+ifdef $(F)oo
+DEF2 = yes
+endif
+
+all:; @echo DEF=$(DEF) DEF2=$(DEF2)
+
+EOF
+
+&run_make_with_options($makefile2,"",&get_logfile,0);
+$answer = "DEF=yes DEF2=yes\n";
+&compare_output($answer,&get_logfile(1));
+
+
# This tells the test driver that the perl test script executed properly.
1;
--- /dev/null
+# -*-perl-*-
+$description = "Check GNU make export/unexport commands.";
+
+$details = "";
+
+# The test driver cleans out our environment for us so we don't have to worry
+# about that here.
+
+open(MAKEFILE,"> $makefile");
+
+# The Contents of the MAKEFILE ...
+
+print MAKEFILE <<'EOMAKE';
+
+FOO = foo
+BAR = bar
+BOZ = boz
+
+export BAZ = baz
+export BOZ
+
+BITZ = bitz
+BOTZ = botz
+
+export BITZ BOTZ
+unexport BOTZ
+
+
+ifdef EXPORT_ALL
+export
+endif
+
+ifdef UNEXPORT_ALL
+unexport
+endif
+
+ifdef EXPORT_ALL_PSEUDO
+.EXPORT_ALL_VARIABLES:
+endif
+
+all:
+ @echo "FOO=$(FOO) BAR=$(BAR) BAZ=$(BAZ) BOZ=$(BOZ) BITZ=$(BITZ) BOTZ=$(BOTZ)"
+ @echo "FOO=$$FOO BAR=$$BAR BAZ=$$BAZ BOZ=$$BOZ BITZ=$$BITZ BOTZ=$$BOTZ"
+
+EOMAKE
+
+close(MAKEFILE);
+
+# TEST 0: basics
+
+&run_make_with_options($makefile,"",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO= BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+# TEST 1: make sure vars inherited from the parent are exported
+
+$ENV{FOO} = 1;
+
+&run_make_with_options($makefile,"",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO=foo BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+delete $ENV{FOO};
+
+# TEST 2: global export. Explicit unexport takes precedence.
+
+&run_make_with_options($makefile,"EXPORT_ALL=1",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+# TEST 3: global unexport. Explicit export takes precedence.
+
+&run_make_with_options($makefile,"UNEXPORT_ALL=1",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO= BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+# TEST 4: both: in the above makefile the unexport comes last so that rules.
+
+&run_make_with_options($makefile,"EXPORT_ALL=1 UNEXPORT_ALL=1",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO= BAR= BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+# TEST 5: test the pseudo target.
+
+&run_make_with_options($makefile,"EXPORT_ALL_PSEUDO=1",&get_logfile,0);
+
+$answer = "FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=botz
+FOO=foo BAR=bar BAZ=baz BOZ=boz BITZ=bitz BOTZ=\n";
+
+&compare_output($answer,&get_logfile(1));
+
+
+# TEST 6: Test the expansion of variables inside export
+
+$makefile2 = &get_tmpfile;
+
+open(MAKEFILE, "> $makefile2");
+
+print MAKEFILE <<'EOF';
+
+foo = f-ok
+bar = b-ok
+
+FOO = foo
+F = f
+
+BAR = bar
+B = b
+
+export $(FOO)
+export $(B)ar
+
+all:
+ @echo foo=$(foo) bar=$(bar)
+ @echo foo=$$foo bar=$$bar
+
+EOF
+
+&run_make_with_options($makefile2,"",&get_logfile,0);
+$answer = "foo=f-ok bar=b-ok\nfoo=f-ok bar=b-ok\n";
+&compare_output($answer,&get_logfile(1));
+
+
+# TEST 7: Test the expansion of variables inside unexport
+
+$makefile3 = &get_tmpfile;
+
+open(MAKEFILE, "> $makefile3");
+
+print MAKEFILE <<'EOF';
+
+foo = f-ok
+bar = b-ok
+
+FOO = foo
+F = f
+
+BAR = bar
+B = b
+
+export foo bar
+
+unexport $(FOO)
+unexport $(B)ar
+
+all:
+ @echo foo=$(foo) bar=$(bar)
+ @echo foo=$$foo bar=$$bar
+
+EOF
+
+&run_make_with_options($makefile3,"",&get_logfile,0);
+$answer = "foo=f-ok bar=b-ok\nfoo= bar=\n";
+&compare_output($answer,&get_logfile(1));
+
+
+# This tells the test driver that the perl test script executed properly.
+1;