Makepp Advanced

Advanced uses for makepp

There is a popular myth that makepp is for compiling programs. In fact it is an abstract rule based mechanisms for creating files from other files whenever those change.

Web pages

Instead of learning one of the template engines out there, you can use makepp's builtin &preprocess command, the language of which you know from writing makefiles. It is not a CGI mechanism (though that should be achievable by sourcing in the makeppbuiltin wrapper) and it doesn't have all the bells and whistles (though you can define neat things). But this allows you to separate content from form, and both can be dynamic at generation time, which is enough for a medium size web site. The result is a static page, which can of course contain AJAX elements. E.g. you can split up the page into a head, body and foot:

%.html: %.shtml $(find-upwards $( head foot).html.mk)
    # %-element must be first above, but reorder it between head and foot:
    &preprocess $(HTMLFLAGS) $(inputs 2 1 3) -o $(output)
happy.html: HTMLFLAGS += TITLE='My Happy Page' KEYWORDS=happy,lucky 
$(phony all): *.html
 

This introduces new file-types .shtml and .html.mk, the distinction being made so that the all-target doesn't produce head.html and foot.html. You can pick any suffixes which your editor will handle as HTML, since the content is just that. But makepp $(...) expressions are evaluated, and conditional statements and include/_include, perl/makeperl/perl_begin or sub/makesub are evaluated.

More Flexible Approach

The above is a bit ugly, because it puts part of the page information, namely the header fields, into the makefile. Instead you should use the -a/--assignment option to set these variables within your body file and produce the header afterwards. Instead of having two different suffixes, we can turn the frame into a dot- or hidden file, so that *.html will not match .frame.html:

%.html: %.shtml .frame.shtml
    &preprocess -a $(HTMLFLAGS) $(input) -o $(output)

This explicitly only processes the body. Of course you would do more fancy things, maybe including a menu from yet another file:

# We don't want <title>$(TITLE)</title> turned into rc-style
# <title>My</title> <title>Happy</title> <title>Page</title>
makepp_simple_concatenation = 1
<html> 
  <head>
    <title>$(TITLE)</title>
    <meta name="keywords" content="$(KEYWORDS)" />
    <meta name="description" content="$(DESCRIPTION)" />
    <meta name="generator" content="makepp/&amp;preprocess" />
  </head>
  <body>
    <h1>$(TITLE)</h1>
define FOOTER =     # Store the footer template for later. 
  </body>
</html>
enddef

The body in turn must include the frame, once it has set any parameters. At the end it must expand the FOOTER variable:

TITLE = My Happy Page
KEYWORDS = happy,lucky
DESCRIPTION = Feeling good today
include .frame.shtml 
<p>This is why I'm <b>so</b> happy: ... 
$(FOOTER)
 

Image Handling

You can write an img function which returns an image tag with the size and text extracted from the image. This is based on the rdjpgcom utility, which outputs any number of comment lines, followed by two lines of meta information. We accumulate the former, until we reach the latter, and then output it all at once:

sub imagefilter {
  if( /^JPEG image is (\d+)w \* (\d+)h/ ) {
    chomp $alt;
    print "width='$1' height='$2' alt='$alt'";
  } else {
    $alt .= $_;
  }
}
%.dim: %.jpeg 
    &perl &imagefilter -Ii 'rdjpgcom -verbose $(input)' -o $(output)

Within &preprocess you would then have a function (best defined in a Perl module) like:

sub f_img {
  my( $name, $rest ) = split /, */, $_[0], 2;
  open my $fh, "$name.dim";
  "<img src='$name.jpeg' " . <$fh> . " $rest />";
}

and use it as (note the double parens, in case somebody reformats a line break into it some day):

Here is the image: $((img basename, align="right"))

The same could be done with gifs and pngs, and the img function could even look which of these it finds for a given basename. But you need different utilities. For png, there can be any number of embedded text attributes, all of which pngtopnm can extract to a file, and you take it from there.

Timestamping Your Files

If you version control your files, you can use the timestamp in the footer. Note the trailing empty expansion, which prevents the final dollar from being illegal makepp syntax:

VC = $Id: index.shtml,v 1.2 2006/08/17 07:38:50 pfeiffer Exp pfeiffer $()

The footer can then contain an expression which extracts the date from the VC variable:

<p>Last changed: $((map $(VC), tr!/!-!; m/([-\d]{10})/; $_ = $1))</p>

Taking it Further

If you want more than just a consistent look and feel for your pages, you can define statement (presumably outputting something with print) or functions returning some generated HTML. E.g., you can define a function which gives you an <a> hyperlink tags based on a name you fetch in a hash or a database. This is left as an excercise for you.

Account setup

We have a certain number of similar applications, each running in several instances in an account of their own. The conffiles for some programs must be converted to binary format within the run time environment. This led us to set everything up with makepp.


Daniel Pfeiffer
Last modified: 2006-05-14