|
| 1 | +# boilermake: A reusable, but flexible, boilerplate Makefile. |
| 2 | +# |
| 3 | +# Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok |
| 4 | +# |
| 5 | +# This program is free software: you can redistribute it and/or modify |
| 6 | +# it under the terms of the GNU General Public License as published by |
| 7 | +# the Free Software Foundation, either version 3 of the License, or |
| 8 | +# (at your option) any later version. |
| 9 | +# |
| 10 | +# This program is distributed in the hope that it will be useful, |
| 11 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | +# GNU General Public License for more details. |
| 14 | +# |
| 15 | +# You should have received a copy of the GNU General Public License |
| 16 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | + |
| 18 | +# Caution: Don't edit this Makefile! Create your own main.mk and other |
| 19 | +# submakefiles, which will be included by this Makefile. |
| 20 | +# Only edit this if you need to modify boilermake's behavior (fix |
| 21 | +# bugs, add features, etc). |
| 22 | + |
| 23 | +# Note: Parameterized "functions" in this makefile that are marked with |
| 24 | +# "USE WITH EVAL" are only useful in conjuction with eval. This is |
| 25 | +# because those functions result in a block of Makefile syntax that must |
| 26 | +# be evaluated after expansion. Since they must be used with eval, most |
| 27 | +# instances of "$" within them need to be escaped with a second "$" to |
| 28 | +# accomodate the double expansion that occurs when eval is invoked. |
| 29 | + |
| 30 | +# ADD_CLEAN_RULE - Parameterized "function" that adds a new rule and phony |
| 31 | +# target for cleaning the specified target (removing its build-generated |
| 32 | +# files). |
| 33 | +# |
| 34 | +# USE WITH EVAL |
| 35 | +# |
| 36 | +define ADD_CLEAN_RULE |
| 37 | + clean: clean_${1} |
| 38 | + .PHONY: clean_${1} |
| 39 | + clean_${1}: |
| 40 | + $$(strip rm -f ${TARGET_DIR}/${1} $${${1}_OBJS:%.o=%.[doP]}) |
| 41 | + $${${1}_POSTCLEAN} |
| 42 | +endef |
| 43 | + |
| 44 | +# ADD_OBJECT_RULE - Parameterized "function" that adds a pattern rule for |
| 45 | +# building object files from source files with the filename extension |
| 46 | +# specified in the second argument. The first argument must be the name of the |
| 47 | +# base directory where the object files should reside (such that the portion |
| 48 | +# of the path after the base directory will match the path to corresponding |
| 49 | +# source files). The third argument must contain the rules used to compile the |
| 50 | +# source files into object code form. |
| 51 | +# |
| 52 | +# USE WITH EVAL |
| 53 | +# |
| 54 | +define ADD_OBJECT_RULE |
| 55 | +${1}/%.o: ${2} |
| 56 | + ${3} |
| 57 | +endef |
| 58 | + |
| 59 | +# ADD_TARGET_RULE - Parameterized "function" that adds a new target to the |
| 60 | +# Makefile. The target may be an executable or a library. The two allowable |
| 61 | +# types of targets are distinguished based on the name: library targets must |
| 62 | +# end with the traditional ".a" extension. |
| 63 | +# |
| 64 | +# USE WITH EVAL |
| 65 | +# |
| 66 | +define ADD_TARGET_RULE |
| 67 | + ifeq "$$(suffix ${1})" ".a" |
| 68 | + # Add a target for creating a static library. |
| 69 | + $${TARGET_DIR}/${1}: $${${1}_OBJS} |
| 70 | + @mkdir -p $$(dir $$@) |
| 71 | + $$(strip $${AR} $${ARFLAGS} $$@ $${${1}_OBJS}) |
| 72 | + $${${1}_POSTMAKE} |
| 73 | + else |
| 74 | + # Add a target for linking an executable. First, attempt to select the |
| 75 | + # appropriate front-end to use for linking. This might not choose the |
| 76 | + # right one (e.g. if linking with a C++ static library, but all other |
| 77 | + # sources are C sources), so the user makefile is allowed to specify a |
| 78 | + # linker to be used for each target. |
| 79 | + ifeq "$$(strip $${${1}_LINKER})" "" |
| 80 | + # No linker was explicitly specified to be used for this target. If |
| 81 | + # there are any C++ sources for this target, use the C++ compiler. |
| 82 | + # For all other targets, default to using the C compiler. |
| 83 | + ifneq "$$(strip $$(filter $${CXX_SRC_EXTS},$${${1}_SOURCES}))" "" |
| 84 | + ${1}_LINKER = $${CXX} |
| 85 | + else |
| 86 | + ${1}_LINKER = $${CC} |
| 87 | + endif |
| 88 | + endif |
| 89 | + |
| 90 | + $${TARGET_DIR}/${1}: $${${1}_OBJS} $${${1}_PREREQS} |
| 91 | + @mkdir -p $$(dir $$@) |
| 92 | + $$(strip $${${1}_LINKER} -o $$@ $${LDFLAGS} $${${1}_LDFLAGS} \ |
| 93 | + $${${1}_OBJS} $${LDLIBS} $${${1}_LDLIBS}) |
| 94 | + $${${1}_POSTMAKE} |
| 95 | + endif |
| 96 | +endef |
| 97 | + |
| 98 | +# CANONICAL_PATH - Given one or more paths, converts the paths to the canonical |
| 99 | +# form. The canonical form is the path, relative to the project's top-level |
| 100 | +# directory (the directory from which "make" is run), and without |
| 101 | +# any "./" or "../" sequences. For paths that are not located below the |
| 102 | +# top-level directory, the canonical form is the absolute path (i.e. from |
| 103 | +# the root of the filesystem) also without "./" or "../" sequences. |
| 104 | +define CANONICAL_PATH |
| 105 | +$(patsubst ${CURDIR}/%,%,$(abspath ${1})) |
| 106 | +endef |
| 107 | + |
| 108 | +# COMPILE_C_CMDS - Commands for compiling C source code. |
| 109 | +define COMPILE_C_CMDS |
| 110 | + @mkdir -p $(dir $@) |
| 111 | + $(strip ${CC} -o $@ -c -MD ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \ |
| 112 | + ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<) |
| 113 | + @cp ${@:%$(suffix $@)=%.d} ${@:%$(suffix $@)=%.P}; \ |
| 114 | + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ |
| 115 | + -e '/^$$/ d' -e 's/$$/ :/' < ${@:%$(suffix $@)=%.d} \ |
| 116 | + >> ${@:%$(suffix $@)=%.P}; \ |
| 117 | + rm -f ${@:%$(suffix $@)=%.d} |
| 118 | +endef |
| 119 | + |
| 120 | +# COMPILE_CXX_CMDS - Commands for compiling C++ source code. |
| 121 | +define COMPILE_CXX_CMDS |
| 122 | + @mkdir -p $(dir $@) |
| 123 | + $(strip ${CXX} -o $@ -c -MD ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \ |
| 124 | + ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<) |
| 125 | + @cp ${@:%$(suffix $@)=%.d} ${@:%$(suffix $@)=%.P}; \ |
| 126 | + sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ |
| 127 | + -e '/^$$/ d' -e 's/$$/ :/' < ${@:%$(suffix $@)=%.d} \ |
| 128 | + >> ${@:%$(suffix $@)=%.P}; \ |
| 129 | + rm -f ${@:%$(suffix $@)=%.d} |
| 130 | +endef |
| 131 | + |
| 132 | +# INCLUDE_SUBMAKEFILE - Parameterized "function" that includes a new |
| 133 | +# "submakefile" fragment into the overall Makefile. It also recursively |
| 134 | +# includes all submakefiles of the specified submakefile fragment. |
| 135 | +# |
| 136 | +# USE WITH EVAL |
| 137 | +# |
| 138 | +define INCLUDE_SUBMAKEFILE |
| 139 | + # Initialize all variables that can be defined by a makefile fragment, then |
| 140 | + # include the specified makefile fragment. |
| 141 | + TARGET := |
| 142 | + TGT_CFLAGS := |
| 143 | + TGT_CXXFLAGS := |
| 144 | + TGT_DEFS := |
| 145 | + TGT_INCDIRS := |
| 146 | + TGT_LDFLAGS := |
| 147 | + TGT_LDLIBS := |
| 148 | + TGT_LINKER := |
| 149 | + TGT_POSTCLEAN := |
| 150 | + TGT_POSTMAKE := |
| 151 | + TGT_PREREQS := |
| 152 | + |
| 153 | + SOURCES := |
| 154 | + SRC_CFLAGS := |
| 155 | + SRC_CXXFLAGS := |
| 156 | + SRC_DEFS := |
| 157 | + SRC_INCDIRS := |
| 158 | + |
| 159 | + SUBMAKEFILES := |
| 160 | + |
| 161 | + # A directory stack is maintained so that the correct paths are used as we |
| 162 | + # recursively include all submakefiles. Get the makefile's directory and |
| 163 | + # push it onto the stack. |
| 164 | + DIR := $(call CANONICAL_PATH,$(dir ${1})) |
| 165 | + DIR_STACK := $$(call PUSH,$${DIR_STACK},$${DIR}) |
| 166 | + |
| 167 | + include ${1} |
| 168 | + |
| 169 | + # Initialize internal local variables. |
| 170 | + OBJS := |
| 171 | + |
| 172 | + # Ensure that valid values are set for BUILD_DIR and TARGET_DIR. |
| 173 | + ifeq "$$(strip $${BUILD_DIR})" "" |
| 174 | + BUILD_DIR := build |
| 175 | + endif |
| 176 | + ifeq "$$(strip $${TARGET_DIR})" "" |
| 177 | + TARGET_DIR := . |
| 178 | + endif |
| 179 | + |
| 180 | + # Determine which target this makefile's variables apply to. A stack is |
| 181 | + # used to keep track of which target is the "current" target as we |
| 182 | + # recursively include other submakefiles. |
| 183 | + ifneq "$$(strip $${TARGET})" "" |
| 184 | + # This makefile defined a new target. Target variables defined by this |
| 185 | + # makefile apply to this new target. Initialize the target's variables. |
| 186 | + TGT := $$(strip $${TARGET}) |
| 187 | + ALL_TGTS += $${TGT} |
| 188 | + $${TGT}_CFLAGS := $${TGT_CFLAGS} |
| 189 | + $${TGT}_CXXFLAGS := $${TGT_CXXFLAGS} |
| 190 | + $${TGT}_DEFS := $${TGT_DEFS} |
| 191 | + $${TGT}_DEPS := |
| 192 | + $${TGT}_INCDIRS := $${TGT_INCDIRS} |
| 193 | + $${TGT}_LDFLAGS := $${TGT_LDFLAGS} |
| 194 | + $${TGT}_LDLIBS := $${TGT_LDLIBS} |
| 195 | + $${TGT}_LINKER := $${TGT_LINKER} |
| 196 | + $${TGT}_OBJS := |
| 197 | + $${TGT}_POSTCLEAN := $${TGT_POSTCLEAN} |
| 198 | + $${TGT}_POSTMAKE := $${TGT_POSTMAKE} |
| 199 | + $${TGT}_PREREQS := $$(addprefix $${TARGET_DIR}/,$${TGT_PREREQS}) |
| 200 | + $${TGT}_SOURCES := |
| 201 | + else |
| 202 | + # The values defined by this makefile apply to the the "current" target |
| 203 | + # as determined by which target is at the top of the stack. |
| 204 | + TGT := $$(strip $$(call PEEK,$${TGT_STACK})) |
| 205 | + $${TGT}_CFLAGS += $${TGT_CFLAGS} |
| 206 | + $${TGT}_CXXFLAGS += $${TGT_CXXFLAGS} |
| 207 | + $${TGT}_DEFS += $${TGT_DEFS} |
| 208 | + $${TGT}_INCDIRS += $${TGT_INCDIRS} |
| 209 | + $${TGT}_LDFLAGS += $${TGT_LDFLAGS} |
| 210 | + $${TGT}_LDLIBS += $${TGT_LDLIBS} |
| 211 | + $${TGT}_POSTCLEAN += $${TGT_POSTCLEAN} |
| 212 | + $${TGT}_POSTMAKE += $${TGT_POSTMAKE} |
| 213 | + $${TGT}_PREREQS += $${TGT_PREREQS} |
| 214 | + endif |
| 215 | + |
| 216 | + # Push the current target onto the target stack. |
| 217 | + TGT_STACK := $$(call PUSH,$${TGT_STACK},$${TGT}) |
| 218 | + |
| 219 | + ifneq "$$(strip $${SOURCES})" "" |
| 220 | + # This makefile builds one or more objects from source. Validate the |
| 221 | + # specified sources against the supported source file types. |
| 222 | + BAD_SRCS := $$(strip $$(filter-out $${ALL_SRC_EXTS},$${SOURCES})) |
| 223 | + ifneq "$${BAD_SRCS}" "" |
| 224 | + $$(error Unsupported source file(s) found in ${1} [$${BAD_SRCS}]) |
| 225 | + endif |
| 226 | + |
| 227 | + # Qualify and canonicalize paths. |
| 228 | + SOURCES := $$(call QUALIFY_PATH,$${DIR},$${SOURCES}) |
| 229 | + SOURCES := $$(call CANONICAL_PATH,$${SOURCES}) |
| 230 | + SRC_INCDIRS := $$(call QUALIFY_PATH,$${DIR},$${SRC_INCDIRS}) |
| 231 | + SRC_INCDIRS := $$(call CANONICAL_PATH,$${SRC_INCDIRS}) |
| 232 | + |
| 233 | + # Save the list of source files for this target. |
| 234 | + $${TGT}_SOURCES += $${SOURCES} |
| 235 | + |
| 236 | + # Convert the source file names to their corresponding object file |
| 237 | + # names. |
| 238 | + OBJS := $$(addprefix $${BUILD_DIR}/$$(call CANONICAL_PATH,$${TGT})/,\ |
| 239 | + $$(addsuffix .o,$$(basename $${SOURCES}))) |
| 240 | + |
| 241 | + # Add the objects to the current target's list of objects, and create |
| 242 | + # target-specific variables for the objects based on any source |
| 243 | + # variables that were defined. |
| 244 | + $${TGT}_OBJS += $${OBJS} |
| 245 | + $${TGT}_DEPS += $${OBJS:%.o=%.P} |
| 246 | + $${OBJS}: SRC_CFLAGS := $${$${TGT}_CFLAGS} $${SRC_CFLAGS} |
| 247 | + $${OBJS}: SRC_CXXFLAGS := $${$${TGT}_CXXFLAGS} $${SRC_CXXFLAGS} |
| 248 | + $${OBJS}: SRC_DEFS := $$(addprefix -D,$${$${TGT}_DEFS} $${SRC_DEFS}) |
| 249 | + $${OBJS}: SRC_INCDIRS := $$(addprefix -I,\ |
| 250 | + $${$${TGT}_INCDIRS} $${SRC_INCDIRS}) |
| 251 | + endif |
| 252 | + |
| 253 | + ifneq "$$(strip $${SUBMAKEFILES})" "" |
| 254 | + # This makefile has submakefiles. Recursively include them. |
| 255 | + $$(foreach MK,$${SUBMAKEFILES},\ |
| 256 | + $$(eval $$(call INCLUDE_SUBMAKEFILE,\ |
| 257 | + $$(call CANONICAL_PATH,\ |
| 258 | + $$(call QUALIFY_PATH,$${DIR},$${MK}))))) |
| 259 | + endif |
| 260 | + |
| 261 | + # Reset the "current" target to it's previous value. |
| 262 | + TGT_STACK := $$(call POP,$${TGT_STACK}) |
| 263 | + TGT := $$(call PEEK,$${TGT_STACK}) |
| 264 | + |
| 265 | + # Reset the "current" directory to it's previous value. |
| 266 | + DIR_STACK := $$(call POP,$${DIR_STACK}) |
| 267 | + DIR := $$(call PEEK,$${DIR_STACK}) |
| 268 | +endef |
| 269 | + |
| 270 | +# MIN - Parameterized "function" that results in the minimum lexical value of |
| 271 | +# the two values given. |
| 272 | +define MIN |
| 273 | +$(firstword $(sort ${1} ${2})) |
| 274 | +endef |
| 275 | + |
| 276 | +# PEEK - Parameterized "function" that results in the value at the top of the |
| 277 | +# specified colon-delimited stack. |
| 278 | +define PEEK |
| 279 | +$(lastword $(subst :, ,${1})) |
| 280 | +endef |
| 281 | + |
| 282 | +# POP - Parameterized "function" that pops the top value off of the specified |
| 283 | +# colon-delimited stack, and results in the new value of the stack. Note that |
| 284 | +# the popped value cannot be obtained using this function; use peek for that. |
| 285 | +define POP |
| 286 | +${1:%:$(lastword $(subst :, ,${1}))=%} |
| 287 | +endef |
| 288 | + |
| 289 | +# PUSH - Parameterized "function" that pushes a value onto the specified colon- |
| 290 | +# delimited stack, and results in the new value of the stack. |
| 291 | +define PUSH |
| 292 | +${2:%=${1}:%} |
| 293 | +endef |
| 294 | + |
| 295 | +# QUALIFY_PATH - Given a "root" directory and one or more paths, qualifies the |
| 296 | +# paths using the "root" directory (i.e. appends the root directory name to |
| 297 | +# the paths) except for paths that are absolute. |
| 298 | +define QUALIFY_PATH |
| 299 | +$(addprefix ${1}/,$(filter-out /%,${2})) $(filter /%,${2}) |
| 300 | +endef |
| 301 | + |
| 302 | +############################################################################### |
| 303 | +# |
| 304 | +# Start of Makefile Evaluation |
| 305 | +# |
| 306 | +############################################################################### |
| 307 | + |
| 308 | +# Older versions of GNU Make lack capabilities needed by boilermake. |
| 309 | +# With older versions, "make" may simply output "nothing to do", likely leading |
| 310 | +# to confusion. To avoid this, check the version of GNU make up-front and |
| 311 | +# inform the user if their version of make doesn't meet the minimum required. |
| 312 | +MIN_MAKE_VERSION := 3.81 |
| 313 | +MIN_MAKE_VER_MSG := boilermake requires GNU Make ${MIN_MAKE_VERSION} or greater |
| 314 | +ifeq "${MAKE_VERSION}" "" |
| 315 | + $(info GNU Make not detected) |
| 316 | + $(error ${MIN_MAKE_VER_MSG}) |
| 317 | +endif |
| 318 | +ifneq "${MIN_MAKE_VERSION}" "$(call MIN,${MIN_MAKE_VERSION},${MAKE_VERSION})" |
| 319 | + $(info This is GNU Make version ${MAKE_VERSION}) |
| 320 | + $(error ${MIN_MAKE_VER_MSG}) |
| 321 | +endif |
| 322 | + |
| 323 | +# Define the source file extensions that we know how to handle. |
| 324 | +C_SRC_EXTS := %.c |
| 325 | +CXX_SRC_EXTS := %.C %.cc %.cp %.cpp %.CPP %.cxx %.c++ |
| 326 | +ALL_SRC_EXTS := ${C_SRC_EXTS} ${CXX_SRC_EXTS} |
| 327 | + |
| 328 | +# Initialize global variables. |
| 329 | +ALL_TGTS := |
| 330 | +DEFS := |
| 331 | +DIR_STACK := |
| 332 | +INCDIRS := |
| 333 | +TGT_STACK := |
| 334 | + |
| 335 | +# Include the main user-supplied submakefile. This also recursively includes |
| 336 | +# all other user-supplied submakefiles. |
| 337 | +$(eval $(call INCLUDE_SUBMAKEFILE,main.mk)) |
| 338 | + |
| 339 | +# Perform post-processing on global variables as needed. |
| 340 | +DEFS := $(addprefix -D,${DEFS}) |
| 341 | +INCDIRS := $(addprefix -I,$(call CANONICAL_PATH,${INCDIRS})) |
| 342 | + |
| 343 | +# Define the "all" target (which simply builds all user-defined targets) as the |
| 344 | +# default goal. |
| 345 | +.PHONY: all |
| 346 | +all: $(addprefix ${TARGET_DIR}/,${ALL_TGTS}) |
| 347 | + |
| 348 | +# Add a new target rule for each user-defined target. |
| 349 | +$(foreach TGT,${ALL_TGTS},\ |
| 350 | + $(eval $(call ADD_TARGET_RULE,${TGT}))) |
| 351 | + |
| 352 | +# Add pattern rule(s) for creating compiled object code from C source. |
| 353 | +$(foreach TGT,${ALL_TGTS},\ |
| 354 | + $(foreach EXT,${C_SRC_EXTS},\ |
| 355 | + $(eval $(call ADD_OBJECT_RULE,${BUILD_DIR}/$(call CANONICAL_PATH,${TGT}),\ |
| 356 | + ${EXT},$${COMPILE_C_CMDS})))) |
| 357 | + |
| 358 | +# Add pattern rule(s) for creating compiled object code from C++ source. |
| 359 | +$(foreach TGT,${ALL_TGTS},\ |
| 360 | + $(foreach EXT,${CXX_SRC_EXTS},\ |
| 361 | + $(eval $(call ADD_OBJECT_RULE,${BUILD_DIR}/$(call CANONICAL_PATH,${TGT}),\ |
| 362 | + ${EXT},$${COMPILE_CXX_CMDS})))) |
| 363 | + |
| 364 | +# Add "clean" rules to remove all build-generated files. |
| 365 | +.PHONY: clean |
| 366 | +$(foreach TGT,${ALL_TGTS},\ |
| 367 | + $(eval $(call ADD_CLEAN_RULE,${TGT}))) |
| 368 | + |
| 369 | +# Include generated rules that define additional (header) dependencies. |
| 370 | +$(foreach TGT,${ALL_TGTS},\ |
| 371 | + $(eval -include ${${TGT}_DEPS})) |
0 commit comments