diff --git a/doc/texinfo/sake-doc.html b/doc/texinfo/sake-doc.html index 2e39010..73a2d81 100644 --- a/doc/texinfo/sake-doc.html +++ b/doc/texinfo/sake-doc.html @@ -1343,11 +1343,150 @@

4 Advanced Sake Usage

4.1 Using Patterns

-

hi +

Sake may have a strong preference for elegance and simplicity, but that +doesn’t mean Sake is lacking advanced features. One such feature is +’formula patterns’. +

+

Very often in project building, the same procedure has to be performed +on many similar files. Formula patterns allow you to condense all of the +targets down to one that gets automatically autoexpanded. If you find +yourself with targets that have identical formulas except for a file +that changes from target to target, this might be a perfect application +for formula patterns. +

+

Concretely, it is a common C programming/compilation idiom to compile all +C files in a directory into object files (which then get linked together). +If there are four such .c files (file1.c, file2.c file3.c, and file4.c) +in a directory that all need to be object-compiled, you certainly +can create four different targets to perform this, but you can +also leverage formula patterns here. +

+

If the original Sakefile snippet looked like this: +

+
compile C file1:
+    help: compiles C file 1
+    dependencies:
+        - "file1.c"
+    formula: >
+        gcc -c -o file1.o file1.c
+    output:
+        - file1.o
+
+compile C file2:
+    help: compiles C file 2
+    ....
+
+ +

the new target to replace the four targets above will look like: +

+
compile %cfiles:
+    help: compiles file %cfiles into object file
+    dependencies:
+        - "%cfiles.c"
+    formula: >
+        gcc -c -o %cfiles.o %cfiles.c
+    output:
+        - %cfiles
+
+ +

This may appear as but one target in the Sakefile, but as far as Sake is +concerned, these are four different targets (or how ever many files the +pattern matches–it was just four in our example). +

+

To prove it, sake help will yield: +

+
"compile file1":
+  - compiles file file1 into object file
+
+"compile file2":
+  - compiles file file2 into object file
+...
+
+ +

Additionally, since these are separate targets, sake visual will +render them separately, and parallel sake will run them in parallel, if +applicable. +

+

Note that anywhere in the target the string "%cfiles" is used, the +substitution is of the base name of the file, and not the file extentions. +

+

For another example, say you have to convert all png images in a directory +to jpeg files; you have a program called "picconvert" that performes the +conversion. The Sakefile snippet will look a little like this: +

+
convert %picfile:
+    dependencies:
+        - %picfile.png
+    formula: >
+        picconvert --from png --to jpg %picfile.png %picfile.jpg
+    output:
+        - %picfile.jpg
+
+ +

When using patterns in your Sakefiles, there are four things to keep in mind +

    +
  1. The pattern must appear in the dependency field. +
  2. A target that has a pattern in the dependency must have the pattern in the +target name. Because Sake treats every file match as a new target, and +different targets cannot share a name, the pattern must be in the target name +to get outexpanded and keep the target names different and specific. +
  3. A target using a pattern must use the pattern in its formula. +
  4. A target using a pattern must have an output, and must use the pattern +in the output +
+

Don’t be worried about this requirements; It is hard to think of a +legitimate usage of formula patterns that will violate any of the rules above.

4.2 Using Includes

-

hi +

Sake’s second advanced feature is called "includes". +

+

Includes are a lot like storing macros in a different file and then +importing those macro definitions into your Sakefile. +

+

The primary use case for this feature would be to use the same Sakefile +across different architectures/platforms but be able to substitute +values for platform dependent variables. +

+

For example, let’s say a C project decides to support the two most +popular open source C compilers, clang and gcc. It would be silly to write +two different Sakefiles–one that uses gcc for compilation, and one that uses +clang for compilation–and switch which Sakefile you use dependending on +the machine being used. +

+

Instead, a program can be run to interrogate a system, find the name of the +extant/preferred C compiler, and drop that into a yaml file as a Sake +compatible macro. That very macro can then be included in the Sakefile. +

+

Concretely, let’s say a configure script is run and it determines that gcc is +the preferred C compiler. It can then create a file called config.yaml +with the following content: +

+
#! C_Compiler=gcc
+
+ +

In the Sakefile, we can include a line like this: +

+
#< config.yaml
+
+

This will make the C_Compiler macro available for use in the Sakefile. +(Note that "config.yaml" could have been named anything.) +

+

If you include a non-existent config file, sake will throw a fatal +error. There may be a use case, however, where you would like to include a +macro definition file, but don’t want to strictly require it. In this +case, you can label the include file optional, as in this line: +

+
#< filetoinclude.yaml optional
+
+ +

It is also possible to raise a warning when an optional include file is +missing; the user will see this warning everytime sake is run until +the include file becomes existent. This can be done thusly: +

+
#< filetoinclude.yaml or warning: include file missing
+
+

Everything after the "or" will be considered the warning message.


