[This enhancement request is for Gnu make 3.79.1.] It would be a useful thing if Make variable names were forbidden to contain slash (`/'), as well as `:', `#', and `='. The reason I make this request is that I was rebuilding a Linux kernel in a directory named (more or less) `/auto/LABEL=Backup/linux-2.4.20-24.8.test4'. The Linux kernel makefile expands out the full path of the files it is working with, rather than using relative names, so at one point, it generated a Makefile rule looking something like this:
cciss.h: \ /auto/LABEL=Backup/linux-2.4.20-24.8.test4/include/linux/genhd.h \ /auto/LABEL=Backup/linux-2.4.20-24.8.test4/drivers/block/cciss_cmd.h @touch cciss.h Because the first non-whitespace thing after the `:' contained an `=', Make interpreted it as a target-specific variable assignment, not a rule. Due to the organization of the Linux kernel makefiles, it is difficult to avoid this problem without moving the file tree to a different place. Following is a patch which should forbid `/' in variable names (in most circumstances), and thus allow `=', `+=', and `?=' in path names after the first `/'. This does not permit `:=' in path names, whose interpretation is much more complex. But that problem is no worse than before. The patch includes a new test, variables/names_equal, to verify that paths containing `=' can be used. The patched code passes all the existing tests as well. The patch adds comments to mark a couple of cases in switches that fall through to the next case, which is good coding style. In addition, the patch reorganizes a "case ':'" in read.c to allow easy insertion of code to handle `:=' when someone feels up to writing it. The new behavior is different than before -- previously, if a device-letter is used on MS-DOS, the "case ':'" falls through to the following "case '$'", which appears to be incorrect behavior, even though it may produce the correct result in most cases. (E.g., it looks like the path `C:$(variable)' will not be variable-substituted correctly.) The patch modifies the texinfo to specify that `/' is forbidden in variable names, and why. Dale ---------------------------------------------------------------------- diff -r --new-file -u --exclude='*~' --exclude=work make-3.79.1.orig/make.texinfo make-3.79.1/make.texinfo --- make-3.79.1.orig/make.texinfo 2000-06-20 10:00:17.000000000 -0400 +++ make-3.79.1/make.texinfo 2004-01-09 11:50:11.000000000 -0500 @@ -4000,11 +4000,13 @@ programs to run, directories to look in for source files, directories to write output in, or anything else you can imagine. -A variable name may be any sequence of characters not containing @samp{:}, [EMAIL PROTECTED], @samp{=}, or leading or trailing whitespace. However, -variable names containing characters other than letters, numbers, and -underscores should be avoided, as they may be given special meanings in the -future, and with some shells they cannot be passed through the environment to a +A variable name may be any sequence of characters not containing [EMAIL PROTECTED]:}, @samp{#}, @samp{=}, @samp{/} or leading or trailing +whitespace. (@samp{/} is forbidden so that path names containing [EMAIL PROTECTED] can be handled.) However, variable names containing +characters other than letters, numbers, and underscores should be +avoided, as they may be given special meanings in the future, and with +some shells they cannot be passed through the environment to a [EMAIL PROTECTED] (@pxref{Variables/Recursion, ,Communicating Variables to a [EMAIL PROTECTED]). diff -r --new-file -u --exclude='*~' --exclude=work make-3.79.1.orig/read.c make-3.79.1/read.c --- make-3.79.1.orig/read.c 2000-06-21 15:33:30.000000000 -0400 +++ make-3.79.1/read.c 2004-01-09 13:00:25.000000000 -0500 @@ -2264,6 +2264,10 @@ enum make_word_type wtype = w_bogus; char *p = buffer, *beg; char c; + /* 1 if we have seen a character which cannot be part of a variable name, + and thus if we seen `=', it is part of the token, not a variable + definition. */ + int non_variable_character_seen = 0; /* Skip any leading whitespace. */ while (isblank ((unsigned char)*p)) @@ -2313,6 +2317,7 @@ wtype = w_varassign; break; } + /* Falls through to next case. */ default: if (delim && strchr (delim, c)) @@ -2326,7 +2331,12 @@ /* This is some non-operator word. A word consists of the longest string of characters that doesn't contain whitespace, one of [:=#], - or [?+]=, or one of the chars in the DELIM string. */ + or [?+]=, or one of the chars in the DELIM string. + In addition, `=' is permitted if the preceding characters contain + a character (currently, only `/' has this role) specifically excluded from + variable names. + In addition, on MS-DOS/MS-Windows systems, `:' is permitted in certain + circumstances as a drive specifier. */ /* We start out assuming a static word; if we see a variable we'll adjust our assumptions then. */ @@ -2343,19 +2353,28 @@ case '\0': case ' ': case '\t': - case '=': case '#': goto done_word; case ':': + /* A word can include a colon under certain circumstances. The + following clauses specify when it can. */ + if (0 #if defined(__MSDOS__) || defined(WINDOWS32) - /* A word CAN include a colon in its drive spec. The drive - spec is allowed either at the beginning of a word, or as part - of the archive member name, like in "libfoo.a(d:/foo/bar.o)". */ - if (!(p - beg >= 2 - && (*p == '/' || *p == '\\') && isalpha ((unsigned char)p[-2]) - && (p - beg == 2 || p[-3] == '('))) + /* A word can include a colon in its drive spec. The drive + spec is allowed either at the beginning of a word, or as part + of the archive member name, like in + "libfoo.a(d:/foo/bar.o)". */ + || (p - beg >= 2 + && (*p == '/' || *p == '\\') && isalpha ((unsigned char)p[-2]) + && (p - beg == 2 || p[-3] == '(')) #endif + ) + /* If any clause is true, continue reading characters of the + word. */ + break; + /* If no clause is true, this `:' is a special character and should + not be included in the word. */ goto done_word; case '$': @@ -2389,7 +2408,7 @@ case '?': case '+': - if (*p == '=') + if (!non_variable_character_seen && *p == '=') goto done_word; break; @@ -2405,7 +2424,17 @@ } break; + case '=': + if (!non_variable_character_seen) + goto done_word; + /* Fall through to next case. */ + default: + /* Currently, `/' is the only character specifically excluded from + variable names (that does not have additional syntax that is + already handled). */ + if (c == '/') + non_variable_character_seen = 1; if (delim && strchr (delim, c)) goto done_word; break; diff -r --new-file -u --exclude='*~' --exclude=work make-3.79.1.orig/tests/scripts/variables/names_equal make-3.79.1/tests/scripts/variables/names_equal --- make-3.79.1.orig/tests/scripts/variables/names_equal 1969-12-31 19:00:00.000000000 -0500 +++ make-3.79.1/tests/scripts/variables/names_equal 2004-01-09 12:47:46.000000000 -0500 @@ -0,0 +1,48 @@ +# -*-perl-*- + +$description = "Test that variable names may not contain `/', specifically in target-specific variable definitions."; + +$details = ""; + +open(MAKEFILE, "> $makefile"); + +# The Contents of the MAKEFILE ... + +# Prepare a makefile with rules that contain the variable assignment +# operators `=', `+=' and `?=' within paths. +# Note that `:=' is NOT allowed, since that case involves the messy semantics +# of `:', which is a problem that is not addressed in this test. + +print MAKEFILE <<'EOF'; +all : target1 target2 target3 + +target1 : ./=a + @echo processing target1 + +./=a : + @echo processing ./=a + +target2 : ./+=a + @echo processing target2 + +./+=a : + @echo processing ./+=a + +target3 : ./?=a + @echo processing target3 + +./?=a : + @echo processing ./?=a +EOF + +# END of Contents of MAKEFILE + +close(MAKEFILE); + +# TEST #1 +# ------- + +&run_make_with_options($makefile, "", &get_logfile); +$answer = "processing ./=a\nprocessing target1\nprocessing ./+=a\nprocessing target2\nprocessing ./?=a\nprocessing target3\n"; +&compare_output($answer, &get_logfile(1)); +1; diff -r --new-file -u --exclude='*~' --exclude=work make-3.79.1.orig/variable.c make-3.79.1/variable.c --- make-3.79.1.orig/variable.c 2000-05-19 12:36:08.000000000 -0400 +++ make-3.79.1/variable.c 2004-01-09 12:18:34.000000000 -0500 @@ -798,7 +798,9 @@ while (1) { c = *p++; - if (c == '\0' || c == '#') + /* `/' is now forbidden in variable names so that paths containing `=' + (at least, after the first `/') can be processed. */ + if (c == '\0' || c == '#' || c == '/') return 0; if (c == '=') { ---------------------------------------------------------------------- _______________________________________________ Bug-make mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-make