The four main top level targets to which you may wish to add additional actions are:
mostlyclean.always ::How these actions are triggered when the `mostlyclean' target is used, can be seen if you look more closely at the structure of the `mostlyclean' target.
$(RM) *% *~
mostlyclean : mostlyclean.setupUsing the `mostlyclean' target results in four sub targets being triggered. The purpose of this structure is to provide control over when your actions will be run. The two primary times at which you would want your actions to be run are: before, or after makeit has visited any subdirectories. If your actions must be run after makeit has visited any subdirectories the `always' sub target for the top level target should be used. If your actions must be run before makeit has visited any subdirectories, the `setup' sub target for the top level target should be used.
mostlyclean : mostlyclean.subdirs
mostlyclean : mostlyclean.target
mostlyclean : mostlyclean.always
mostlyclean.setup ::
mostlyclean.subdirs :: mostlyclean.setup
ifneq "$(SUBDIRS)" ""
ifneq "$(filter navigate_all_variants,$(MAKEIT_OPTIONS))" ""
@$(foreach var,$(VARIANTS), \
$(foreach dir,$(SUBDIRS), \
$(MAKE) -C $(dir) VARIANT=$(var) mostlyclean \
|| $(FAILACTION);))
else
@$(foreach d,$(SUBDIRS), \
$(MAKE) -C $(d) mostlyclean || $(FAILACTION);)
endif
endif
mostlyclean.target :: mostlyclean.setup
mostlyclean.always :: mostlyclean.setup
The two sub targets of `setup' and `always', are the only sub targets you should need to extend. The `subdirs' sub target should never have to be extended. The purpose of the `target' sub target can be seen by looking at the structure of the `clean' target.
clean : clean.setupFrom this it can be seen that when the `clean' target is used, sub targets will be triggered in the following order:
clean : clean.subdirs
clean : clean.target
clean : clean.always
clean.setup :: mostlyclean.setup
clean.subdirs :: clean.setup
ifneq "$(SUBDIRS)" ""
ifneq "$(filter navigate_all_variants,$(MAKEIT_OPTIONS))" ""
@$(foreach var,$(VARIANTS), \
$(foreach dir,$(SUBDIRS), \
$(MAKE) -C $(dir) VARIANT=$(var) clean \
|| $(FAILACTION);))
else
@$(foreach dir,$(SUBDIRS), \
$(MAKE) -C $(dir) clean || $(FAILACTION);)
endif
endif
clean.target :: clean.setup
clean.always :: clean.setup mostlyclean.always
In the case of the `clean' and `mostlyclean' targets, the `mostlyclean.target' target should be extended to add actions which are only to be run when the `mostlyclean' target is used, and not the `clean' target. As the `clean.always' target totally removes the makeit subdirectory you would not want to add to the `mostlyclean.always' target, actions which remove only parts of the makeit subdirectory. Instead, add actions which only remove portions of the makeit subdirectory to the `mostlyclean.target' target.
A further two levels of targets exist above the `clean' target. These targets are `distclean' and `realclean'. Neither of these targets define default actions. The `distclean' target structure can be added to, to define actions which will bring back the directory to a state ready for distribution. The `realclean' target structure can be added to, to define actions which will remove everything which can be regenerated.
In all the above targets, the FAILACTION macro is special and will evaluate to either `true' or `exit'. For a normal build it will take the value `exit'. This ensures that if makeit fails while in one directory, it will not continue to other directories. When the `-k' option is passed to makeit on the command line, FAILACTION takes the value `true', and makeit will attempt to traverse all subdirectories, even if errors occur.
Other top level targets such as `all', `install' and `check' have a similar structure and would be extended in a similar way to the set of `clean' targets described above.
A module to support the use of the InterViews graphics library is included below, as an example of a library module.
ifeq "$(origin INTERVIEWS_HOME)" "undefined"When defining additional options to be passed on to the preprocessor, compiler, or linker, you should always append to the existing value of the variable for those options. If you do not append to the variables, flags could be passed on, in the wrong order. For example, libraries could be linked in the wrong order, resulting in undefined symbols at link time. When you define variables, use the `override' directive. This will ensure that the variables will not be overridden by options passed to makeit on the command line, or because of `override' being used previously with the variable.
INTERVIEWS_HOME := /usr/local/InterViews
endif
ifeq "$(origin X11LIBDIR)" "undefined"
X11LIBDIR := /usr/lib/X11
endif
override CPPFLAGS += \
-I$(INTERVIEWS_HOME)/include -Dcplusplus_2_1
ifneq "$(filter 2.6,$(INTERVIEWS_OPTIONS))" ""
override CPPFLAGS += \
-I$(INTERVIEWS_HOME)/include/InterViews/2.6 \
-I$(INTERVIEWS_HOME)/include/IV-look/2.6 \
-Div2_6_compatible
endif
override LDFLAGS += $(LOPT)$(INTERVIEWS_HOME)/lib/$(CPU)
ifneq "$(X11LIBDIR)" ""
override LDFLAGS += $(LOPT)$(X11LIBDIR)
endif
ifneq "$(filter libUnidraw,$(INTERVIEWS_OPTIONS))" "
override LDLIBS += -lUnidraw
endif
override LDLIBS += -lIV -lXext -lX11 -lm
If you know that the module will need to be portable across multiple platforms, do not use the `-L' option for specifying the location of libraries. Instead of the `-L' option, use `$(LOPT)'. This will be expanded to either `-L' or `-Wl,-L', whichever is appropriate for the platform on which makeit is being run.
If optional libraries need to be linked, include directories searched, or preprocessor symbols defined, set up an options variable for the module in which you can list names, to enable the additional features. For example, in the InterViews module, the INTERVIEWS_OPTIONS variable can be set to enable the linking of the Unidraw library and to enable backwards compatibility support for InterViews version 2.6.
You should also allow for library packages to be installed in different locations, by providing a variable which can be set to specify the location. This will allow you to specify a different location in your personal or project makefile without having to modify the module file. A variable, giving the location of the library package will also make it easier to select different versions of the software.
Each of the primary languages supported by makeit provide variables, which can be set by other modules, to indicate that code files have been generated for that language. For the `c' module, these variables are:
--------------------------------------------------------------------- Variable Purpose --------------------------------------------------------------------- _c_generated_SRC The names of C code files that should be compiled into object files and placed into the library. _c_generated_PROGRAM_SRC The names of C code files that should be compiled into programs. _c_generated_NONLIB_SRC The names of C code files that should be compiled into object files, but which should be placed into the library. ---------------------------------------------------------------------If a module adds files to these variables, the `c' module expects to find those files in the makeit subdirectory. When the files are listed in the variables, do not include the makeit subdirectory in the name of the file. For example, from the Lex input file `lexan.l', the file `lexan.c' will be generated. The name `lexan.c' would be listed in the variable _c_generated_NONLIB_SRC, however the `c' module will actually search for the file `$(MK)/lexan.c'.
The cut down version of the Lex module is given below.
## Search source directory as well as build directoryWhen writing any language module, allow the user to exclude an input file from consideration, by listing the name of the file in the EXCLUDE variable. When you integrate a language module for a code generator into the `modules.mk' file, it must be included, before the module supporting the language that it generates code files for.
## if they are different.
vpath %.l $(SRCDIR)
## Calculate language src.
_lex_real_SRC := \
$(filter-out $(EXCLUDE),$(filter %.l,$(SRCFILES)))
## Generate stems for src.
_lex_real_SRC_STEMS := $(basename $(_lex_real_SRC))
## Let C module know about generated src files.
_lex_OUTPUT_SRC := $(addsuffix .c,$(_lex_real_SRC_STEMS))
_c_generated_NONLIB_SRC += $(_lex_OUTPUT_SRC)
## Rules for generated files.
%.l :
%.c : %.l
ifneq "$(_lex_real_SRC_STEMS)" ""
$(patsubst %,$(MK)/%.c,$(_lex_real_SRC_STEMS)) \
: $(MK)/%.c : %.l
$(LEX) $(LFLAGS) $<
mv lex.yy.c $@
endif
## Add lex library.
ifeq "$(origin LEXLIB)" "undefined"
LEXLIB := -ll
endif
override LDLIBS += $(LEXLIB)
--------------------------------------------------------------- Variable Purpose --------------------------------------------------------------- _makeit_MK_LIB_OBJECTS The names of object files which should be archived into the library. _makeit_MK_BINARIES The names of program binaries genera ted. ---------------------------------------------------------------The names listed in these variables should include the name of the makeit subdirectory.
An example of a cut down module to support C code is given below. The example does not cater to C code file created by code generators. Neither does the example support generation of PIC objects for shared libraries.
## Search source directory as well as build directoryFor compiled languages, you also need to set up rules to generate dependency information. To pass the location of the dependency files to makeit, which your rules generate, you need to set the _depend_SRC variable. Dependency files which your rules generate, should be placed into the makeit subdirectory. The name of the dependency file should be the same as the language file, except that the filename extension for that language would be replaced with `.d'.
## if they are different.
vpath %.h $(SRCDIR)
vpath %.c $(SRCDIR)
## Define compilation commands.
PREPROCESS.c =
COMPILE.c =
LINK.c =
PREPROCESS.c += $(CC) -C -E $(CFLAGS) $(CPPFLAGS)
COMPILE.c += $(CC) $(CFLAGS) $(CPPFLAGS) -c
LINK.c += $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
## Libraries and object files to be linked with programs.
LDLIBS1.c = $(filter-out $(LDLIBS),$(filter %.a %.o,$^))
LDLIBS2.c = $(LDLIBS)
## Wipe out standard target for creation of object file
## from src file and program from src file.
%.o : %.c
% : %.c
## Calculate all language src.
_c_real_SRC := \
$(filter-out $(EXCLUDE),$(filter %.c,$(SRCFILES)))
## Calculate program src.
_c_real_PROGRAM_SRC := \
$(filter-out $(EXCLUDE),$(filter \
$(addsuffix .c,$(PROGRAMS)),$(SRCFILES)))
## Calculate non library src.
_c_real_NONLIB_SRC := \
$(filter-out $(EXCLUDE),$(filter %.c,$(NONLIBSRC)))
## Calculate library src.
_c_real_LIB_SRC := \
$(filter-out \
$(_c_real_NONLIB_SRC) $(_c_real_PROGRAM_SRC), \
$(_c_real_SRC))
## Setup library dependencies for real src.
ifneq "$(_c_real_LIB_SRC)" ""
_c_real_LIB_OBJECTS := \
$(patsubst %.c,%.o,$(_c_real_LIB_SRC))
_c_real_MK_LIB_OBJECTS := \
$(addprefix $(MK)/,$(_c_real_LIB_OBJECTS))
$(_c_real_MK_LIB_OBJECTS) : $(MK)/%.o : %.c
$(COMPILE.c) $<
mv $(<F:.c=.o) $@
$(_c_real_LIB_OBJECTS) : %.o : $(MK)/%.o
_makeit_MK_LIB_OBJECTS += $(_c_real_MK_LIB_OBJECTS)
endif
## Setup dependencies for non library objects coming
## from real src.
ifneq "$(_c_real_NONLIB_SRC)" ""
_c_real_NONLIB_OBJECTS := \
$(patsubst %.c,%.o,$(_c_real_NONLIB_SRC))
_c_real_MK_NONLIB_OBJECTS := \
$(addprefix $(MK)/,$(_c_real_NONLIB_OBJECTS))
$(_c_real_MK_NONLIB_OBJECTS) : $(MK)/%.o : %.c
$(COMPILE.c) $<
mv $(<F:.c=.o) $@
$(_c_real_NONLIB_OBJECTS) : %.o : $(MK)/%.o
endif
## Setup dependencies for programs coming from real src.
ifneq "$(_c_real_PROGRAM_SRC)" ""
_c_real_PROGRAM_OBJECTS := \
$(patsubst %.c,%.o,$(_c_real_PROGRAM_SRC))
_c_real_MK_PROGRAM_OBJECTS := \
$(addprefix $(MK)/,$(_c_real_PROGRAM_OBJECTS))
_c_real_MK_PROGRAMS := \
$(addprefix $(MK)/,$(basename $(_c_real_PROGRAM_SRC)))
$(_c_real_MK_PROGRAMS) : $(MK)/% : $(MK)/%.o
$(LINK.c) $(LDLIBS1.c) $(LDLIBS2.c) -o $@~
mv $@~ $@
$(_c_real_PROGRAM_OBJECTS) : %.o : $(MK)/%.o
$(_c_real_MK_PROGRAM_OBJECTS) : $(MK)/%.o : %.c
$(COMPILE.c) $<
mv $(<F:.c=.o) $@
_makeit_MK_BINARIES += $(_c_real_MK_PROGRAMS)
endif
For an object file, the dependency file should consist of a series of lines of the form:
$(MK)/object.o $(MK)/object.d : file.hOnly one file on which the object file is dependent should be listed on each line. For a program, the dependency file should be of the form:
$(MK)/program $(MK)/program.o $(MK)/object.d : file.hRules to generate dependency files for the cut down version of the C module are given below.
## Dependency files.
DEPFILTER.c = sed -n \
-e `s/\# [1-9][0-9]* "\(.*\)".*$$/TARGET : \1/p' \
-e `s/\#line [1-9][0-9]* "\(.*\)".*$$/TARGET : \1/p' \
| sort -u
ifneq "$(_c_real_LIB_SRC)" ""
_c_real_LIB_D := \
$(patsubst %.c,$(MK)/%.d,$(_c_real_LIB_SRC))
$(_c_real_LIB_D) : $(MK)/%.d : %.c
@echo makeit: generating dependencies for $<
@$(PREPROCESS.c) $< | $(DEPFILTER.c) | \
sed -e "s%^TARGET%TARGET \$$(MK)/$(*F).o%" \
-e "s%^TARGET%\$$(MK)/$(*F).d%" > $@
_depend_SRC += $(_c_real_LIB_D)
endif
ifneq "$(_c_real_NONLIB_SRC)" ""
_c_real_NONLIB_D := \
$(patsubst %.c,$(MK)/%.d,$(_c_real_NONLIB_SRC))
$(_c_real_NONLIB_D) : $(MK)/%.d : %.c
@echo makeit: generating dependencies for $<
@$(PREPROCESS.c) $< | $(DEPFILTER.c) | \
sed -e "s%^TARGET%TARGET \$$(MK)/$(*F).o%" \
-e "s%^TARGET%\$$(MK)/$(*F).d%" > $@
_depend_SRC += $(_c_real_NONLIB_D)
endif
ifneq "$(_c_real_PROGRAM_SRC)" ""
_c_real_PROGRAM_D := \
$(patsubst %.c,$(MK)/%.d,$(_c_real_PROGRAM_SRC))
$(_c_real_PROGRAM_D) : $(MK)/%.d : %.c
@echo makeit: generating dependencies for $<
@$(PREPROCESS.c) $< | $(DEPFILTER.c) | \
sed -e "s%^TARGET%TARGET \$$(MK)/$(*F)%" \
-e "s%^TARGET%TARGET \$$(MK)/$(*F).o%" \
-e "s%^TARGET%\$$(MK)/$(*F).d%" > $@
_depend_SRC += $(_c_real_PROGRAM_D)
endif
The module provided with makeit to handle shell scripts, excluding support for generated shell scripts, is given below.
## Search source directory as well as build directoryModules for script languages should provide a means to process the script, as it is copied to the makeit subdirectory. For example, the `sh' module allows an arbitrary command to be supplied by defining the SHFILTER variable. If defined, the program is run with the script being passed to the standard input of the program. The output from the program is saved as the resultant program in the makeit subdirectory.
## if they are different.
vpath %.sh $(SRCDIR)
## Wipe out standard target for creation of object file
## from src file and program from src file.
% : %.sh
## Calculate language src.
_sh_real_SRC := \
$(filter-out $(EXCLUDE),$(filter %.sh),$(SRCFILES))
## Setup dependencies.
ifneq "$(_sh_real_SRC)" ""
_sh_real_SCRIPTS := $(basename $(_sh_real_SRC))
_sh_real_MK_SCRIPTS := \
$(addprefix $(MK)/,$(_sh_real_SCRIPTS))
$(_sh_real_MK_SCRIPTS) : $(MK)/% : %.sh
ifneq "$(SHFILTER)" ""
cat $< | $(SHFILTER) > $@
else
cp $< $@
endif
chmod 0775 $@
$(_sh_real_SCRIPTS) : % : $(MK)/%
_makeit_MK_SCRIPTS += $(_sh_real_MK_SCRIPTS)
endif