Chapter 9. Stirmake for entire project structures

Table of Contents

Including sub-projects
Invoking stirmake: smka, smkp, smkt
Controlling what to export with holey scopes

Including sub-projects

Previously, @dirinclude to include subdirectories was demonstrated. This is intended for cases where the included subdirectory belongs to the same project, i.e. same git repository. The included sub-Stirfile must have @subfile in the first line.

However, git submodules are projects that can be built separately or as part of the parent module. Because they can be built separately, they cannot have @subfile in the first line; rather, they must have @toplevel. Including a @toplevel Stirfile with @dirinclude does not work. In this case, the project would be included with @projdirinclude:

@toplevel
@strict

@phonyrule: 'all': 'subproj/all'

@projdirinclude 'subproj'

The subproj Stirfile would then start with @toplevel too.

Invoking stirmake: smka, smkp, smkt

Stirmake can be invoked using three commands: smka (equal to stirmake -a), smkp (equal to stirmake -p), and smkt (equal to stirmake -t). The last characters mean "all", "(this) project", "this directory".

Let us suppose that you have a parent project named "parent", with sub-directory "parent/subdir", and a sub-project "parent/subdir/subproj", and a sub-directory "parent/subdir/subproj/subdir2". If you are currently in the directory "parent/subdir/subproj/subdir2", then you may invoke stirmake in the following ways:

  • smkt ../all

  • smkp all

  • smka subdir/subproj/all

All of them refer to the target all in the Stirfile "subdir/subproj/Stirfile". If smkt, smkp or smka are executed without arguments in the same directory "parent/subdir/subproj/subdir2", "smkt" would execute the first target of parent/subdir/subproj/subdir2/Stirfile", "smkp" would execute the first target of parent/subdir/subproj/Stirfile", and "smka" would execute the first target of the top-level parent/Stirfile. Usually the first target is named "all" by convention, and the rule is a phony rule, but this is not certain in all cases.

Note how Stirmake is superior to make in this aspect. You may execute "smka" in any subdirectory and it will build everything in the whole project structure. With inclusive make, this is not possible, and "make" must be executed in the top-level directory that contains a Makefile and not in a subdirectory that contains module.mk. Note also that with recursive "make", if you execute "make" in a subdirectory, it does not build its dependencies, and if the dependencies are alreayd built and the build of the subdirectory succeeds, you still can't be certain that the interface wasn't changed in a manner that would cause build of some other subdirectory (and thus a top-level build of everything) to fail. Stirmake is similar to git: you can execute "git status" or any other git command in any subdirectory, and it will work.

Controlling what to export with holey scopes

Stirmake uses recursive scoping, where if the variable $(CC) is accessed, it accesses first $(CC) in the current scope (lexical or dynamic specified by @L or @D before the variable name), then its parent scope, then its grandparent scope, etc. until there are no longer any parent scopes. This means that if you have a complex Stirfile and include a subproject, everything in the parent scope is visible to the subproject. This may not be optimal in all cases. It may be useful to be able to specify what variables are visible to the subproject.

This is possible with @beginholeyscope and @endscope. A holey scope is a scope that terminates the recursive scoping so that the parent scope is not accessed by default, but the lexical or dynamic parent scope can still be explicitly accessed with @LP or @DP.

Example from Stirfile of stirmake:

@beginholeyscope
  $(CC) = @LP$(CC)
  $(CFLAGS) = @LP$(CFLAGS)
  $(WITH_LUA) = @LP$(WITH_LUA)
  $(LUAINCS) = @LP$(LUAINCS)
  $(LUALIBS) = @LP$(LUALIBS)
  $(FLEX) = @LP$(FLEX)
  $(BYACC) = @LP$(BYACC)
  @projdirinclude "abce"
@endscope

In this case, the subproject abce sees only $CC, $CFLAGS, $WITH_LUA, $LUAINCS, $LUALIBS, $FLEX and $BYACC and all other variables are left undefined. The variables are taken from the scope of the Stirfile in which @beginholeyscope is defined. Note how @LP avoids the recursion break of @beginholeyscope, by accessing the parent scope (or the grandparent scope or the parent of grandparent, etc.).

If you want to access the lexical parent scope without recursion to grandparent, or the dynamic parent scope without recursion to grandparent, you can do so with @LPO or @DPO. Similarly, you can access the lexical or dynamic scope without recursion to parent scope by @LO and @DO. All scope type specifiers with character O terminate recursion, and character P mean "access parent explicitly".