This file has been translated from LaTeX by HeVeA.  Node: Section 6-4, Next: Section 6-5, Prev: Section 6-3, Up: Chapter 6 6.4 Iteration, mapping, and foreach *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* Most builtin functions operate transparently on arrays. << osh> addprefix(-D, DEBUG WIN32) - : -DDEBUG -DWIN32 : Array osh> mapprefix(-I, /etc /tmp) - : -I /etc -I /tmp : Array osh> uppercase(fee fi foo fum) - : FEE FI FOO FUM : Array >> The `mapprefix' and `addprefix' functions are slightly different (the `addsuffix' and `mapsuffix' functions are similar). The `addprefix' adds the prefex to each array element. The `mapprefix' doubles the length of the array, adding the prefix as a new array element before each of the original elements. Even though most functions work on arrays, there are times when you will want to do it yourself. The `foreach' function is the way to go. The `foreach' function has two forms, but the form with a body is most useful. In this form, the function takes two arguments and a body. The second argument is an array, and the first is a variable. The body is evaluated once for each element of the array, where the variable is bound to the element. Let's define a function to add 1 to each element of an array of numbers. << osh> add1(l) = foreach(i, $l): add($i, 1) osh> add1(7 21 75) - : 8 22 76 : Array >> Sometimes you have an array of filenames, and you want to define a rule for each of them. Rules are not special, you can define them anywhere a statement is expected. Say we want to write a function that describes how to process each file, placing the result in the `tmp/' directory. << TMP = $(dir tmp) my-special-rule(files) = foreach(name, $(files)) $(TMP)/$(name): $(name) process $< > $@ >> Later, in some other part of the project, we may decide that we want to use this function to process some files. << # These are the files to process in src/lib MY_SPECIAL_FILES[] = fee.src fi.src file with spaces in its name.src my-special-rule($(MY_SPECIAL_FILES)) >> The result of calling `my-special-rule' is exactly the same as if we had written the following three rules explicitly. << $(TMP)/fee.src: fee.src process fee > $@ $(TMP)/fi.src: fi.src process fi.src > $@ $(TMP)/$"file with spaces in its name.src": $"file with spaces in its name.src" process $< > $@ >> Of course, writing these rules is not nearly as pleasant as calling the function. The usual properties of function abstraction give us the usual benefits. The code is less redundant, and there is a single location (the `my-special-rule' function) that defines the build rule. Later, if we want to modify/update the rule, we need do so in only one location.  Node: Section 6-5, Next: Subsection 6-5-1, Prev: Section 6-4, Up: Chapter 6 6.5 Lazy expressions *=*=*=*=*=*=*=*=*=*=*= Evaluation in omake is normally eager. That is, expressions are evaluated as soon as they are encountered by the evaluator. One effect of this is that the right-hand-side of a variable definition is expanded when the variable is defined. There are two ways to control this behavior. The `$`(v)' form introduces lazy behavior, and the `$,(v)' form restores eager behavior. Consider the following sequence. << osh> A = 1 - : "1" : Sequence osh> B = 2 - : "2" : Sequence osh> C = $`(add $(A), $,(B)) - : $(apply add $(apply A) "2" : Sequence) osh> println(C = $(C)) C = 3 osh> A = 5 - : "5" : Sequence osh> B = 6 - : "6" : Sequence osh> println(C = $(C)) C = 7 >> The definition `C = $`(add $(A), $,(B))' defines a lazy application. The `add' function is not applied in this case until its value is needed. Within this expression, the value `$,(B)' specifies that `B' is to be evaluated immediately, even though it is defined in a lazy expression. The first time that we print the value of `C', it evaluates to 3 since `A' is 1 and `B' is 2. The second time we evaluate `C', it evaluates to 7 because `A' has been redefined to `5'. The second definition of `B' has no effect, since it was evaluated at definition time. * Menu: * Subsection 6-5-1:: A larger example of lazy expressions  Node: Subsection 6-5-1, Next: Section 6-6, Prev: Section 6-5, Up: Section 6-5 6.5.1 A larger example of lazy expressions ============================================ Lazy expressions are not evaluated until their result is needed. Some people, including this author, frown on overuse of lazy expressions, mainly because it is difficult to know when evaluation actually happens. However, there are cases where they pay off. One example comes from option processing. Consider the specification of "include" directories on the command line for a C compiler. If we want to include files from /home/jyh/include and ../foo, we specify it on the command line with the options `-I/home/jyh/include -I../foo'. Suppose we want to define a generic rule for building C files. We could define a `INCLUDES' array to specify the directories to be included, and then define a generic implicit rule in our root OMakefile. << # Generic way to compile C files. CFLAGS = -g INCLUDES[] = %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $< # The src directory builds my_widget+ from 4 source files. # It reads include files from the include directory. .SUBDIRS: src FILES = fee fi foo fum OFILES = $(addsuffix .o, $(FILES)) INCLUDES[] += -I../include my_widget: $(OFILES) $(CC) $(CFLAGS) -o $@ $(OFILES) >> But this is not quite right. The problem is that INCLUDES is an array of options, not directories. If we later wanted to recover the directories, we would have to strip the leading `-I' prefix, which is a hassle. Furthermore, we aren't using proper names for the directories. The solution here is to use a lazy expression. We'll define INCLUDES as a directory array, and a new variable `PREFIXED_INCLUDES' that adds the -I prefix. The `PREFIXED_INCLUDES' is computed lazily, ensuring that the value uses the most recent value of the INCLUDES variable. << # Generic way to compile C files. CFLAGS = -g INCLUDES[] = PREFIXED_INCLUDES[] = $`(addprefix -I, $(INCLUDES)) %.o: %.c $(CC) $(CFLAGS) $(PREFIXED_INCLUDES) -c $< # For this example, we define a proper name for the include directory STDINCLUDE = $(dir include) # The src directory builds my_widget+ from 4 source files. # It reads include files from the include directory. .SUBDIRS: src FILES = fee fi foo fum OFILES = $(addsuffix .o, $(FILES)) INCLUDES[] += $(STDINCLUDE) my_widget: $(OFILES) $(CC) $(CFLAGS) -o $@ $(OFILES) >> Note that there is a close connection between lazy values and functions. In the example above, we could equivalently define `PREFIXED_INCLUDES' as a function with zero arguments. << PREFIXED_INCLUDES() = addprefix(-I, $(INCLUDES)) >>  Node: Section 6-6, Next: Section 6-7, Prev: Section 6-5, Up: Chapter 6 6.6 Scoping and exports *=*=*=*=*=*=*=*=*=*=*=*=* The OMake language is functional (apart from IO and shell commands). This comes in two parts: functions are first-class, and variables are immutable (there is no assignment operator). The latter property may seem strange to users used to GNU make, but it is actually a central point of OMake. Since variables can't be modified, it is impossible (or at least hard) for one part of the project to interfere with another. To be sure, pure functional programming can be awkward. In OMake, each new indentation level introduces a new scope, and new definitions in that scope are lost when the scope ends. If OMake were overly strict about scoping, we would wind up with a lot of convoluted code. << osh> X = 1 osh> setenv(BOO, 12) osh> if $(equal $(OSTYPE), Win32) setenv(BOO, 17) X = 2 osh> println($X $(getenv BOO)) 1 12 >> The `export' command presents a way out. It takes care of "exporting" a value (or the entire variable environment) from an inner scope to an outer one. << osh> X = 1 osh> setenv(BOO, 12) osh> if $(equal $(OSTYPE), Win32) setenv(BOO, 17) X = 2 export osh> println($X $(getenv BOO)) 2 17 >> Exports are especially useful in loop to export values from one iteration of a loop to the next. << # Ok, let's try to add up the elements of the array osh>sum(l) = total = 0 foreach(i, $l) total = $(add $(total), $i) value $(total) osh>sum(1 2 3) - : 0 : Int # Oops, that didn't work! osh>sum(l) = total = 0 foreach(i, $l) total = $(add $(total), $i) export value $(total) osh>sum(1 2 3) - : 6 : Int >> A `while' loop is another form of loop, with an auto-export. << osh>i = 0 osh>total = 0 osh>while $(lt $i, 10) total = $(add $(total), $i) i = $(add $i, 1) osh>println($(total)) 45 >>  Node: Section 6-7, Next: Section 6-8, Prev: Section 6-6, Up: Chapter 6 6.7 Shell aliases *=*=*=*=*=*=*=*=*=* Sometimes you may want to define an alias, an OMake command that masquerades as a real shell command. You can do this by adding your function as a method to the `Shell' object. For an example, suppose we use the `awk' function to print out all the comments in a file. << osh>cat comment.om # Comment function comments(filename) = awk($(filename)) case $'^#' println($0) # File finished osh>include comment osh>comments(comment.om) # Comment function # File finished >> To add it as an alias, add the method (using += to preserve the existing entries in the Shell). << osh>Shell. += printcom(argv) = comments($(nth 0, $(argv))) osh>printcom comment.om > output.txt osh>cat output.txt # Comment function # File finished >> A shell command is passed an array of arguments `argv'. This does not include the name of the alias.  Node: Section 6-8, Next: Chapter 7, Prev: Section 6-7, Up: Chapter 6 6.8 Input/output redirection on the cheap *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* As it turns out, scoping also provides a nice alternate way to perform redirection. Suppose you have already written a lot of code that prints to the standard output channel, but now you decide you want to redirect it. One way to do it is using the technique in the previous example: define your function as an alias, and then use shell redirection to place the output where you want. There is an alternate method that is easier in some cases. The variables `stdin', `stdout', and `stderr' define the standard I/O channels. To redirect output, redefine these variables as you see fit. Of course, you would normally do this in a nested scope, so that the outer channels are not affected. << osh>f() = println(Hello world) osh>f() Hello world osh>section: stdout = $(fopen output.txt, w) f() close($(stdout)) osh>cat output.txt Hello world >> This also works for shell commands. If you like to gamble, you can try the following example. << osh>f() = println(Hello world) osh>f() Hello world osh>section: stdout = $(fopen output.txt, w) f() cat output.txt close($(stdout)) osh>cat output.txt Hello world Hello world >>  Node: Chapter 7, Next: Section 7-1, Prev: Chapter 6, Up: Top Chapter 7 Rules ******************* Rules are used by OMake to specify how to build files. At its simplest, a rule has the following form. << : >> The `' is the name of a file to be built. The `' are a list of files that are needed before the `' can be built. The `' are a list of indented lines specifying commands to build the target. For example, the following rule specifies how to compile a file `hello.c'. << hello.o: hello.c $(CC) $(CFLAGS) -c -o hello.o hello.c >> This rule states that the hello.o file depends on the hello.c file. If the hello.c file has changed, the command `$(CC) $(CFLAGS) -c -o hello.o hello.c' is to be executed to update the target file `hello.o'. A rule can have an arbitrary number of commands. The individual command lines are executed independently by the command shell. The commands do not have to begin with a tab, but they must be indented from the dependency line. In addition to normal variables, the following special variables may be used in the body of a rule. - `$*': the target name, without a suffix. - `$@': the target name. - `$^': a list of the sources, in alphabetical order, with duplicates removed. - `$+': all the sources, in the original order. - `$<': the first source. For example, the above `hello.c' rule may be simplified as follows. << hello.o: hello.c $(CC) $(CFLAGS) -c -o $@ $< >> Unlike normal values, the variables in a rule body are expanded lazily, and binding is dynamic. The following function definition illustrates some of the issues. << CLibrary(name, files) = OFILES = $(addsuffix .o, $(files)) $(name).a: $(OFILES) $(AR) cq $@ $(OFILES) >> This function defines a rule to build a program called `$(name)' from a list of `.o' files. The files in the argument are specified without a suffix, so the first line of the function definition defines a variable `OFILES' that adds the `.o' suffix to each of the file names. The next step defines a rule to build a target library `$(name).a' from the `$(OFILES)' files. The expression `$(AR)' is evaluated when the function is called, and the value of the variable `AR' is taken from the caller's scope (see also the section on Scoping). * Menu: * Section 7-1:: Implicit rules * Section 7-2:: Bounded implicit rules * Section 7-3:: section * Section 7-4:: section rule * Section 7-5:: Special dependencies * Section 7-6:: '.SCANNER' rules * Section 7-7:: .DEFAULT * Section 7-8:: .SUBDIRS * Section 7-9:: .INCLUDE * Section 7-10:: .PHONY * Section 7-11:: Rule scoping * Section 7-12:: Running OMake from a subdirectory * Section 7-13:: Pathnames in rules  Node: Section 7-1, Next: Section 7-2, Prev: Chapter 7, Up: Chapter 7 7.1 Implicit rules *=*=*=*=*=*=*=*=*=*= Rules may also be implicit. That is, the files may be specified by wildcard patterns. The wildcard character is `%'. For example, the following rule specifies a default rule for building `.o' files. << %.o: %.c $(CC) $(CFLAGS) -c -o $@ $*.c >> This rule is a template for building an arbitrary `.o' file from a `.c' file. By default, implicit rules are only used for the targets in the current directory. However subdirectories included via the `.SUBDIRS' rules inherit all the implicit rules that are in scope (see also the section on Scoping).  Node: Section 7-2, Next: Section 7-3, Prev: Section 7-1, Up: Chapter 7 7.2 Bounded implicit rules *=*=*=*=*=*=*=*=*=*=*=*=*=*= Implicit rules may specify the set of files they apply to. The following syntax is used. << : : >> For example, the following rule applies only to the files `a.o' and `b.o'. << a.o b.o: %.o: %.c $(CC) $(CFLAGS) -DSPECIAL -c $*.c >>  Node: Section 7-3, Next: Section 7-4, Prev: Section 7-2, Up: Chapter 7 7.3 section *=*=*=*=*=*=* Frequently, the commands in a rule body are expressions to be evaluated by the shell. omake also allows expressions to be evaluated by omake itself. The syntax of these "computed rules" uses the `section' expression. The following rule uses the omake IO functions to produce the target `hello.c'. << hello.c: section FP = fopen(hello.c, w) fprintln($(FP), $""#include int main() { printf("Hello world\n"); }"") close($(FP)) >> This example uses the quotation `$""...""' (see also Section B.1.6*Note Subsection B-1-6::) to quote the text being printed. These quotes are not included in the output file. The `fopen', `fprintln', and `close' functions perform file IO as discussed in the IO section. In addition, commands that are function calls, or special expressions, are interpreted correctly. Since the `fprintln' function can take a file directly, the above rule can be abbreviated as follows. << hello.c: fprintln($@, $""#include int main() { printf("Hello world\n"); }"") >>  Node: Section 7-4, Next: Section 7-5, Prev: Section 7-3, Up: Chapter 7 7.4 section rule *=*=*=*=*=*=*=*=*= Rules can also be computed using the `section rule' form, where a rule body is expected instead of an expression. In the following rule, the file `a.c' is copied onto the `hello.c' file if it exists, otherwise `hello.c' is created from the file `default.c'. << hello.c: section rule if $(target-exists a.c) hello.c: a.c cat a.c > hello.c else hello.c: default.c cp default.c hello.c >>  Node: Section 7-5, Next: Subsection 7-5-1, Prev: Section 7-4, Up: Chapter 7 7.5 Special dependencies *=*=*=*=*=*=*=*=*=*=*=*=*= * Menu: * Subsection 7-5-1:: :exists: * Subsection 7-5-2:: :effects: * Subsection 7-5-3:: :value:  Node: Subsection 7-5-1, Next: Subsection 7-5-2, Prev: Section 7-5, Up: Section 7-5 7.5.1 :exists: ================ In some cases, the contents of a dependency do not matter, only whether the file exists or not. In this case, the `:exists:' qualifier can be used for the dependency. << foo.c: a.c :exists: .flag if $(test -e .flag) $(CP) a.c $@ >>  Node: Subsection 7-5-2, Next: Subsection 7-5-3, Prev: Subsection 7-5-1, Up: Section 7-5 7.5.2 :effects: ================= Some commands produce files by side-effect. For example, the latex(1) command produces a `.aux' file as a side-effect of producing a `.dvi' file. In this case, the `:effects:' qualifier can be used to list the side-effect explicitly. omake is careful to avoid simultaneously running programs that have overlapping side-effects. << paper.dvi: paper.tex :effects: paper.aux latex paper >>  Node: Subsection 7-5-3, Next: Section 7-6, Prev: Subsection 7-5-2, Up: Section 7-5 7.5.3 :value: =============== The `:value:' dependency is used to specify that the rule execution depends on the value of an expression. For example, the following rule << a: b c :value: $(X) ... >> specifies that "a" should be recompiled if the value of `$(X)' changes (X does not have to be a filename). This is intended to allow greater control over dependencies. In addition, it can be used instead of other kinds of dependencies. For example, the following rule: << a: b :exists: c commands >> is the same as << a: b :value: $(target-exists c) commands >> Notes: - The values are arbitrary (they are not limited to variables) - The values are evaluated at rule expansion time, so expressions containing variables like `$@', `$^', etc are legal.  Node: Section 7-6, Next: Subsection 7-6-1, Prev: Section 7-5, Up: Chapter 7 7.6 '.SCANNER' rules *=*=*=*=*=*=*=*=*=*=*= Scanner rules define a way to specify automatic dependency scanning. A `.SCANNER' rule has the following form. << .SCANNER: target: dependencies commands >> The rule is used to compute additional dependencies that might be defined in the source files for the specified target. The result of executing the scanner commands must be a sequence of dependencies in OMake format, printed to the standard output. For example, on GNU systems the `gcc -MM foo.c' produces dependencies for the file `foo.c' (based on `#include' information). We can use this to specify a scanner for C files that adds the scanned dependencies for the `.o' file. The following scanner specifies that dependencies for a file, say `foo.o' can be computed by running `gcc -MM foo.c'. Furthermore, `foo.c' is a dependency, so the scanner should be recomputed whenever the `foo.c' file changes. << .SCANNER: %.o: %.c gcc -MM $< >> Let's suppose that the command `gcc -MM foo.c' prints the following line. << foo.o: foo.h /usr/include/stdio.h >> The result is that the files `foo.h' and `/usr/include/stdio.h' are considered to be dependencies of `foo.o'---that is, `foo.o' should be rebuilt if either of these files changes. This works, to an extent. One nice feature is that the scanner will be re-run whenever the `foo.c' file changes. However, one problem is that dependencies in C are recursive. That is, if the file `foo.h' is modified, it might include other files, establishing further dependencies. What we need is to re-run the scanner if `foo.h' changes too. We can do this with a value dependency. The variable `$&' is defined as the dependency results from any previous scan. We can add these as dependencies using the `digest' function, which computes an MD5 digest of the files. << .SCANNER: %.o: %.c :value: $(digest $&) gcc -MM $< >> Now, when the file `foo.h' changes, its digest will also change, and the scanner will be re-run because of the value dependency (since `$&' will include `foo.h'). This still is not quite right. The problem is that the C compiler uses a search-path for include files. There may be several versions of the file `foo.h', and the one that is chosen depends on the include path. What we need is to base the dependencies on the search path. The `$(digest-in-path-optional ...)' function computes the digest based on a search path, giving us a solution that works. << .SCANNER: %.o: %.c :value: $(digest-in-path-optional $(INCLUDES), $&) gcc -MM $(addprefix -I, $(INCLUDES)) $< >> The standard output of the scanner rules will be captured by OMake and is not allowed to contain any content that OMake will not be able to parse as a dependency. The output is allowed to contain dependency specifications for unrelated targets, however such dependencies will be ignored. The scanner rules are allowed to produce arbitrary output on the standard error channel --- such output will be handled in the same way as the output of the ordinary rules (in other words, it will be presented to the user, when dictated by the `--output-'... options enabled). Additional examples of the `.SCANNER' rules can be found in Section 3.4.3*Note Subsection 3-4-3::. * Menu: * Subsection 7-6-1:: Named scanners, and the ':scanner:' dependencies * Subsection 7-6-2:: Notes  Node: Subsection 7-6-1, Next: Subsection 7-6-2, Prev: Section 7-6, Up: Section 7-6 7.6.1 Named scanners, and the ':scanner:' dependencies ======================================================== Sometimes it may be useful to specify explicitly which scanner should be used in a rule. For example, we might compile `.c' files with different options, or (heaven help us) we may be using both `gcc' and the Microsoft Visual C++ compiler `cl'. In general, the target of a `.SCANNER' is not tied to a particular target, and we may name it as we like. << .SCANNER: scan-gcc-%.c: %.c :value: $(digest-in-path-optional $(INCLUDES), $&) gcc -MM $(addprefix -I, $(INCLUDES)) $< .SCANNER: scan-cl-%.c: %.c :value: $(digest-in-path-optional $(INCLUDES), $&) cl --scan-dependencies-or-something $(addprefix /I, $(INCLUDES)) $< >> The next step is to define explicit scanner dependencies. The `:scanner:' dependency is used for this. In this case, the scanner dependencies are specified explicitly. << $(GCC_FILES): %.o: %.c :scanner: scan-gcc-%c gcc ... $(CL_FILES): %.obj: %.c :scanner: scan-cl-%c cl ... >> Explicit `:scanner:' scanner specification may also be used to state that a single `.SCANNER' rule should be used to generate dependencies for more than one target. For example, << .SCANNER: scan-all-c: $(GCC_FILES) :value: $(digest-in-path-optional $(INCLUDES), $&) gcc -MM $(addprefix -I, $(INCLUDES)) $(GCC_FILES) $(GCC_FILES): %.o: %.c :scanner: scan-all-c ... >> The above has the advantage of only running gcc once and a disadvantage that when a single source file changes, all the files will end up being re-scanned.  Node: Subsection 7-6-2, Next: Section 7-7, Prev: Subsection 7-6-1, Up: Section 7-6 7.6.2 Notes ============= In most cases, you won't need to define scanners of your own. The standard installation includes default scanners (both explicitly and implicitly named ones) for C, OCaml, and LaTeX files. The 'SCANNER_MODE' variable controls the usage of implicit scanner dependencies. The explicit `:scanner:' dependencies reduce the chances of scanner mis-specifications. In large complicated projects it might be a good idea to set `SCANNER_MODE' to `error' and use only the named `.SCANNER' rules and explicit `:scanner:' specifications.  Node: Section 7-7, Next: Section 7-8, Prev: Section 7-6, Up: Chapter 7 7.7 .DEFAULT *=*=*=*=*=*=*= The `.DEFAULT' target specifies a target to be built by default if omake is run without explicit targets. The following rule instructs omake to build the program `hello' by default << .DEFAULT: hello >>  Node: Section 7-8, Next: Section 7-9, Prev: Section 7-7, Up: Chapter 7 7.8 .SUBDIRS *=*=*=*=*=*=*= The `.SUBDIRS' target is used to specify a set of subdirectories that are part of the project. Each subdirectory should have its own OMakefile, which is evaluated in the context of the current environment. << .SUBDIRS: src doc tests >> This rule specifies that the `OMakefile's in each of the `src', `doc', and `tests' directories should be read. In some cases, especially when the `OMakefile's are very similar in a large number of subdirectories, it is inconvenient to have a separate `OMakefile' for each directory. If the `.SUBDIRS' rule has a body, the body is used instead of the `OMakefile'. << .SUBDIRS: src1 src2 src3 println(Subdirectory $(CWD)) .DEFAULT: lib.a >> In this case, the `src1', `src2', and `src3' files do not need `OMakefile's. Furthermore, if one exists, it is ignored. The following includes the file if it exists. << .SUBDIRS: src1 src2 src3 if $(file-exists OMakefile) include OMakefile .DEFAULT: lib.a >>  Node: Section 7-9, Next: Section 7-10, Prev: Section 7-8, Up: Chapter 7 7.9 .INCLUDE *=*=*=*=*=*=*= The `.INCLUDE' target is like the `include' directive, but it specifies a rule to build the file if it does not exist. << .INCLUDE: config echo "CONFIG_READ = true" > config echo CONFIG_READ is $(CONFIG_READ) >> You may also specify dependencies to an `.INCLUDE' rule. << .INCLUDE: config: config.defaults cp config.defaults config >> A word of caution is in order here. The usual policy is used for determining when the rule is out-of-date. The rule is executed if any of the following hold. - the target does not exist, - the rule has never been executed before, - any of the following have changed since the last time the rule was executed, - the target, - the dependencies, - the commands-text. In some of the cases, this will mean that the rule is executed even if the target file already exists. If the target is a file that you expect to edit by hand (and therefore you don't want to overwrite it), you should make the rule evaluation conditional on whether the target already exists. << .INCLUDE: config: config.defaults # Don't overwrite my carefully hand-edited file if $(not $(file-exists config)) cp config.defaults config >>  Node: Section 7-10, Next: Section 7-11, Prev: Section 7-9, Up: Chapter 7 7.10 .PHONY *=*=*=*=*=*=* A "phony" target is a target that is not a real file, but exists to collect a set of dependencies. Phony targets are specified with the `.PHONY' rule. In the following example, the `install' target does not correspond to a file, but it corresponds to some commands that should be run whenever the `install' target is built (for example, by running `omake install'). << .PHONY: install install: myprogram.exe cp myprogram.exe /usr/bin >>  Node: Section 7-11, Next: Subsection 7-11-1, Prev: Section 7-10, Up: Chapter 7 7.11 Rule scoping *=*=*=*=*=*=*=*=*=* As we have mentioned before, omake is a scoped language. This provides great flexibility---different parts of the project can define different configurations without interfering with one another (for example, one part of the project might be compiled with `CFLAGS=-O3' and another with `CFLAGS=-g'). But how is the scope for a target file selected? Suppose we are building a file `dir/foo.o'. omake uses the following rules to determine the scope. - First, if there is an explicit rule for building `dir/foo.o' (a rule with no wildcards), the context for that rule determines the scope for building the target. - Otherwise, the directory `dir/' must be part of the project. This normally means that a configuration file `dir/OMakefile' exists (although, see the `.SUBDIRS' section for another way to specify the `OMakefile'). In this case, the scope of the target is the scope at the end of the `dir/OMakefile'. To illustrate rule scoping, let's go back to the example of a "Hello world" program with two files. Here is an example `OMakefile' (the two definitions of `CFLAGS' are for illustration). << # The executable is compiled with debugging CFLAGS = -g hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ # Redefine CFLAGS CFLAGS += -O3 >> In this project, the target `hello' is explicit. The scope of the `hello' target is the line beginning with `hello:', where the value of `CFLAGS' is `-g'. The other two targets, `hello_code.o' and `hello_lib.o' do not appear as explicit targets, so their scope is at the end of the `OMakefile', where the `CFLAGS' variable is defined to be `-g -O3'. That is, `hello' will be linked with `CFLAGS=-g' and the `.o' files will be compiled with `CFLAGS=-g -O3'. We can change this behavior for any of the targets by specifying them as explicit targets. For example, suppose we wish to compile `hello_lib.o' with a preprocessor variable `LIBRARY'. << # The executable is compiled with debugging CFLAGS = -g hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ # Compile hello_lib.o with CFLAGS = -g -DLIBRARY section CFLAGS += -DLIBRARY hello_lib.o: # Redefine CFLAGS CFLAGS += -O3 >> In this case, `hello_lib.o' is also mentioned as an explicit target, in a scope where `CFLAGS=-g -DLIBRARY'. Since no rule body is specified, it is compiled using the usual implicit rule for building `.o' files (in a context where `CFLAGS=-g -DLIBRARY'). * Menu: * Subsection 7-11-1:: Scoping of implicit rules * Subsection 7-11-2:: Scoping of '.SCANNER' rules * Subsection 7-11-3:: Scoping for '.PHONY' targets  Node: Subsection 7-11-1, Next: Subsection 7-11-2, Prev: Section 7-11, Up: Section 7-11 7.11.1 Scoping of implicit rules ================================== Implicit rules (rules containing wildcard patterns) are not global, they follow the normal scoping convention. This allows different parts of a project to have different sets of implicit rules. If we like, we can modify the example above to provide a new implicit rule for building `hello_lib.o'. << # The executable is compiled with debugging CFLAGS = -g hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ # Compile hello_lib.o with CFLAGS = -g -DLIBRARY section %.o: %.c $(CC) $(CFLAGS) -DLIBRARY -c $< hello_lib.o: # Redefine CFLAGS CFLAGS += -O3 >> In this case, the target `hello_lib.o' is built in a scope with a new implicit rule for building `%.o' files. The implicit rule adds the `-DLIBRARY' option. This implicit rule is defined only for the target `hello_lib.o'; the target `hello_code.o' is built as normal.  Node: Subsection 7-11-2, Next: Subsection 7-11-3, Prev: Subsection 7-11-1, Up: Section 7-11 7.11.2 Scoping of '.SCANNER' rules ==================================== Scanner rules are scoped the same way as normal rules. If the `.SCANNER' rule is explicit (containing no wildcard patterns), then the scope of the scan target is the same as the the rule. If the `.SCANNER' rule is implicit, then the environment is taken from the `:scanner:' dependency. << # The executable is compiled with debugging CFLAGS = -g hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ # scanner for .c files .SCANNER: scan-c-%.c: %.c $(CC) $(CFLAGS) -MM $< # Compile hello_lib.o with CFLAGS = -g -DLIBRARY section CFLAGS += -DLIBRARY hello_lib.o: hello_lib.c :scanner: scan-c-hello_lib.c $(CC) $(CFLAGS) -c $< # Compile hello_code.c with CFLAGS = -g -O3 section CFLAGS += -O3 hello_code.o: hello_code.c :scanner: scan-c-hello_code.c $(CC) $(CFLAGS) -c $< >> Again, this is for illustration---it is unlikely you would need to write a complicated configuration like this! In this case, the `.SCANNER' rule specifies that the C-compiler should be called with the `-MM' flag to compute dependencies. For the target `hello_lib.o', the scanner is called with `CFLAGS=-g -DLIBRARY', and for `hello_code.o' it is called with `CFLAGS=-g -O3'.  Node: Subsection 7-11-3, Next: Section 7-12, Prev: Subsection 7-11-2, Up: Section 7-11 7.11.3 Scoping for '.PHONY' targets ===================================== Phony targets (targets that do not correspond to files) are defined with a `.PHONY:' rule. Phony targets are scoped as usual. The following illustrates a common mistake, where the `.PHONY' target is declared after it is used. << # !!This example is broken!! all: hello hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ .PHONY: all >> This doesn't work as expected because the `.PHONY' declaration occurs too late. The proper way to write this example is to place the `.PHONY' declaration first. << # Phony targets must be declared before being used .PHONY: all all: hello hello: hello_code.o hello_lib.o $(CC) $(CFLAGS) -o $@ $+ >> Phony targets are passed to subdirectories. As a practical matter, it is wise to declare all `.PHONY' targets in your root `OMakefile', before any `.SUBDIRS'. This will ensure that 1) they are considered as phony targets in each of the subdirectories, and 2) you can build them from the project root. << .PHONY: all install clean .SUBDIRS: src lib clib >> Note that when a `.PHONY' target is inherited by a subdirectory via a `.SUBDIRS', a whole hierarchy of `.PHONY' target (that are a part of the global one) is created, as described in Section 7.12.2*Note Subsection 7-12-2:: below.  Node: Section 7-12, Next: Subsection 7-12-1, Prev: Section 7-11, Up: Chapter 7 7.12 Running OMake from a subdirectory *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Running `omake foo' asks OMake to build the file `foo' in context of the whole project, even when running from a subdirectory of the project. Therefore, if `bar/baz' is a regular target (not a `.PHONY' one), then running `omake bar/baz' and running `(cd bar; omake baz)' are usually equivalent. There are two noteworthy exceptions to the above rule: - If the subdirectory is not a part of the project (there is no `.SUBDIRS') for it, then OMake will complain if you try to run it in that directory. - If a subdirectory contains an `OMakeroot' of its own, this would designate the subdirectory as a separate project (which is usually a bad idea and is not recommended). * Menu: * Subsection 7-12-1:: Phony targets in a subdirectory * Subsection 7-12-2:: Hierarchy of '.PHONY' targets  Node: Subsection 7-12-1, Next: Subsection 7-12-2, Prev: Section 7-12, Up: Section 7-12 7.12.1 Phony targets in a subdirectory ======================================== \@n ame{@default56} Suppose you have a `.PHONY: clean' declared in your root `OMakefile' and both the root `OMakefile' and the `OMakefile' in some of the subdirectories contain `clean:' rules. In this case - Running `omake clean' in the root directory will execute all the rules (each in the appropriate directory); - Running `omake clean' in the subdirectory will execute just its local one, as well as the ones from the subdirectories of the current directory. The above equally applies to the built-in `.PHONY' targets, including '.DEFAULT'. Namely, if OMake is executed (without argument) in the root directory of a project, all the `.DEFAULT' targets in the project will be built. On the other hand, when OMake is executed (without argument) in a subdirectory, only the `.DEFAULT' targets defined in and under that subdirectory will be built. The following Section explains the underlying semantics that gives rise to the above behavior.  Node: Subsection 7-12-2, Next: Section 7-13, Prev: Subsection 7-12-1, Up: Section 7-12 7.12.2 Hierarchy of '.PHONY' targets ====================================== When the the root `OMakefile' contains a `.PHONY: clean' directive, it creates: - A "global" phony target `/.PHONY/clean' (note the leading "`/'"); - A "relative" phony target attached to the current directory --- `.PHONY/clean' (note the lack of the leading "`/'"); - A dependency `/.PHONY/clean: .PHONY/clean'. All the `clean: ...' rules in the root `OMakefile' following this `.PHONY: clean' declaration would be interpreted as rules for the `.PHONY/clean' target. Now when OMake then comes across a `.SUBDIRS: foo' directive (when it is in scope of the above `.PHONY: clean' declaration), it does the following: - Creates a new `.PHONY/foo/clean' "relative" phony target; - Creates the dependency `.PHONY/clean: .PHONY/foo/clean'; - Processes the body of the `.SUBDIRS: foo' directive, or reads the `foo/OMakefile' file, if the body is empty. While doing that, it interprets its instructions relative to the `foo' directory. In particular, all the `clean: ...' rules will be taken to apply to `.PHONY/foo/clean'. Now when you run `omake clean' in the root directory of the project, it is interpreted as `omake .PHONY/clean' (similar to how it happens with the normal targets), so both the rules for `.PHONY/clean' are executed and the rules for its dependency `.PHONY/foo/clean'. Running `(cd foo; omake clean)' is, as for normal targets, equivalent to running `omake .PHONY/foo/clean' and only those rules that apply to `.PHONY/foo/clean' will be executed.  Node: Section 7-13, Next: Chapter 8, Prev: Section 7-12, Up: Chapter 7 7.13 Pathnames in rules *=*=*=*=*=*=*=*=*=*=*=*=* In rules, the targets and dependencies are first translated to file values (as in the 'file' function). They are then translated to strings for the command line. This can cause some unexpected behavior. In the following example, the 'absname' function is the absolute pathname for the file `a', but the rule still prints the relative pathname. << .PHONY: demo demo: $(absname a) echo $< # omake demo a >> There is arguably a good reason for this. On Win32 systems, the `/' character is viewed as an "option specifier." The pathname separator is the `\' character. OMake translates the filenames automatically so that things work as expected on both systems. << demo: a/b echo $< # omake demo (on a Unix system) a/b # omake demo (on a Win32 system) a\b >> Sometimes you may wish that target strings to be passed literally to the commands in the rule. One way to do this is to specify them literally. << SRC = a/b $(absname c/d) demo: $(SRC) echo $(SRC) # omake demo (on a Win32 system) a/b c:\...\c\d >> Alternately, you might wish that filenames be automatically expanded to absolute pathnames. For example, this might be useful when parsing the OMake output to look for errors. For this, you can use the `--absname' option (Section A.3.20*Note Subsection A-3-20::). If you call `omake' with the `--absname' option, all filenames will be expanded to absolute names. << # omake --absname demo (on a Unix system) /home/.../a/b /home/.../c/d >> Alternately, the `--absname' option is scoped. If you want to use it for only a few rules, you can use the 'OMakeFlags' function to control how it is applied. << section OMakeFlags(--absname) demo: a echo $< # omake demo /home/.../a >> N.B. The `--absname' option is currently an experimental feature.  Node: Chapter 8, Next: Section 8-1, Prev: Chapter 7, Up: Top Chapter 8 Base library ************************** * Menu: * Section 8-1:: Builtin variables * Section 8-2:: Logic, Boolean functions, and control flow * Section 8-3:: Arrays and sequences * Section 8-4:: Arithmetic * Section 8-5:: First-class functions * Section 8-6:: Iteration and mapping  Node: Section 8-1, Next: Section 8-2, Prev: Chapter 8, Up: Chapter 8 8.1 Builtin variables *=*=*=*=*=*=*=*=*=*=*=* OMAKE_VERSION Version of OMake. STDLIB The directory where the OMake standard library files reside. At startup, the default value is determined as follows. - The value of the `OMAKELIB' environment variable, if set (must contain an absolute path, if set), otherwise - On Windows, the registry keys `HKEY_CURRENT_USER\SOFTWARE\MetaPRL\OMake\OMAKELIB' and `HKEY_LOCAL_MACHINE\SOFTWARE\MetaPRL\OMake\OMAKELIB' are looked up and the value is used, if exist. - Otherwise a compile-time default it used. The current default value may be accessed by running `omake --version' OMAKEPATH An array of directories specifying the lookup path for the `include' and `open' directives (see Section 4.7*Note Section 4-7::). The default value is an array of two elements --- `.' and `$(STDLIB)'. OSTYPE Set to the machine architecture omake is running on. Possible values are `Unix' (for all Unix versions, including Linux and Mac OS X), `Win32' (for MS-Windows, OMake compiled with MSVC++ or Mingw), and `Cygwin' (for MS-Windows, OMake compiled with Cygwin). SYSNAME The name of the operating system for the current machine. NODENAME The hostname of the current machine. OS_VERSION The operating system release. MACHINE The machine architecture, e.g. `i386', `sparc', etc. HOST Same as `NODENAME'. USER The login name of the user executing the process. HOME The home directory of the user executing the process. PID The OMake process id. TARGETS The command-line target strings. For example, if OMake is invoked with the following command line, << omake CFLAGS=1 foo bar.c >> then `TARGETS' is defined as `foo bar.c'. BUILD_SUMMARY The `BUILD_SUMMARY' variable refers to the file that `omake' uses to summarize a build (the message that is printed at the very end of a build). The file is empty when the build starts. If you wish to add additional messages to the build summary, you can edit/modify this file during the build. For example, if you want to point out that some action was taken, you can append a message to the build summary. << foo: boo echo "The file foo was built" >> $(BUILD_SUMMARY) ...build foo... >> VERBOSE Whether certain commands should be verbose. A boolean flag that is `false' by default and is set to `true' when OMake is invoked with the `--verbose' option.  Node: Section 8-2, Next: Subsection 8-2-1, Prev: Section 8-1, Up: Chapter 8 8.2 Logic, Boolean functions, and control flow *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*= Boolean values in omake are represented by case-insensitive strings. The false value can be represented by the strings `false', `no', `nil', `undefined' or `0', and everything else is true. * Menu: * Subsection 8-2-1:: not * Subsection 8-2-2:: equal * Subsection 8-2-3:: and * Subsection 8-2-4:: or * Subsection 8-2-5:: if * Subsection 8-2-6:: switch, match * Subsection 8-2-7:: try * Subsection 8-2-8:: raise * Subsection 8-2-9:: exit * Subsection 8-2-10:: defined * Subsection 8-2-11:: defined-env * Subsection 8-2-12:: getenv * Subsection 8-2-13:: setenv * Subsection 8-2-14:: unsetenv * Subsection 8-2-15:: get-registry * Subsection 8-2-16:: getvar * Subsection 8-2-17:: setvar  Node: Subsection 8-2-1, Next: Subsection 8-2-2, Prev: Section 8-2, Up: Section 8-2 8.2.1 not =========== << $(not e) : String e : String >> The `not' function negates a Boolean value. For example, `$(not false)' expands to the string `true', and `$(not hello world)' expands to `false'.  Node: Subsection 8-2-2, Next: Subsection 8-2-3, Prev: Subsection 8-2-1, Up: Section 8-2 8.2.2 equal ============= << $(equal e1, e2) : String e1 : String e2 : String >> The `equal' function tests for equality of two values. For example `$(equal a, b)' expands to `false', and `$(equal hello world, hello world)' expands to `true'.  Node: Subsection 8-2-3, Next: Subsection 8-2-4, Prev: Subsection 8-2-2, Up: Section 8-2 8.2.3 and =========== << $(and e1, ..., en) : String e1, ..., en: Sequence >> The `and' function evaluates to the conjunction of its arguments. For example, in the following code, `X' is true, and `Y' is false. << A = a B = b X = $(and $(equal $(A), a) true $(equal $(B), b)) Y = $(and $(equal $(A), a) true $(equal $(A), $(B))) >>  Node: Subsection 8-2-4, Next: Subsection 8-2-5, Prev: Subsection 8-2-3, Up: Section 8-2 8.2.4 or ========== << $(or e1, ..., en) : String e1, ..., en: String Sequence >> The `or' function evaluates to the disjunction of its arguments. For example, in the following code, `X' is true, and `Y' is false. << A = a B = b X = $(or $(equal $(A), a) false $(equal $(A), $(B))) Y = $(or $(equal $(A), $(B)) $(equal $(A), b)) >>  Node: Subsection 8-2-5, Next: Subsection 8-2-6, Prev: Subsection 8-2-4, Up: Section 8-2 8.2.5 if ========== << $(if e1, e2[, e3]) : value e1 : String e2, e3 : value >> The `if' function represents a conditional based on a Boolean value. For example `$(if $(equal a, b), c, d)' evaluates to `d'. Conditionals may also be declared with an alternate syntax. << if e1 body1 elseif e2 body2 ... else bodyn >> If the expression `e1' is not false, then the expressions in `body1' are evaluated and the result is returned as the value of the conditional. Otherwise, if `e1' evaluates to false, the evaluation continues with the `e2' expression. If none of the conditional expressions is true, then the expressions in `bodyn' are evaluated and the result is returned as the value of the conditional. There can be any number of `elseif' clauses; the `else' clause is optional. Note that each branch of the conditional defines its own scope, so variables defined in the branches are normally not visible outside the conditional. The `export' command may be used to export the variables defined in a scope. For example, the following expression represents a common idiom for defining the C compiler configuration. << if $(equal $(OSTYPE), Win32) CC = cl CFLAGS += /DWIN32 export else CC = gcc CFLAGS += -g -O2 export >>  Node: Subsection 8-2-6, Next: Subsection 8-2-7, Prev: Subsection 8-2-5, Up: Section 8-2 8.2.6 switch, match ===================== The `switch' and `match' functions perform pattern matching. `$(switch , , , ..., , )' `$(match , , , ..., , )' The number of `/' pairs is arbitrary. They strictly alternate; the total number of arguments to `' must be odd. The `' is evaluated to a string, and compared with `'. If it matches, the result of the expression is `'. Otherwise evaluation continues with the remaining patterns until a match is found. If no pattern matches, the value is the empty string. The `switch' function uses string comparison to compare the argument with the patterns. For example, the following expression defines the `FILE' variable to be either `foo', `bar', or the empty string, depending on the value of the `OSTYPE' variable. << FILE = $(switch $(OSTYPE), Win32, foo, Unix, bar) >> The `match' function uses regular expression patterns (see the `grep' function). If a match is found, the variables `$1, $2, ...' are bound to the substrings matched between `\(' and `\)' delimiters. The `$0' variable contains the entire match, and `$*' is an array of the matched substrings. to the matched substrings. << FILE = $(match foo_xyz/bar.a, foo_\\\(.*\\\)/\\\(.*\\\)\.a, foo_$2/$1.o) >> The `switch' and `match' functions also have an alternate (more usable) form. << match e case pattern1 body1 case pattern2 body2 ... default bodyd >> If the value of expression `e' matches `pattern_i' and no previous pattern, then `body_i' is evaluated and returned as the result of the `match'. The `switch' function uses string comparison; the `match' function uses regular expression matching. << match $(FILE) case $".*\(\.[^\/.]*\)" println(The string $(FILE) has suffix $1) default println(The string $(FILE) has no suffix) >>