(root)/Notes/Notes/notes/make.md 🍁

Make

--- make.html --- https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html --- POSIX.1-2017

reosurce A Tutorial on Portable Makefiles by Chris Wellons, on adhering to POSIX make --- A Tutorial on Portable Makefiles.pdf --- https://nullprogram.com/blog/2017/08/20/

if the first non-comment line is not the special target .POSIX, the behavior is unspecified. make has built-in rules, which can be disabled by supplying a rule for the special target .SUFFIXES with no prerequisites. when there are no rules to build a target, the special target .DEFAULT is invoked. targets matching \.[A-Z]+ are reserved.

# introduces a comment to the end of the line. not supported in command lines, but shells tend to use # comments so it's likely to work regardless

newlines can be escaped with \ and get replaced s/\\\n\s*/ /, except in a command line, where they get replaced s/\\\n\t?/\\\n/

command lines are indented with a tab, not spaces. each is executed in its own shell so a cd only applies to the current line. after the tab there can be any number of:

  • - --- ignore any errors executing the commad, like .IGNORE
  • @ --- don't print the command before executing it, like .SILENT
  • + --- also execute the command in dry runs

include path behaves like c > preprocessor #include. path can't contain blanks

name = value defines a macro: thereafter $(name) and ${name} both expand to value, and $(name:suffix=substitute) and ${name:suffix=substitute} both expand to s/suffix\b/substitute/g on value. in the first two forms, the parentheses or braces may be omitted when name has length one. the name of the macro being invoked cannot depend on other macro invocations. macro expansion is lazy: after MACRO = 1 then REF = $(MACRO) then MACRO = 2, $(REF) expands to 2. The macro $$ shall be replaced by the single charater '$' and only God would know whether $($) and ${$} expand to '$' as well.

There are five built-in macros, $< $* $@ $? $%, and two sets of alternative forms, $(<F) $(*F) $(@F) $(?F) $(%F) to extract the filename parts and $(<D) $(*D) $(@D) $(?D) $(%D) to extract the directory parts (plus the equivalent ${<F} ${*F} ${@F} ${?F} ${%F} and ${<D} ${*D} ${@D} ${?D} ${%D}). careful, some work in inference rules but not target rules, and some only work for lib(member.o) targets

an "inference rule"---not to be confused with an inference rule---is a rule whose target part is of the form .o or .c.o, where .c and .o are included as prerequisites of the special target .SUFFIXES. it describes how to build any file with extension .o from a corresponding file with extension .c in the same directory

whining

Applications shall select target names from the set of characters consisting solely of periods, underscores, digits, and alphabetics from the portable character set [...]. thus targets cannot contain /s. (the standard is so sloppy that I'm not ruling out this being a mistake)

Target rules are formatted as follows: target [target...]: [prerequisite...][;command]<newline>[<tab>command<tab>command...]<newline>line that does not begin with <tab>. so a rule must contain either zero or at least two command lines, all of which must be on the same line

There are two kinds of rules: inference rules and target rules. [...] If a rule is defined more than once, the value of the rule shall be that of the last one specified. so later rules overwrite earlier rules. A target that has prerequisites, but does not have any commands, can be used to add to the prerequisite list for that target. Only one target rule for any given target can contain commands. so later rules don't actually overwrite earlier rules. Inference rules can be redefined. A target that matches an existing inference rule shall overwrite the old inference rule. so later rules do sometimes overwrite earlier rules. (the wording is confusing here, what they mean is that overwriting happens when the target parts of the inference rules are the same)

The five internal macros are --- $@: The $@ [macro] shall evaluate to the full target name of the current target, or the archive filename part of a library archive target. [...] $%: The $% macro shall be evaluated only when the current target is an archive library member [...]. $?: The $? macro shall evaluate to the list of prerequisites that are newer than the current target. [...] $<: In an inference rule, the $< macro shall evaluate to [...]. $*: The $* macro shall evaluate to the current target name with its suffix deleted. [...] Each of the internal macros has an alternative form. When an uppercase 'D' or 'F' is appended to any of the macros, the meaning shall be changed to the directory part for 'D' and filename part for 'F'. if we're calling $@ a macro then appending D to the macro gives $@D, not $(@D) or ${@D}. so sloppy

For the target lib(member.o) and the s2.a rule, the internal macros shall be defined as: $< = member.s2, $* = member, $@ = lib, $? = member.s2, $% = member.o. lmao, they meant to say the .s2.a rule. the rule s2.a wouldn't match lib(member.o)