Follow-up Comment #7, bug #64185 (project make): I often remind developers that “the tail does not wag the dog”, in the same way that the current behavior of the code does not define correctness.
While you keep explaining what the parser is currently doing, what I am reporting is that this is not the correct behavior as described by the GNU Make documentation. While the documented behavior makes perfect sense, the parser behavior you are describing contradicts the documentation as well as common sense. Specifically, the documentation clearly defines two fundamental behaviors for Make Conditionals as follows: “Extra spaces are allowed and ignored at the beginning of the conditional directive line, but a tab is not allowed. (If the line begins with a tab, it will be considered part of a recipe for a rule.)” “The other two directives that play a part in a conditional are else and endif. Each of these directives is written as one word, with no arguments. Extra spaces are allowed and ignored at the beginning of the line, and spaces or tabs at the end.” “Conditionals affect which lines of the makefile make uses. If the condition is true, make reads the lines of the test-if-true as part of the makefile; if the condition is false, make ignores those lines completely.” The two behaviors are: 1. Any lines of code within an inactive conditional branch are entirely ignored. 2. Conditional directives cannot be confused with recipe lines because they cannot begin with a tab character. The documentation should be updated to refer to the .RECIPEPREFIX character, which did not exist prior to Make 3.82. Lets apply the above statements, in detail, to the behavior you have explained regarding the excerpt: all: ifdef blah junk: else else endif > Here, the parser sees rule 'all:' and begins its search for recipe lines of 'all:'. Then the parser sees 'ifdef blah'. 'blah' is not defined and the parser ignores the following line, which is 'junk:'. > Then parser reads '\telse' and takes it as a recipe of 'all:'. This is incorrect behavior, because the condition was false so it is in an inactive branch: "if the conditon is false, make ignores those lines completely.” > Because the parser took one of the two elses as a recipe, there is no complain about extra elses in a conditional. This is incorrect behavior because the recipe else begins with a tab so it is not a conditional directive: “(If the line begins with a tab, it will be considered part of a recipe for a rule.)” Since the conditional is false, all lines of code are ignored until the next conditional (else) preceded only by optional spaces: "Extra spaces are allowed and ignored at the beginning of the line, and spaces or tabs at the end.” The else begins the active branch of the conditional, so any lines of code (in this case none) until the following conditional endif are passed to the Make parser. The endif ends the active branch and the scope of the conditional. The correct result is that only the following lines of code are "seen" by the Make parser: all: Similarly, for the second excerpt: all: $(info hello) ifdef blah junk: else else endif > Here, $(info hello) ends the search for recipe lines of 'all'. By the time the parser reads 'ifdef blah' it is no longer looking for recipe lines. > The parser then ignores 'junk:', because 'blah' is not defined and treats '\telse' as a conditional directive. This is incorrect behavior because conditional directives cannot begin with a tab character: “(If the line begins with a tab, it will be considered part of a recipe for a rule.)” As above, since the conditional was false, all lines of code will be ignored until it reaches the next conditional directive: "if the conditon is false, make ignores those lines completely.” As above, the conditional directive else terminates the inactive branch and begins the active branch until the conditional directive endif terminates the active branch and the scope of the conditional. The correct result is that the following lines of code are "seen" by the Make parser: all: $(info hello) It may be helpful to understand that Make conditionals are defined to behave similarly to "C" pre-processor conditionals, in that each line of code is first examined and handled as follows: 1. If the line is a conditional directive, it is processed as such and the "state" of any conditional is adjusted accordingly (none, active conditional branch, inactive conditional branch). 2. Otherwise, if the "state" is currently an inactive conditional branch, the line is ignored. 3. Otherwise, the line of code is passed to the code parser. _______________________________________________________ Reply to this item at: <https://savannah.gnu.org/bugs/?64185> _______________________________________________ Message sent via Savannah https://savannah.gnu.org/