diff options
Diffstat (limited to 'mk')
-rw-r--r-- | mk/Makefile | 52 | ||||
-rw-r--r-- | mk/Readme.txt | 469 | ||||
-rw-r--r-- | mk/build-debug.mk | 4 | ||||
-rw-r--r-- | mk/build-profile.mk | 4 | ||||
-rw-r--r-- | mk/build-release.mk | 4 | ||||
-rw-r--r-- | mk/config-Cygwin-i686_Cygwin-i686.mk | 10 | ||||
-rw-r--r-- | mk/config-Cygwin-i686_Linux-ppc.mk | 11 | ||||
-rw-r--r-- | mk/config-MinGW-i686_MinGW-i686.mk | 8 | ||||
-rw-r--r-- | mk/config-SunOS-sun4u_SunOS-sun4u.mk | 6 | ||||
-rw-r--r-- | mk/config-default.mk | 8 | ||||
-rw-r--r-- | mk/config.mk | 44 | ||||
-rw-r--r-- | mk/def_rules.mk | 123 | ||||
-rw-r--r-- | mk/footer.mk | 119 | ||||
-rw-r--r-- | mk/header.mk | 12 | ||||
-rw-r--r-- | mk/skel.mk | 254 |
15 files changed, 1128 insertions, 0 deletions
diff --git a/mk/Makefile b/mk/Makefile new file mode 100644 index 0000000..7658b42 --- /dev/null +++ b/mk/Makefile @@ -0,0 +1,52 @@ +SHELL := /bin/bash +RUNDIR := $(CURDIR) +ifndef TOP +TOP := $(shell \ + top=$(RUNDIR); \ + while [ ! -r "$$top/Rules.top" ] && [ "$$top" != "" ]; do \ + top=$${top%/*}; \ + done; \ + echo $$top) +endif + +MK := $(TOP)/mk + +.PHONY: dir tree all clean clean_all clean_tree dist_clean + +# Default target when nothing is given on the command line. Reasonable +# options are: +# "dir" - updates only targets from current directory and its dependencies +# "tree" - updates targets (and their dependencies) in whole subtree +# starting at current directory +# "all" - updates all targets in the project +.DEFAULT_GOAL := dir + +dir : dir_$(RUNDIR) +tree : tree_$(RUNDIR) + +clean : clean_$(RUNDIR) +clean_tree : clean_tree_$(RUNDIR) + +# $(d) keeps the path of "current" directory during tree traversal and +# $(dir_stack) is used for backtracking during traversal +d := $(TOP) +dir_stack := + +include $(MK)/header.mk +include $(MK)/footer.mk + +# Automatic inclusion of the skel.mk at the top level - that way +# Rules.top has exactly the same structure as other Rules.mk +include $(MK)/skel.mk + +.SECONDEXPANSION: +$(eval $(value HEADER)) +include $(TOP)/Rules.top +$(eval $(value FOOTER)) + +# Optional final makefile where you can specify additional targets +-include $(TOP)/final.mk + +# This is just a convenience - to let you know when make has stopped +# interpreting make files and started their execution. +$(info Rules generated $(if $(BUILD_MODE),for "$(BUILD_MODE)" mode,)...) diff --git a/mk/Readme.txt b/mk/Readme.txt new file mode 100644 index 0000000..c341b48 --- /dev/null +++ b/mk/Readme.txt @@ -0,0 +1,469 @@ +################################################################################ +# Non-recursive make build system # +# ------------------------------- # +# Copyright (C) 2012 Andrzej Ostruszka <andrzej.ostruszka@gmail.com> # +# # +# URL: http://github.com/aostruszka/nonrec-make # +# (or older: http://nonrec-make.googlecode.com/) # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy # +# of this software and associated documentation files (the "Software"), to # +# deal in the Software without restriction, including without limitation the # +# rights to use, copy, modify, merge, publish, distribute, sublicense, # +# and/or sell copies of the Software, and to permit persons to whom the # +# Software is furnished to do so, subject to the following conditions: # +# # +# The above copyright notice and this permission notice shall be included in # +# all copies or substantial portions of the Software. # +# # +# Except as contained in this notice, the name(s) of the above copyright # +# holders shall not be used in advertising or otherwise to promote the sale, # +# use or other dealings in this Software without prior written authorization. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # +# IN THE SOFTWARE. # +################################################################################ + +NOTE: This readme _might_ not be up to date. For up to date information +see the above URL (and accompanying wiki pages). + +This is my attempt to implement a non-recursive make build system. For +the motivation Google for the paper "Recursive make consider harmful" by +Peter Miller. + +I've seen couple of other proposals and decided to have something that +will be a blend of nice ideas I have seen plus some improvements. If +you actually use this I'd like to hear from you :) - is it useful, does +it perform well, do you have any suggestions for the improvements ... +and so on. This implementation is based on GNU make and its new +features introduced in 3.80. But don't use that version - these +features had bugs in that version. Use version 3.81 where everything +works OK. + +Before you keep on reading though, just take a look at the structure of +the Rules.mk files (Rules.top has exactly the same structure as Rules.mk +- it just has another name to ease location of the top level project +directory from its subfolders). +I've got a feeling that it is much easier to understand how the system +looks from the user perspective just by looking at the example than +reading its explanation :D. + +OK, now that you have a feeling how the Rules.mk look like let me walk +you through an example (ex1 in the repository). Consider the project +that has some source files at the top directory and is depending on two +libraries in Dir_1 and Dir_2 and another one in Dir_3. The libraries +themselves are partitioned between several subdirectories and Dir_2 has +some examples in a separate subfolder (do not pay attention to all *.c +files). + +ex1/ + Makefile + Rules.top <- Just a symlink to Rules.mk to mark where the top level is + Rules.mk + main.c + top_a.c + top_b.c + cli.c + cli_dep.c + mk/* <- This is where the mk files from this build system are + Dir_1/ + Makefile + Rules.mk + dir_1_file1.c + dir_1_file2.c + dir_1_file3.c + Dir_1a/ + Makefile + Rules.mk + dir_1a_file1.c + dir_1a_file2.c + dir_1a_file3.c + Dir_1b/ + Makefile + Rules.mk + src/ + dir_1b_file1.c + dir_1b_file2.c + Dir_2/ + Makefile + Rules.mk + dir_2_file1.c + dir_2_file2.c + Dir_2a/ + Makefile + Rules.mk + dir_2a_file1.c + dir_2a_file2.c + dir_2a_file3.c + Dir_2b/ + Makefile + Rules.mk + dir_2b_file1.c + dir_2b_file2.c + dir_2b_file3.c + Dir_ex/ + Makefile + Rules.mk + ex.c + Dir_3/ + Makefile + Rules.mk + dir_3_file1.c + dir_3_file2.c + +There's one top level make file (Rules.top) which eventually includes +all the makefiles. In addition in each directory there is Makefile +(which can be a link to the one in the top level directory) which +searches for the Rules.top includes it with the default goal +changed to rebuild only targets for the current directory. This allows +you to run make from each subdirectory and update only part of the +targets (in contrary to other implementation which usually require +you to run it at the top level and make full build each time). + +This build system was designed to have very simple structure of the +"user makefiles". The user just has to set the Rules.mk files in each +directory and some general configuration options. All the "magic" is +hidden in header.mk, footer.mk and skel.mk which don't have to be +modified [1]. + +The structure of the Rules.mk is following (this is from top level +Rules.top which has the same format as Rules.mk - and in fact it is +suggested that it should be a symlink to normal Rules.mk file since it +will allow for this project to act as a subproject of some super project +treating your whole project tree as a subdirectory[2]): + +-8<---Rules.top--------------- +1: TARGETS = app.exe cli.exe +2: SUBDIRS = Dir_1 Dir_2 +3: +4: app.exe_DEPS = top_a.o top_b.o main.o $(SUBDIRS_TGTS) +5: app.exe_LIBS = -lm +6: # Let's use DEFAULT_MAKECMD for app.exe +7: +8: cli.exe_DEPS = cli.o cli_dep.o +9: cli.exe_CMD = $(LINK.c) $^ $(LDLIBS) -o $@ +-8<--------------------------- + +Line 1 - this directory has two targets that should be built. +Line 2 - this directory has two subdirectories that should be scanned +Line 4 - app.exe depends on ... (SUBDIRS_TGTS is a variable that + contains all the targets from the subdirectories mentioned at + line 4) +Line 5 - app.exe should be linked with math library +Line 6 - app.exe will be built with default "rule" +Line 8 - cli.exe depends on ... and +Line 9 - use the following command to build it + +You can specify the targets for current directory in two ways: +1. Give them in TARGETS. Each target can have it's own *_DEPS, *_LIBS + and *_CMD which give the dependencies, additional libs needed and + a command to run which will update the target. They are explained + a bit below. +2. The targets are simply objects - or in more general files that + match patterns in AUTO_TGTS, and have appropriate rules in 'skeleton'. + In that case you can list them in OBJS or SRCS like e.g. in Rules.mk + from Dir_1a + +-8<---Dir_2/Dir_2a/Rules.mk--- +1: SRCS := dir_2a_file1.c dir_2a_file2.c dir_2a_file3.c +-8<--------------------------- + +There are "reserved" variables that you should not modify. Most notably: +- $(d) is the directory of the current Rules.mk [see note 2] +- $(TOP) is the top level directory of the project tree +- $(MK) is the directory where the included *.mk makefiles are +For the full list you have to take a look at the makefiles in mk +directory (e.g. in the skel.mk there are macros 'include_subdir_rules', +'save_vars', 'tgt_rule' and 'skeleton' which you should not change [1]). + +Going back to the Rules.mk. Normally wildcards in variable assignments +are not expanded in make but this make system detects wildcards in SRCS +and expands them (both in directory of the Rules.mk and its SRCS_VPATH +subdirectories - see below what SRCS_VPATH is used for). Thus you can +simply say in Rules.mk: + +SRCS := *.c + +If you have directory with large number of files where simple glob is +what you want to use in SRCS but there are some files that you'd like to +exclude just list them in SRCS_EXCLUDES :) - this is a list of makefile +patterns e.g. + +SRCS_EXCLUDES := extra% test% + +Of course you can use the built in make wildcards but you should do that +as follows: + +SRCS := $(notdir $(wildcard $(d)/*.c)) + +Keep in mind that the directory where make is invoked is usually different +from where given Rules.mk is located. + +When supplying the value for *_DEPS you can refer to the object from the +same directory with no directory prefix. To be specific all +dependencies that are not absolute paths will be treated as ones from +the $(OBJDIR) subdirectory of current directory (OBJDIR and OBJPATH are +"discussed" below). You can use SUBDIRS_TGTS variable which will list +all targets in subdirectories. You can also name them explicitly like +$(TARGETS_$(d)/subdir) and so on - see e.g. the Rules.mk in Dir_2 +directory where Dir_ex is mentioned as a subdirectory but is excluded +from the *_DEPS (this allows you to create folders that "inherit" all +the setting from the project build system but are not meant to be a part +of the project itself - like examples). For instance: + +dir1_lib.a_DEPS = dir_1_file1.o dir_1_file2.o dir_1_file3.o $(SUBDIRS_TGTS) + +tells that dir1_lib.a (which will be created in Dir_1/$(OBJDIR)) depends +on several object files from the same directory and the targets from all +subdirectories. + +One last thing about the TARGETS/OBJS. By default source files for the +objects are searched in the directory where Rules.mk is, but if you want +to have source files in a subdirectory (say 'src') you can do that via +SRCS_VPATH variable (see skel.mk). E.g.: + +SRCS_VPATH := src1 src2 + +will cause make to first look at the directory where Rules.mk is present +and then in its src1 and src2 subdirectories. + +*_LIBS are appended to the LDLIBS variable when updating the target. +This variable is used by several make built in rules but if you create +your own rule or MAKECMD.* (see next paragraph) you can refer to it (see +the function 'save_vars'). + +When *_CMD is not present and the target does not match any pattern in +AUTO_TGTS then either MAKECMD.suff (where .suff is the suffix of the +target) or DEFAULT_MAKECMD is used - take a look into skel.mk. + +If you want to setup special flags for compilation you can do that via +"directory specific variables". As an example here's what I did for +compilation of C files. There's a built in rule in make which uses +COMPILE.c variable for making %.o out of %.c so I added $(DIR_CFLAGS) to +its default value and DIR_CFLAGS is defined in skel.mk as: + +DIR_INCLUDES = $(addprefix -I,$(INCLUDES_$(<D))) +DIR_CFLAGS = $(CFLAGS_$(<D)) $(DIR_INCLUDES) + +So it extracts the directory part of the first prerequisite in the rule +(that is %.c file - check the section 'automatic variables' in make +manual for the meaning of $(<) and $(<D)) and refer to variables named +CFLAGS_the_directory_part and INCLUDES_the_directory_part. +Thus if you wanted to add special includes for files in Dir_1/Dir_1b you +could add: + +INCLUDES_$(d) := $(TOP)/some/special/include_dir + +into its Rules.mk and all files in this directory will be compiled with +-I$(TOP)/some... switch. The same goes for CFLAGS and CXXFLAGS. + +The same goes for the linker flags - quoting from skel.mk: + +LDFLAGS = $(addprefix -L,$(LIBDIRS_$(subst /$(OBJDIR),,$(@D)))) +LDLIBS = $(LIBS_$(@)) + +The above means that if targets in given directory need to be linked +with special -L switches you can provide them via LIBDIRS_$(d) +variables. If there are some global -L switches just append them in +skel.mk. The second line above shows how *_LIBS variable that you can +give for specific target gets added to the LDLIBS (there's 'save_vars' +in between if you're curious :)). + +You can of course use target specific variables that GNU make supports +so you have more control (if you don't know what target specific +variables are take a look into manual). Say you want to compile +dir_1b_file2.c with an additional flag but all other files in +Dir_1/Dir_1b directory should not have this flag turned on. All you +need to do is to add this line into Rules.mk in Dir_1b directory. + +$(OBJPATH)/dir_1b_file2.o : CFLAGS += -ansi + +OBJPATH is a variable that contains the full directory where the +resulting object file will be placed. While we are at this, by default +all targets are compiled into OBJDIR (defined in skel.mk as 'obj') +subdirectory of the directory where Rules.mk is present. You can use +this OBJDIR variable (and perhaps some conditional statements) to setup +the output path according to your current compilation mode. E.g. +obj/debug for objects with debugging information or obj/ppc_7xx for +cross compilation to the given Power PC family and so on. There's +predefined (in config* files) HOST_ARCH variable that you can use for +this (e.g. set OBJDIR := obj/$(HOST_ARCH) in skel.mk). + +Finally let me explain what targets are defined and the way you can run +them from command line. By default (that is if you have not modified +anything :)) there are several targets that are "global". It is 'all', +'clean_all' and 'dist_clean'. If you specify them in the command line +they will respectively rebuild whole tree, clean everything and clean +everything together with the removal of OBJDIRs - no matter from which +directory you started make. BTW if there's something that you want to +clean up and it's not in the OBJDIR - e.g. you've got file lexer.l out +of which lexer.c and lexer.h is generated and you want them to be +removed - you can specify this in the variable CLEAN (this is relative +to the directory where Rules.mk is). +In addition to those each dir has "it's own" targets. These are: + +1) dir_<directory_path> + which builds all targets in given directory plus its dependencies +2) tree_<directory_path> + which builds all targets in subtree starting at directory given +3) clean_<directory_path> + which removes all "products" from the $(OBJDIR) subdirectory of + current directory +4) clean_tree_<directory_path> + which does clean_<directory_path> and the same for each its + subdirectory + +For your convenience there are couple "aliases" defined (see Makefile). +When no target is given on command line it defaults to dir_$(pwd). +If you give 'clean' as a target that will result in execution of target +clean_$(pwd) and the same for 'clean_tree'. E.g. say you're in Dir_1. +Then: + +* 'make' (same as 'make dir_$(pwd)') + builds all targets in the Dir_1 which in our example is + Dir_1/obj/dir1_lib.a - of course any of its dependencies that are not + up to date are updated also. This rule has one exception - if your + Rules.mk has no targets and only SUBDIRS (e.g. you have grouped + several subdirectories in one directory) then simple 'make' in this + directory - instead of doing nothing - will build targets of all its + subdirectories. +* 'make tree' (same as 'make tree_$(pwd)') + rebuilds everything in given subtree +* 'make clean' (same as 'make clean_$(pwd)') + removes everything from Dir_1/obj/ +* 'make clean_tree (same as 'make clean_tree_$(pwd)') + cleans Dir_1/obj and Dir_1/Dir_1[abc]/obj + +You can obviously provide the path by yourself - it does not have to +be $(pwd) - and as usual you can build particular object files too e.g. +'make $(pwd)/obj/dir_1_file1.o' + +And that would be it. Gee, so much writing for something that is rather +simple to use - go ahead and take a look again at these Rules.mk in +various directories. Setting up you project should be simple by now :). + +Have fun! + + Andrzej Ostruszka + +[1] Unless this build system does not do what you wanted :-P. In that +case you probably need to spiff it up. So you'll need to +digest it first and note [3] is my hand at it :). + +[2] There is one limitation that you should be aware. +Prior to commit 070f681 you should not have in your project two "target +specific" LIBS, LDFLAGS or CMD variables (that is those that are used +during second phase of make execution) that have the same names! For +example in one part of your tree you're generating target abc which has +it's abc_CMD and in the other part another target that has the same name +and also it's own command. In such case the last assignment to abc_CMD +will hold and it will be used for both targets. The same goes for LIBS +and LDFLAGS. + +And this also applied to situation when you would like to use two +subprojects in one larger project. There should be no clash between +variables from these subprojects. + +Starting with commit 070f681 you can have in your (sub)projects two +LIBS, LDFLAGS or CMD variables. However there is a catch here! Since +these variables are not mandatory (you don't have to provide them for +each target) in order to differentiate between case where abc_CMD was +actually given for this instance of abc target from the situation where +abc_CMD is still visible from previous instance of abc target those +abc_(LIBS|LDFLAGS|CMD) variables are cleared once their value is +used/remembered (see save_vars macro in skel.mk). That means referring +to these variables outside Rules.mk where they were assigned will not +work (and even in the same Rules.mk they will work only in case of +simply expanded variables - not recursive). If you have such need I'd +advice to introduce your own variable and use this variable in all +places, e.g.: + +MATH_LIBS := -lgsl -lgslcblas -lm +... +TARGETS := abc + +abc_DEPS = ... +abc_LIBS = $(MATH_LIBS) +... + +[3] You should know that make works in two phases - first it scans the +makefiles and then it begins their execution (see discussion of +'immediate' and 'deferred' in section 'Reading Makefiles' of make +manual). This implies that the $(d) variable is not valid during +execution of the commands used for target updates. If you need to refer +to the directory of the target or prerequisite you should rely on +automatic variables (@, <, ...) and built in functions (dir, notdir, +...). + +Every Rules.mk (or Rules.top) need to be included in cooperation with +header.mk and footer.mk. This is now done automatically but in older +versions this was not so and user had to include them manually. +The main purpose of header is to clear all variables that you can use +inside Rules.mk so that values set in one rules file does not propagate +to other. In addition at the top level it sets the $(d) variable (which +stands for the directory where the currently included Rules.mk is) and +includes the skel.mk so the top level Rules.top can have exactly the +same structure as other Rules.mk. + +The skel.mk is a skeleton which defines variables used by make. In +addition it includes: +- config.mk - this is a file with the "configuration" for your project +- def_rules.mk - where to put general rules (e.g. pattern rules). E.g. + if you want to add a rule that builds %.o out of %.m4 (by running m4 + preprocessor before passing the contents of file to CC) just put it in + here. + +skel.mk also defines some functions like save_vars and tgt_rule +which are called in the footer.mk. Take a look into make manual for the +way the functions are defined and called if you're not familiar with it. + +include_subdir_rules: This is where I keep track of directory of + currently included makefile and include the Rules.mk from the + subdirectories. This function is called in footer.mk in foreach + loop with a subdirectory name as an argument. + +save_vars: This one is very simple it just saves the target specific + variables under their "full path" variables. E.g. + dir1_lib.a_DEPS will get saved as DEPS_$(TOP)/Dir_1/obj/dir1_lib.a + This has two purposes. First it allows you to have targets with + the same names in different directories (not that I recommend + this :)) and allows for easier definition of tgt_rules :-P + +tgt_rule: This is where the rule for given target is created. First + I convert all relative dependencies to the absolute ones then + I include all dependency files (by default they are created as + side effects during compilation - if your compiler does not + allow you to do that just make simple shell script that will do + this). I also append appropriate libs and then issue the rule + for this target. By using the short circuiting 'or' command + I give priority to the CMD over MAKECMD.suffix which itself has + priority over DEFAULT_MAKECMD. + +skeleton: This is just a skeleton for compilation of files in given + directory. If you want to add some rule here then also add + appropriate pattern to the AUTO_TGTS that will filter out these + targets and prevent generation of the specific rules via + tgt_rule function. + +The footer.mk is where Rules.mk gets translated into the proper +makefile. There's not much to explain, just take a look in there. +First I memorize the targets for given directory (either from OBJS/SRCS +or from TARGETS) with appropriate directory prefix. If there's need to +save the target specific *_(CMD|DEP|LIB) I do it. Then I include all +the Rules.mk from the subdirectories. Then I define the targets for +given directory either explicitly (like clean_all or clean_$(d)) or by +evaluation of the 'skeleton' mentioned above or by iterating through all +targets which do not match AUTO_TGTS and evaluating what tgt_rule +function for this target has returned. + +In case you want to play with these settings make sure you understand +how make works, what are it's phases, when and how the variables are +expanded and so on. It will save you a lot of time :). + +Best regards +Andrzej diff --git a/mk/build-debug.mk b/mk/build-debug.mk new file mode 100644 index 0000000..adcc04f --- /dev/null +++ b/mk/build-debug.mk @@ -0,0 +1,4 @@ +CFLAGS += -ggdb +CXXFLAGS += -ggdb +CPPFLAGS += -DDEBUG +LDFLAGS += -ggdb diff --git a/mk/build-profile.mk b/mk/build-profile.mk new file mode 100644 index 0000000..e7b14ac --- /dev/null +++ b/mk/build-profile.mk @@ -0,0 +1,4 @@ +CFLAGS += -ggdb -pg $(OPT_FLAGS) +CXXFLAGS += -ggdb -pg $(OPT_FLAGS) +CPPFLAGS += -DPROFILE +LDFLAGS += -ggdb -pg diff --git a/mk/build-release.mk b/mk/build-release.mk new file mode 100644 index 0000000..7869bbb --- /dev/null +++ b/mk/build-release.mk @@ -0,0 +1,4 @@ +CFLAGS += $(OPT_FLAGS) +CXXFLAGS += $(OPT_FLAGS) +CPPFLAGS += -DRELEASE +#LDFLAGS += diff --git a/mk/config-Cygwin-i686_Cygwin-i686.mk b/mk/config-Cygwin-i686_Cygwin-i686.mk new file mode 100644 index 0000000..ee7880f --- /dev/null +++ b/mk/config-Cygwin-i686_Cygwin-i686.mk @@ -0,0 +1,10 @@ +include $(MK)/config-default.mk + +CPPFLAGS += -DCYGWIN +# There's no rt lib on Cygwin +LDLIBS := $(subst -lrt,,$(LDLIBS)) + +# On cygwin shared libraries have dll extension +SOEXT := dll +# and by default executables have .exe appended +EXE := .exe diff --git a/mk/config-Cygwin-i686_Linux-ppc.mk b/mk/config-Cygwin-i686_Linux-ppc.mk new file mode 100644 index 0000000..6a7c865 --- /dev/null +++ b/mk/config-Cygwin-i686_Linux-ppc.mk @@ -0,0 +1,11 @@ +# How the "cross tools" should be invoked +CC := powerpc-750-linux-gnu-gcc +CXX := powerpc-750-linux-gnu-g++ +AR := powerpc-750-linux-gnu-ar +RANLIB := powerpc-750-linux-gnu-ranlib + +# Since we are compiling for a "remote target" we have to set this manually +ENDIAN := big + +# Any other target specific settings +CPPFLAGS += -DLINUX_PPC diff --git a/mk/config-MinGW-i686_MinGW-i686.mk b/mk/config-MinGW-i686_MinGW-i686.mk new file mode 100644 index 0000000..fc097de --- /dev/null +++ b/mk/config-MinGW-i686_MinGW-i686.mk @@ -0,0 +1,8 @@ +include $(MK)/config-default.mk + +CPPFLAGS += -DMINGW + +# On mingw shared libraries have dll extension +SOEXT := dll + +OPEN_GL_LIBS := -lopengl32 -lglu32 diff --git a/mk/config-SunOS-sun4u_SunOS-sun4u.mk b/mk/config-SunOS-sun4u_SunOS-sun4u.mk new file mode 100644 index 0000000..57db3dc --- /dev/null +++ b/mk/config-SunOS-sun4u_SunOS-sun4u.mk @@ -0,0 +1,6 @@ +include $(MK)/config-default.mk + +# These two settings are the reason for a separate config +CPPFLAGS += -DSPARC +# On Sun the sockets are in a separate library +#LDLIBS += -lsocket diff --git a/mk/config-default.mk b/mk/config-default.mk new file mode 100644 index 0000000..d8db456 --- /dev/null +++ b/mk/config-default.mk @@ -0,0 +1,8 @@ +CC := gcc +CXX := g++ + +# AR is a make default but won't hurt spelling it out :) +AR := ar +RANLIB := ranlib + +OPEN_GL_LIBS := -lGL -lGLU diff --git a/mk/config.mk b/mk/config.mk new file mode 100644 index 0000000..baaf1f8 --- /dev/null +++ b/mk/config.mk @@ -0,0 +1,44 @@ +# Fill BUILD_ARCH with appropriate value automatically (with some +# cosmetics in case of Cygwin/MinGW :)). +BUILD_ARCH := $(patsubst MINGW32_%,MinGW,$(patsubst CYGWIN_%,Cygwin,$(shell uname -s)))-$(shell uname -m) + +# Target platform (where the code will be executed). I'm not using +# TARGET_ARCH for this since this variable is already used in builtin +# make rules and I want to be able to use those built in rules. By +# default we are running on the same machine we are building. +HOST_ARCH := $(BUILD_ARCH) + +# Build mode e.g. debug, profile, release. Build specific mode flags +# can be entered in $(MK)/build-$(BUILD_MODE).mk file e.g. for debug +# following seems to be a reasonable contents +#CFLAGS += -ggdb +#CXXFLAGS += -ggdb +#CPPFLAGS += -DDEBUG +#LDFLAGS += -ggdb +# If you don't plan on having different build modes then just comment +# below or set it to empty. +#BUILD_MODE := $(or $(BUILD_MODE),debug) + +# To have some per directory setting automatically propagated to all +# subdirs then uncomment below. That way you can have all project +# compiled with "global" settings and easily switch flags for some +# subtree just by setting per directory settings at the top dir of the +# subtree. You may of course overwrite inherited values and you can +# turn inheritance in some part by just clearing INHERIT_DIR_VARS_$(d) +# This is a global inheritance flag - you might want to turn it on only +# in some directory (just set INHERIT_DIR_VARS_$(d) there). +#INHERIT_DIR_VARS := CPPFLAGS INCLUDES CFLAGS CXXFLAGS + +# Again, by default we are running on the same architecture we are +# building - if you're cross compiling then you should set this manually +ENDIAN := $(shell perl -le 'print unpack(N,pack(L,0x01020304)) == 0x01020304 ? big : little') + +# Make the compiler invocation lines verbose - if it is not defined or +# set to value other then "true" you'll see just indication of what is +# being compiled (without details about options) +#VERBOSE := true + +# Uncomment if you don't like coloring of the output +#COLOR_TTY := false + +# Any additional settings should go here diff --git a/mk/def_rules.mk b/mk/def_rules.mk new file mode 100644 index 0000000..9197b03 --- /dev/null +++ b/mk/def_rules.mk @@ -0,0 +1,123 @@ +# For now I depend on flex and bison - I want to generate source files +# in the same directory as their lex/yacc inputs. +%.c %.h : %.y + bison -d -o $*.c $< + +%.c : %.l + flex -o$@ $< + +# "Pretty printing" stuff +# +# The value of the variable VERBOSE decides whether to output only +# a short note what is being done (e.g. "CC foobar.c") or a full +# command line. +# +# Sometimes you have a code that you're not in charge of and which gives +# a lot of warnings. In that case you can use colors so that you find +# easily what is being compiled. By default I check terminal +# capabilities and use colors only when the terminal support them but you +# can suppress coloring by setting COLOR_TTY to something else than +# 'true' (see config.mk). +# Please don't argue about this choice of colors - I'm always using black +# background so yellow on black it is :-D - background is specified +# below just for those using bright background :-P +COLOR := \033[33;40m +NOCOLOR := \033[0m + +ifndef COLOR_TTY +ifdef TERM +COLOR_TTY := $(shell [ `tput colors` -gt 2 ] && echo true) +endif +endif + +ifneq ($(VERBOSE),true) +ifneq ($(strip $(TOP_BUILD_DIR)),) + strip_top = $(subst $(TOP)/,,$(subst $(TOP_BUILD_DIR)/,,$(1))) +else + strip_top = $(subst $(TOP)/,,$(1)) +endif +ifeq ($(COLOR_TTY),true) +echo_prog := $(shell if echo -e | grep -q -- -e; then echo echo; else echo echo -e; fi) +echo_cmd = @$(echo_prog) "$(COLOR)$(call strip_top,$(1))$(NOCOLOR)"; +else +echo_cmd = @echo "$(call strip_top,$(1))"; +endif +else # Verbose output +echo_cmd = +endif + +COMPILE.c = $(call echo_cmd,CC $<) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c +COMPILE.cc = $(call echo_cmd,CXX $<) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c +LINK.c = $(call echo_cmd,LINK $@) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) +LINK.cc = $(call echo_cmd,LINK $@) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) + +# This rule is just for running C/C++ preprocessor and saving the output +# into the file with .E appended - sometimes this can be handy. +# Suffix E comes from -E option to gcc. Make sure you invoke this rule +# via full path (e.g.: make $(pwd)/foobar.c.E) if you want to have per +# directory preprocessor flags included. +%.E : % + $(call echo_cmd,CPP $<) $(CPP) $(CPPFLAGS) -o $@ $< + +# Special rule to get easily CPP options for given file. This can be +# handy for your code "assistant" (e.g. clang) that needs to know +# preprocessor options in order to parse file properly. In that case +# you can run: make /path/to/foobar.c.CPPFLAGS | tail -1 +# to get effective flags for foobar.c +%.CPPFLAGS : % + @echo $(CPPFLAGS) + +# Create the output directory for build targets. +%/$(OBJDIR): + @mkdir -p $@ + +# Automatic rules. Again, since the output is in different directory +# than source files I cannot count on the built in make rules. So +# I keep them in a "macro" (see 'skeleton' below) that is expanded for +# every directory with Rules.mk (and its SRCS_VPATH subdirectories). +# Below setting means that %.o are made from %.cpp and the same for .cc +# and .c - this is just the list of mappings. +# You can add your own here. For example to add support for Fortran you +# would just append ".o:.f" and set COMPILE.f (actually make already +# defines it - just take a look at output of "make -p") +AUTO_RULES := .o:.cpp .o:.cc .o:.c +# Additional mapping together with corresponding variables can be specified +# in user_rules.mk +-include $(MK)/user_rules.mk + +# This compile command should be generic for most compilers - you should +# just define appropriate COMPILE.suffix variable. +COMPILECMD = $(COMPILE$(suffix $<)) -o $@ $< + +# In cases where from one source different types of objects can be +# generated I have added COMPILECMD_TD (TD stands for "target +# dependent"). So e.g. for OCaml one could use: +# CAML := ocamlc +# CAMLOPT := ocamlopt +# AUTO_TGTS += %.cmo %.cmx # or modify its value in skel.mk +# COMPILE.cmo.ml = $(call echo_cmd,CAML $<) $(CAML) -c +# COMPILE.cmx.ml = $(call echo_cmd,CAMLOPT $<) $(CAMLOPT) -c +# AUTO_TD_RULES := .cmo&.cmx:.ml +# The syntax for AUTO_TD_RULES is similar to AUTO_RULES but instead of +# single output suffix (e.g. ".o") you have to list them all separated +# by "&" (sorry, comma gives me problems since it is part of normal make +# syntax for functions :P). The above setting means that %.cmo and %.cmx +# can be generated from %.ml via their respective COMPILE commands +# expanded in COMPILECMD_TD (see below). + +# Again this should be generic enough so that you won't have to touch it +COMPILECMD_TD = $(COMPILE$(suffix $@)$(suffix $<)) -o $@ $< + +# Definition of variable ${\n} containing just new-line character +define \n + + +endef + +# Definition of 'skeleton' macro used in generation of recipes. This +# definition is itself computed so you should not modify it (unless you +# know what you are doing :D). It should be enough for you to add new +# mappings to AUTO_RULES and AUTO_TD_RULES above and define/change +# corresponding COMPILE.suffix and COMPILE.outsuffix.insuffix variables. +$(eval define skeleton$(foreach rule,$(AUTO_RULES),${\n}$$(OBJPATH)/%$(subst :,: $$(1)/%,$(rule)) | $$(OBJPATH); $$(value COMPILECMD))${\n}\ + $(foreach rule,$(AUTO_TD_RULES),${\n}$$(OBJPATH)/%$(subst :,: $$(1)/%,$(subst &, $$(OBJPATH)/%,$(rule))) | $$(OBJPATH); $$(value COMPILECMD_TD))${\n}endef) diff --git a/mk/footer.mk b/mk/footer.mk new file mode 100644 index 0000000..c6d19d3 --- /dev/null +++ b/mk/footer.mk @@ -0,0 +1,119 @@ +define FOOTER +SUBDIRS_$(d) := $(patsubst %/,%,$(addprefix $(d)/,$(SUBDIRS))) + +ifneq ($(strip $(OBJS)),) +OBJS_$(d) := $(addprefix $(OBJPATH)/,$(OBJS)) +else # Populate OBJS_ from SRCS + +# Expand wildcards in SRCS if they are given +ifneq ($(or $(findstring *,$(SRCS)),$(findstring ?,$(SRCS)),$(findstring ],$(SRCS))),) + SRCS := $(notdir $(foreach sd,. $(SRCS_VPATH),$(wildcard $(addprefix $(d)/$(sd)/,$(SRCS))))) + SRCS := $(filter-out $(SRCS_EXCLUDES), $(SRCS)) +endif + +OBJS_$(d) := $(addprefix $(OBJPATH)/,$(addsuffix .o,$(basename $(SRCS)))) +endif + +CLEAN_$(d) := $(CLEAN_$(d)) $(filter /%,$(CLEAN) $(TARGETS)) $(addprefix $(d)/,$(filter-out /%,$(CLEAN))) + +ifdef TARGETS +abs_tgts := $(filter /%, $(TARGETS)) +rel_tgts := $(filter-out /%,$(TARGETS)) +TARGETS_$(d) := $(abs_tgts) $(addprefix $(OBJPATH)/,$(rel_tgts)) +$(foreach tgt,$(filter-out $(AUTO_TGTS),$(rel_tgts)),$(eval $(call save_vars,$(OBJPATH)/,$(tgt)))) +# Absolute targets are entry points for external (sub)projects which +# have their own build system - what is really interesting is only CMD +# and possibly DEPS however I use this general save_vars (two more vars +# that are not going to be used should not be a problem :P). +$(foreach tgt,$(abs_tgts),$(eval $(call save_vars,,$(tgt)))) +else +TARGETS_$(d) := $(OBJS_$(d)) +endif + +# Save user defined vars +$(foreach v,$(VERB_VARS),$(eval $(v)_$(d) := $($v))) +$(foreach v,$(OBJ_VARS),$(eval $(v)_$(d) := $(addprefix $(OBJPATH)/,$($v)))) +$(foreach v,$(DIR_VARS),$(eval $(v)_$(d) := $(filter /%,$($v)) $(addprefix $(d)/,$(filter-out /%,$($v))))) + +# Update per directory variables that are automatically inherited +ifeq ($(origin INHERIT_DIR_VARS_$(d)),undefined) + INHERIT_DIR_VARS_$(d) := $(or $(INHERIT_DIR_VARS_$(parent_dir)), $(INHERIT_DIR_VARS)) +endif +$(foreach v,$(INHERIT_DIR_VARS_$(d)),$(if $($(v)_$(d)),,$(eval $(v)_$(d) := $($(v)_$(parent_dir))))) + +######################################################################## +# Inclusion of subdirectories rules - only after this line one can # +# refer to subdirectory targets and so on. # +######################################################################## +$(foreach sd,$(SUBDIRS),$(eval $(call include_subdir_rules,$(sd)))) + +.PHONY: dir_$(d) clean_$(d) clean_extra_$(d) clean_tree_$(d) dist_clean_$(d) +.SECONDARY: $(OBJPATH) + +# Whole tree targets +all :: $(TARGETS_$(d)) + +clean_all :: clean_$(d) + +# dist_clean is optimized in skel.mk if we are building in out of project tree +ifeq ($(strip $(TOP_BUILD_DIR)),) +dist_clean :: dist_clean_$(d) + +# No point to enforce clean_extra dependency if CLEAN is empty +ifeq ($(strip $(CLEAN_$(d))),) +dist_clean_$(d) : +else +dist_clean_$(d) : clean_extra_$(d) +endif + rm -rf $(DIST_CLEAN_DIR) +endif + +######################################################################## +# Per directory targets # +######################################################################## + +# Again - no point to enforce clean_extra dependency if CLEAN is empty +ifeq ($(strip $(CLEAN_$(d))),) +clean_$(d) : +else +clean_$(d) : clean_extra_$(d) +endif + rm -f $(CLEAN_DIR)/* + +# clean_extra is meant for the extra output that is generated in source +# directory (e.g. generated source from lex/yacc) so I'm not using +# TOP_BUILD_DIR below +clean_extra_$(d) : + rm -rf $(filter %/,$(CLEAN_$(subst clean_extra_,,$@))); rm -f $(filter-out %/,$(CLEAN_$(subst clean_extra_,,$@))) + +clean_tree_$(d) : clean_$(d) $(foreach sd,$(SUBDIRS_$(d)),clean_tree_$(sd)) + +# Skip the target rules generation and inclusion of the dependencies +# when we just want to clean up things :) +ifeq ($(filter clean clean_% dist_clean,$(MAKECMDGOALS)),) + +SUBDIRS_TGTS := $(foreach sd,$(SUBDIRS_$(d)),$(TARGETS_$(sd))) + +# Use the skeleton for the "current dir" +$(eval $(call skeleton,$(d))) +# and for each SRCS_VPATH subdirectory of "current dir" +$(foreach vd,$(SRCS_VPATH),$(eval $(call skeleton,$(d)/$(vd)))) + +# Target rules for all "non automatic" targets +$(foreach tgt,$(filter-out $(AUTO_TGTS),$(TARGETS_$(d))),$(eval $(call tgt_rule,$(tgt)))) + +# Way to build all targets in given subtree (not just current dir as via +# dir_$(d) - see below) +tree_$(d) : $(TARGETS_$(d)) $(foreach sd,$(SUBDIRS_$(d)),tree_$(sd)) + +# If the directory is just for grouping its targets will be targets from +# all subdirectories +ifeq ($(strip $(TARGETS_$(d))),) +TARGETS_$(d) := $(SUBDIRS_TGTS) +endif + +# This is a default rule - see Makefile +dir_$(d) : $(TARGETS_$(d)) + +endif +endef diff --git a/mk/header.mk b/mk/header.mk new file mode 100644 index 0000000..079be59 --- /dev/null +++ b/mk/header.mk @@ -0,0 +1,12 @@ +# Clear vars used by this make system +define HEADER +SRCS := +SRCS_EXCLUDES := +OBJS := +CLEAN := +TARGETS := +SUBDIRS := + +# Clear user vars +$(foreach v,$(VERB_VARS) $(OBJ_VARS) $(DIR_VARS),$(eval $(v) := )) +endef diff --git a/mk/skel.mk b/mk/skel.mk new file mode 100644 index 0000000..99547ea --- /dev/null +++ b/mk/skel.mk @@ -0,0 +1,254 @@ +# For the reference here are some automatic variables defined by make. +# There are also their D/F variants e.g. $(<D) - check the manual. +# +# $@ - file name of the target of the rule +# $% - target member name when the target is archive member +# $< - the name of the first dependency +# $? - the names of all dependencies that are newer then the target +# $^ - the names of all dependencies + +######################################################################## +# User defined variables # +######################################################################## + +# VERB_VARS is a list of variables that you'd like to record on per +# directory level. So if you set it to say AUTOTEST then each each +# directory will have it's own AUTOTEST_$(dir) variable with value taken +# from appropriate Rules.mk +VERB_VARS := + +# OBJ_VARS - like VERB_VARS but all values taken from Rules.mk have +# $(OBJPATH) prepended so instead of saying: +# INSTALL_$d := $(OBJPATH)/some_target +# you can say simply +# INSTALL := some_target +OBJ_VARS := INSTALL_BIN INSTALL_LIB + +# DIR_VARS - like VERB_VARS but all values taken from Rules.mk have $(d) +# prepended (unless value is an absolute path) so you can say: +# INSTALL_DOC := Readme.txt +# instead of: +# INSTALL_DOC_$d := $(d)/Readme.txt +DIR_VARS := INSTALL_DOC INSTALL_INC + +# NOTE: There is generic macro defined below with which you can get all +# values of given variable from some subtree e.g.: +# $(call get_subtree,INSTALL,dir) +# will give you value of all INSTALL variables from tree starting at +# 'dir' + +######################################################################## +# Directory specific flags # +######################################################################## + +# You just define in Rules.mk say +# INCLUDES_$(d) := .... +# and this will get expanded properly during compilation (see e.g. COMPILE.c) +# Of course you can still use the target specific variables if you want +# to have special setting for just one target and not the whole +# directory. See below for definition of @RD variable. +DIR_INCLUDES = $(addprefix -I,$(INCLUDES_$(@RD))) +DIR_CPPFLAGS = $(CPPFLAGS_$(@RD)) +DIR_CFLAGS = $(CFLAGS_$(@RD)) +DIR_CXXFLAGS = $(CXXFLAGS_$(@RD)) + +######################################################################## +# Global flags/settings # +######################################################################## + +CFLAGS = -g -W -Wall $(DIR_CFLAGS) +CXXFLAGS = -g -W -Wall $(DIR_CXXFLAGS) + +OPT_FLAGS := -O3 + +# List of includes that all (or at least majority) needs +INCLUDES := + +# Here's an example of settings for preprocessor. -MMD is to +# automatically build dependency files as a side effect of compilation. +# This has some drawbacks (e.g. when you move/rename a file) but it is +# good enough for me. You can improve this by using a special script +# that builds the dependency files (one can find examples on the web). +# Note that I'm adding DIR_INCLUDES before INCLUDES so that they have +# precedence. +CPPFLAGS = -MMD -D_REENTRANT -D_POSIX_C_SOURCE=200112L -D__EXTENSIONS__ \ + $(DIR_CPPFLAGS) $(DIR_INCLUDES) $(addprefix -I,$(INCLUDES)) + +# Linker flags. The values below will use what you've specified for +# particular target or directory but if you have some flags or libraries +# that should be used for all targets/directories just append them at end. +LDFLAGS = $(LDFLAGS_$(@)) $(addprefix -L,$(LIBDIRS_$(@RD))) + +# List of libraries that all targets need (either with specific command +# generated by this makefile system or for which make has built in rules +# since LDLIBS is a variable that implicit make rules are using). +# LDLIBS can be either simple or recursive, but simpler version is +# suggested :). +LDLIBS := + +######################################################################## +# The end of generic flags # +######################################################################## + +# Now we suck in configuration ... +include $(MK)/config.mk + +# ... optional build mode specific flags ... +ifdef BUILD_MODE + -include $(MK)/build-$(BUILD_MODE).mk +endif + +# ... host and build specific settings ... +ifneq ($(wildcard $(MK)/config-$(BUILD_ARCH)_$(HOST_ARCH).mk),) + include $(MK)/config-$(BUILD_ARCH)_$(HOST_ARCH).mk +else + include $(MK)/config-default.mk +endif + +# ... and here's a good place to translate some of these settings into +# compilation flags/variables. As an example a preprocessor macro for +# target endianess +ifeq ($(ENDIAN),big) + CPPFLAGS += -DBIG_ENDIAN +else + CPPFLAGS += -DLITTLE_ENDIAN +endif + +# Use host/build specific config files to override default extension +# for shared libraries +SOEXT := $(or $(SOEXT),so) + +######################################################################## +# A more advanced part - if you change anything below # +# you should have at least vague idea how this works :D # +######################################################################## + +# I define these for convenience - you can use them in your command for +# updating the target. +DEP_OBJS = $(filter %.o, $^) +DEP_ARCH = $(filter %.a, $^) +DEP_LIBS = $(addprefix -L,$(dir $(filter %.$(SOEXT), $^))) $(patsubst lib%.$(SOEXT),-l%,$(notdir $(filter %.$(SOEXT), $^))) + +# Kept for backward compatibility - you should stop using these since +# I'm now not dependent on $(OBJDIR)/.fake_file any more +?R = $? +^R = $^ + +# Targets that match this pattern (make pattern) will use rules defined +# in: +# - def_rules.mk included below (explicit or via `skeleton' macro) +# - built in make rules +# Other targets will have to use _DEPS (and so on) variables which are +# saved in `save_vars' and used in `tgt_rule' (see below). +AUTO_TGTS := %.o + +# Where to put the compiled objects. You can e.g. make it different +# depending on the target platform (e.g. for cross-compilation a good +# choice would be OBJDIR := obj/$(HOST_ARCH)) or debugging being on/off. +OBJDIR := $(if $(BUILD_MODE),obj/$(BUILD_MODE),obj) + +# Convenience function to convert from a build directory back to the +# "real directory" of a target +define build_to_real_dir +$(if $(strip $(TOP_BUILD_DIR)),$(patsubst $(TOP_BUILD_DIR)%/$(OBJDIR),$(TOP)%,$(1)),$(patsubst %/$(OBJDIR),%,$(1))) +endef + +# Convenience function to convert from the "real directory" to the build +# directory +define real_to_build_dir +$(if $(strip $(TOP_BUILD_DIR)),$(TOP_BUILD_DIR)$(subst $(TOP),,$(1))/$(OBJDIR),$(1)/$(OBJDIR)) +endef + +# By default OBJDIR is relative to the directory of the corresponding Rules.mk +# however you can use TOP_BUILD_DIR to build all objects outside of your +# project tree. This should be an absolute path. Note that it can be +# also inside your project like example below. +#TOP_BUILD_DIR := $(TOP)/build_dir +OBJPATH = $(call real_to_build_dir,$(d)) +CLEAN_DIR = $(call real_to_build_dir,$(subst clean_,,$@)) +DIST_CLEAN_DIR = $(patsubst %/$(OBJDIR),%/$(firstword $(subst /, ,$(OBJDIR))),\ + $(call real_to_build_dir,$(subst dist_clean_,,$@))) + +# This variable contains a list of subdirectories where to look for +# sources. That is if you have some/dir/Rules.mk where you name object +# say client.o this object will be created in some/dir/$(OBJDIR)/ and +# corresponding source file will be searched in some/dir and in +# some/dir/{x,y,z,...} where "x y z ..." is value of this variable. +SRCS_VPATH := src + +# Target "real directory" - this is used above already and is most +# reliable way to refer to "per directory flags". In theory one could +# use automatic variable already defined by make "<D" but this will not +# work well when somebody uses SRCS_VPATH variable. +@RD = $(call build_to_real_dir,$(@D)) + +# These are commands that are used to update the target. If you have +# a target that make handles with built in rules just add its pattern to +# the AUTO_TGTS below. Otherwise you have to supply the command and you +# can either do it explicitly with _CMD variable or based on the +# target's suffix and corresponding MAKECMD variable. For example %.a +# are # updated by MAKECMD.a (exemplary setting below). If the target +# is not filtered out by AUTO_TGTS and there's neither _CMD nor suffix +# specific command to build the target DEFAULT_MAKECMD is used. +MAKECMD.a = $(call echo_cmd,AR $@) $(AR) $(ARFLAGS) $@ $(DEP_OBJS) && $(RANLIB) $@ +MAKECMD.$(SOEXT) = $(LINK.cc) $(DEP_OBJS) $(DEP_ARCH) $(DEP_LIBS) $(LIBS_$(@)) $(LDLIBS) -shared -o $@ +DEFAULT_MAKECMD = $(LINK.cc) $(DEP_OBJS) $(DEP_ARCH) $(DEP_LIBS) $(LIBS_$(@)) $(LDLIBS) -o $@ + +######################################################################## +# Below is a "Blood sugar sex^H^H^Hmake magik" :) - don't touch it # +# unless you know what you are doing. # +######################################################################## + +# This can be useful. E.g. if you want to set INCLUDES_$(d) for given +# $(d) to the same value as includes for its parent directory plus some +# add ons then: INCLUDES_$(d) := $(INCLUDES_$(parent_dir)) ... +parent_dir = $(patsubst %/,%,$(dir $(d))) + +define include_subdir_rules +dir_stack := $(d) $(dir_stack) +d := $(d)/$(1) +$$(eval $$(value HEADER)) +include $(addsuffix /Rules.mk,$$(d)) +$$(eval $$(value FOOTER)) +d := $$(firstword $$(dir_stack)) +dir_stack := $$(wordlist 2,$$(words $$(dir_stack)),$$(dir_stack)) +endef + +define save_vars +DEPS_$(1)$(2) = $(value $(2)_DEPS) +LIBS_$(1)$(2) = $(value $(2)_LIBS) +LDFLAGS_$(1)$(2) = $(value $(2)_LDFLAGS) +CMD_$(1)$(2) = $(value $(2)_CMD) +$(2)_DEPS = +$(2)_LIBS = +$(2)_LDFLAGS = +$(2)_CMD = +endef + +define tgt_rule +abs_deps := $$(foreach dep,$$(DEPS_$(1)),$$(if $$(or $$(filter /%,$$(dep)),$$(filter $$$$%,$$(dep))),$$(dep),$$(addprefix $(OBJPATH)/,$$(dep)))) +-include $$(addsuffix .d,$$(basename $$(abs_deps))) +$(1): $$(abs_deps) $(if $(findstring $(OBJDIR),$(1)),| $(OBJPATH),) + $$(or $$(CMD_$(1)),$$(MAKECMD$$(suffix $$@)),$$(DEFAULT_MAKECMD)) +endef + +# subtree_tgts is now just a special case of a more general get_subtree +# macro since $(call get_subtree,TARGETS,dir) has the same effect but +# I'm keeping it for backward compatibility +define subtree_tgts +$(TARGETS_$(1)) $(foreach sd,$(SUBDIRS_$(1)),$(call subtree_tgts,$(sd))) +endef + +define get_subtree +$($(1)_$(2)) $(foreach sd,$(SUBDIRS_$(2)),$(call get_subtree,$(1),$(sd))) +endef + +# if we are using out of project build tree then there is no need to +# have dist_clean on per directory level and the one below is enough +ifneq ($(strip $(TOP_BUILD_DIR)),) +dist_clean : + rm -rf $(TOP_BUILD_DIR) +endif + +# Suck in the default rules +include $(MK)/def_rules.mk |