diff --git a/doc/texinfo/sake-doc.pdf b/doc/texinfo/sake-doc.pdf index dcd5934..a0f8d23 100644 Binary files a/doc/texinfo/sake-doc.pdf and b/doc/texinfo/sake-doc.pdf differ diff --git a/doc/texinfo/sake-doc.texi b/doc/texinfo/sake-doc.texi index df10279..bb0e5e4 100644 --- a/doc/texinfo/sake-doc.texi +++ b/doc/texinfo/sake-doc.texi @@ -1324,11 +1324,155 @@ The Sakefile in the example above will yield a visualization like this: @c ----------------------- @section Using Patterns -hi +Sake may have a strong preference for elegance and simplicity, but that +doesn't mean Sake is lacking advanced features. One such feature is +'formula patterns'. + +Very often in project building, the same procedure has to be performed +on many similar files. Formula patterns allow you to condense all of the +targets down to one that gets automatically autoexpanded. If you find +yourself with targets that have identical formulas except for a file +that changes from target to target, this might be a perfect application +for formula patterns. + +Concretely, it is a common C programming/compilation idiom to compile all +C files in a directory into object files (which then get linked together). +If there are four such .c files (file1.c, file2.c file3.c, and file4.c) +in a directory that all need to be object-compiled, you certainly +@emph{can} create four different targets to perform this, but you can +also leverage formula patterns here. + +If the original Sakefile snippet looked like this: +@example +compile C file1: + help: compiles C file 1 + dependencies: + - "file1.c" + formula: > + gcc -c -o file1.o file1.c + output: + - file1.o + +compile C file2: + help: compiles C file 2 + .... +@end example + +the new target to replace the four targets above will look like: +@example +compile %cfiles: + help: compiles file %cfiles into object file + dependencies: + - "%cfiles.c" + formula: > + gcc -c -o %cfiles.o %cfiles.c + output: + - %cfiles +@end example + +This may appear as but one target in the Sakefile, but as far as Sake is +concerned, these are four different targets (or how ever many files the +pattern matches--it was just four in our example). + +To prove it, @code{sake help} will yield: +@example +"compile file1": + - compiles file file1 into object file + +"compile file2": + - compiles file file2 into object file +... +@end example + +Additionally, since these are separate targets, @code{sake visual} will +render them separately, and parallel sake will run them in parallel, if +applicable. + +Note that anywhere in the target the string "@code{%cfiles}" is used, the +substitution is of the base name of the file, and not the file extentions. + +For another example, say you have to convert all png images in a directory +to jpeg files; you have a program called "picconvert" that performes the +conversion. The Sakefile snippet will look a little like this: +@example +convert %picfile: + dependencies: + - %picfile.png + formula: > + picconvert --from png --to jpg %picfile.png %picfile.jpg + output: + - %picfile.jpg +@end example + +When using patterns in your Sakefiles, there are four things to keep in mind +@enumerate +@item +The pattern must appear in the dependency field. +@item +A target that has a pattern in the dependency must have the pattern in the +target name. Because Sake treats every file match as a new target, and +different targets cannot share a name, the pattern must be in the target name +to get outexpanded and keep the target names different and specific. +@item +A target using a pattern must use the pattern in its formula. +@item +A target using a pattern must have an output, and must use the pattern +in the output +@end enumerate +Don't be worried about this requirements; It is hard to think of a +legitimate usage of formula patterns that will violate any of the rules above. @c ----------------------- +@c ----------------------- @section Using Includes -hi +Sake's second advanced feature is called "includes". + +Includes are a lot like storing macros in a different file and then +importing those macro definitions into your Sakefile. + +The primary use case for this feature would be to use the same Sakefile +across different architectures/platforms but be able to substitute +values for platform dependent variables. + +For example, let's say a C project decides to support the two most +popular open source C compilers, clang and gcc. It would be silly to write +two different Sakefiles--one that uses gcc for compilation, and one that uses +clang for compilation--and switch which Sakefile you use dependending on +the machine being used. + +Instead, a program can be run to interrogate a system, find the name of the +extant/preferred C compiler, and drop that into a yaml file as a Sake +compatible macro. That very macro can then be included in the Sakefile. + +Concretely, let's say a configure script is run and it determines that gcc is +the preferred C compiler. It can then create a file called @code{config.yaml} +with the following content: +@example +#! C_Compiler=gcc +@end example + +In the Sakefile, we can include a line like this: +@example +#< config.yaml +@end example +This will make the @code{C_Compiler} macro available for use in the Sakefile. +(Note that "@code{config.yaml}" could have been named anything.) + +If you include a non-existent config file, @code{sake} will throw a fatal +error. There may be a use case, however, where you would like to include a +macro definition file, but don't want to strictly @emph{require} it. In this +case, you can label the include file @code{optional}, as in this line: +@example +#< filetoinclude.yaml optional +@end example + +It is also possible to raise a warning when an optional include file is +missing; the user will see this warning everytime @code{sake} is run until +the include file becomes existent. This can be done thusly: +@example +#< filetoinclude.yaml or warning: include file missing +@end example +Everything after the "@code{or}" will be considered the warning message. @c ----------------------- @c -------------------------------------------------------------------- diff --git a/functests/test3/Sakefile.yaml b/functests/test3/Sakefile.yaml index 95244fb..9007b8f 100644 --- a/functests/test3/Sakefile.yaml +++ b/functests/test3/Sakefile.yaml @@ -4,7 +4,7 @@ ## #< config.yaml -###< optional.yaml or this was optional anyways +######< optional.yaml or this was optional anyways #< optional.yaml optional #! CFLAGS=-w -O2 -I./include diff --git a/sakelib/acts.py b/sakelib/acts.py index b494edf..a3b2f87 100644 --- a/sakelib/acts.py +++ b/sakelib/acts.py @@ -169,7 +169,7 @@ def expand_macros(raw_text, macros={}): includes = {} result = [] pattern = re.compile("#!\s*(\w+)\s*=\s*(.+$)", re.UNICODE) - ipattern = re.compile("#<\s*(\S+)\s*(optional|or\s+(.+))?$") + ipattern = re.compile("#<\s*(\S+)\s*(optional|or\s+(.+))?$", re.UNICODE) for line in raw_text.split("\n"): line = string.Template(line).safe_substitute(macros) # note that the line is appended to result before it is checked for macros