# boilermake: A reusable, but flexible, boilerplate Makefile. # # Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Caution: Don't edit this Makefile! Create your own main.mk and other # submakefiles, which will be included by this Makefile. # Only edit this if you need to modify boilermake's behavior (fix # bugs, add features, etc). # Note: Parameterized "functions" in this makefile that are marked with # "USE WITH EVAL" are only useful in conjuction with eval. This is # because those functions result in a block of Makefile syntax that must # be evaluated after expansion. Since they must be used with eval, most # instances of "$" within them need to be escaped with a second "$" to # accomodate the double expansion that occurs when eval is invoked. # # You can watch what it's doing by: # # $ VERBOSE=1 make ... args ... # ifeq "${VERBOSE}" "" Q=@ else Q= endif # ADD_CLEAN_RULE - Parameterized "function" that adds a new rule and phony # target for cleaning the specified target (removing its build-generated # files). # # USE WITH EVAL # define ADD_CLEAN_RULE clean: clean_$(notdir ${1}) .PHONY: clean_$(notdir ${1}) clean_$(notdir ${1}): $(Q)$(strip rm -f ${${1}_BUILD}/${1} $${${1}_OBJS} $${${1}_DEPS} $${${1}_OBJS:%.${OBJ_EXT}=%.[do]}) $(if ${TARGET_DIR},$${TARGET_DIR}/$(notdir ${1})) $${${1}_POSTCLEAN} endef # FILTER_DEPENDS: function to turn a *.d file into a *.mk file. # We start off with the dependencies as created by the compiler, # CPP, or makedepend. We then ensure that there is an empty dependency # for each header file. The blank target ensures that the build # can proceed even if the header file has been deleted. # # COMMON filters: # remove comments # remove dependencies on global include files # remove empty dependencies # remove CPP hacks like "foo: " # # 1) Filter the .d file to remove unnecessary cruft # # COMMON # Replace ".o" with "${OBJ_EXT}" # delete empty continuation lines # delete blank lines # replace "build/" with "${BUILD_DIR}/" when it's at the start of a line # delete references to ${BUILD_DIR}/make/include, the "config.mk" # file adds these dependencies automatically. # replace "build/" with "${BUILD_DIR}/" when it's in the middle of a line # # remove sequential duplicate lines # # 2) Create empty dependencies from the files # # COMMON # remove existing targets # remove continuations (to make the targets stand by themselves) # delete blank lines # add in empty dependency for each file. # remove sequential duplicate lines # define FILTER_DEPENDS $(Q)mkdir -p $$(dir $${BUILD_DIR}/make/src/$$*) $(Q)mkdir -p $$(dir $${BUILD_DIR}/objs/$$*) $(Q)sed -e 's/#.*//' \ -e 's,^$${top_srcdir},$$$${top_srcdir},' \ -e 's, $${top_srcdir}, $$$${top_srcdir},' \ -e 's,^$${BUILD_DIR},$$$${BUILD_DIR},' \ -e 's, $${BUILD_DIR}/make/include/[^ :]*,,' \ -e 's, $${BUILD_DIR}, $$$${BUILD_DIR},' \ -e 's, /[^: ]*,,g' \ -e 's,^ *[^:]* *: *$$$$,,' \ -e '/: $${BUILD_DIR}/make/src/$$*.mk $(Q)sed -e 's/#.*//' \ -e 's, $${BUILD_DIR}/make/include/[^ :]*,,' \ -e 's, /[^: ]*,,g' \ -e 's,^ *[^:]* *: *$$$$,,' \ -e '/: > $${BUILD_DIR}/make/src/$$*.mk endef # ADD_OBJECT_RULE - Parameterized "function" that adds a pattern rule, using # the commands from the second argument, for building object files from # source files with the filename extension specified in the first argument. # # This function assumes that the C/C++ sources files have filenames # *relative* to the source root. If they have absolute pathnames, it # creates the wrong filenames... # # USE WITH EVAL # ifeq "${CPP_MAKEDEPEND}" "yes" define ADD_OBJECT_RULE $${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD} ${2} $${CPP} $${CPPFLAGS} $$(addprefix -I,$${SRC_INCDIRS}) $${SRC_DEFS} $$< | sed \ -n 's,^\# *[0-9][0-9]* *"\([^"]*\)".*,$$@: \1,p' > $${BUILD_DIR}/objs/$$*.d ${FILTER_DEPENDS} endef else define ADD_OBJECT_RULE $${BUILD_DIR}/objs/%.${OBJ_EXT} $${BUILD_DIR}/objs/%.d: ${1} | ${BOOTSTRAP_BUILD} ${2} ${FILTER_DEPENDS} endef endif define ADD_ANALYZE_RULE $${BUILD_DIR}/plist/%.plist: ${1} ${2} endef # ADD_TARGET_DIR - Parameterized "function" that makes a link from # TARGET_DIR to the executable or library in the BUILD_DIR directory. # # USE WITH EVAL # ifneq "${TARGET_DIR}" "" define ADD_TARGET_DIR all: $${TARGET_DIR}/$$(notdir ${1}) $${TARGET_DIR}/$$(notdir ${1}): ${1} [ -f $${TARGET_DIR}/$$(notdir ${1}) ] || ln -s ${1} $${TARGET_DIR}/$$(notdir ${1}) endef endif # ADD_TARGET_TO_ALL - Parameterized "function" that adds the target, # and makes "all" depend on it. # # USE WITH EVAL # define ADD_TARGET_TO_ALL all: ${1} endef # ADD_TARGET_RULE.* - Parameterized "functions" that adds a new target to the # Makefile. There should be one ADD_TARGET_RULE definition for each # type of target that is used in the build. # # New rules can be added by copying one of the existing ones, and # replacing the line after the "mkdir" # # ADD_TARGET_RULE.exe - Build an executable target. # # USE WITH EVAL # define ADD_TARGET_RULE.exe # So "make ${1}" works .PHONY: ${1} ${1}: $${${1}_BUILD}/${1} # Create executable ${1} $${${1}_BUILD}/${1}: $${${1}_OBJS} $${${1}_PRBIN} $${${1}_PRLIBS} $(Q)$(strip mkdir -p $(dir $${${1}_BUILD}/${1})) $(Q)$(ECHO) LINK $${${1}_BUILD}/${1} $(Q)$${${1}_LINKER} -o $${${1}_BUILD}/${1} $${RPATH_FLAGS} $${LDFLAGS} \ $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_PRLIBS} \ $${LDLIBS} $${${1}_LDLIBS} $(Q)$${${1}_POSTMAKE} ifneq "${ANALYZE.c}" "" scan.${1}: $${${1}_PLISTS} endif .PHONY: $(DIR) $(DIR)/: ${1} endef # ADD_TARGET_RULE.a - Build a static library target. # # USE WITH EVAL # define ADD_TARGET_RULE.a # So "make ${1}" works .PHONY: ${1} ${1}: $${${1}_BUILD}/${1} # Create static library ${1} $${${1}_BUILD}/${1}: $${${1}_OBJS} $${${1}_PRLIBS} $(Q)$(strip mkdir -p $(dir $${${1}_BUILD}/${1})) $(Q)$(ECHO) LINK $${${1}_BUILD}/${1} $(Q)$${AR} $${ARFLAGS} $${${1}_BUILD}/${1} $${${1}_OBJS} $(Q)$${${1}_POSTMAKE} ifneq "${ANALYZE.c}" "" scan.${1}: $${${1}_PLISTS} endif .PHONY: $(DIR) $(DIR)/: ${1} endef # ADD_TARGET_RULE.so - Build a ".so" target. # # USE WITH EVAL # define ADD_TARGET_RULE.so $(error Please add rules to build a ".so" file.) endef # ADD_TARGET_RULE.dll - Build a ".dll" target. # # USE WITH EVAL # define ADD_TARGET_RULE.dll $(error Please add rules to build a ".dll" file.) endef # ADD_TARGET_RULE.dylib - Build a ".dylib" target. # # USE WITH EVAL # define ADD_TARGET_RULE.dylib $(error Please add rules to build a ".dylib" file.) endef # CANONICAL_PATH - Given one or more paths, converts the paths to the canonical # form. The canonical form is the path, relative to the project's top-level # directory (the directory from which "make" is run), and without # any "./" or "../" sequences. For paths that are not located below the # top-level directory, the canonical form is the absolute path (i.e. from # the root of the filesystem) also without "./" or "../" sequences. define CANONICAL_PATH $(patsubst ${CURDIR}/%,%,$(abspath ${1})) endef # COMPILE_C_CMDS - Commands for compiling C source code. ifeq "$(CPPCHECK)" "" define COMPILE_C_CMDS $(Q)mkdir -p $(dir $@) $(Q)$(ECHO) CC $< $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CPPFLAGS} ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \ $(addprefix -I, ${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<) endef else # # do cppcheck AND compilation, so that we have correct dependencies # Suppress variable scope warnings for now. They're style, and don't really # affect anything. # define COMPILE_C_CMDS $(Q)mkdir -p $(dir $@) $(Q)$(ECHO) CC $< $(Q)$(strip ${COMPILE.c} -o $@ -c -MD ${CPPFLAGS} ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<) $(Q)cppcheck --enable=style -q ${CHECKFLAGS} $(filter -isystem%,${SRC_CFLAGS}) \ $(filter -I%,${SRC_CFLAGS}) $(filter -D%,${SRC_CFLAGS}) ${INCDIRS} \ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} --suppress=variableScope --suppress=invalidscanf $< endef endif # ANALYZE_C_CMDS - Commands for analyzing C source code with clang. define ANALYZE_C_CMDS $(Q)mkdir -p $(dir $@) $(Q)$(ECHO) SCAN $< $(Q)$(strip ${ANALYZE.c} --analyze -Xanalyzer -analyzer-output=html -c $< -o $@ ${CPPFLAGS} \ ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS}) || (rm -f $@ && false) $(Q)touch $@ endef # COMPILE_CXX_CMDS - Commands for compiling C++ source code. define COMPILE_CXX_CMDS $(Q)mkdir -p $(dir $@) $(Q)$(strip ${COMPILE.cxx} -o $@ -c -MD ${CPPFLAGS} ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \ $(addprefix -I,${SRC_INCDIRS}) ${SRC_DEFS} ${DEFS} $<) endef # INCLUDE_SUBMAKEFILE - Parameterized "function" that includes a new # "submakefile" fragment into the overall Makefile. It also recursively # includes all submakefiles of the specified submakefile fragment. # # USE WITH EVAL # define INCLUDE_SUBMAKEFILE # Initialize all variables that can be defined by a makefile fragment, then # include the specified makefile fragment. TARGET := TGT_LDFLAGS := TGT_LDLIBS := TGT_LINKER := TGT_POSTCLEAN := TGT_POSTMAKE := TGT_PREREQS := TGT_POSTINSTALL := TGT_INSTALLDIR := .. TGT_CHECK_HEADERS := TGT_CHECK_LIBS := TEST := SOURCES := SRC_CFLAGS := SRC_CXXFLAGS := SRC_DEFS := SRC_INCDIRS := MAN := FILES := OUTPUT := SUBMAKEFILES := # A directory stack is maintained so that the correct paths are used as we # recursively include all submakefiles. Get the makefile's directory and # push it onto the stack. DIR := $(call CANONICAL_PATH,$(dir ${1})) DIR_STACK := $$(call PUSH,$${DIR_STACK},$${DIR}) include ${1} # Initialize internal local variables. OBJS := # Determine which target this makefile's variables apply to. A stack is # used to keep track of which target is the "current" target as we # recursively include other submakefiles. ifneq "$$(strip $${TARGET})" "" # This makefile defined a new target. Target variables defined by this # makefile apply to this new target. Initialize the target's variables. # libs go into ${BUILD_DIR}/lib # everything else goes into ${BUILD_DIR}/bin # TGT := $$(strip $$(if $$(suffix $${TARGET}),$${BUILD_DIR}/lib,$${BUILD_DIR}/bin)/$${TARGET}) TGT := $${TARGET} # A "hook" to rewrite "libfoo.a" -> "libfoo.la" when using libtool $$(eval $$(call ADD_LIBTOOL_SUFFIX)) ALL_TGTS += $${TGT} $${TGT}_LDFLAGS := $${TGT_LDFLAGS} $${TGT}_LDLIBS := $${TGT_LDLIBS} $${TGT}_LINKER := $${TGT_LINKER} $${TGT}_POSTMAKE := $${TGT_POSTMAKE} $${TGT}_POSTCLEAN := $${TGT_POSTCLEAN} $${TGT}_POSTINSTALL := $${TGT_POSTINSTALL} $${TGT}_PREREQS := $${TGT_PREREQS} $${TGT}_PRBIN := $$(addprefix $${BUILD_DIR}/bin/,$$(filter-out %.a %.so %.la,$${TGT_PREREQS})) $${TGT}_PRLIBS := $$(addprefix $${BUILD_DIR}/lib/,$$(filter %.a %.so %.la,$${TGT_PREREQS})) $${TGT}_DEPS := $${TGT}_OBJS := $${TGT}_SOURCES := $${TGT}_MAN := $${MAN} $${TGT}_SUFFIX := $$(if $$(suffix $${TGT}),$$(suffix $${TGT}),.exe) # If it's an EXE, ensure that transitive library linking works. # i.e. we build libfoo.a which in turn requires -lbar. So, the executable # has to be linked to both libfoo.a and -lbar. ifeq "$${$${TGT}_SUFFIX}" ".exe" $${TGT}_LDLIBS += $$(filter-out %.a %.so %.la,$${$${TGT_PREREQS}_LDLIBS}) endif $${TGT}_BUILD := $$(if $$(suffix $${TGT}),$${BUILD_DIR}/lib,$${BUILD_DIR}/bin) $${TGT}_MAKEFILES += ${1} $${TGT}_CHECK_HEADERS := $${TGT_CHECK_HEADERS} $${TGT}_CHECK_LIBS := $${TGT_CHECK_LIBS} else # The values defined by this makefile apply to the the "current" target # as determined by which target is at the top of the stack. TGT := $$(strip $$(call PEEK,$${TGT_STACK})) $${TGT}_LDFLAGS += $${TGT_LDFLAGS} $${TGT}_LDLIBS += $${TGT_LDLIBS} $${TGT}_POSTCLEAN += $${TGT_POSTCLEAN} $${TGT}_POSTMAKE += $${TGT_POSTMAKE} $${TGT}_PREREQS += $${TGT_PREREQS} endif # Push the current target onto the target stack. TGT_STACK := $$(call PUSH,$${TGT_STACK},$${TGT}) # If there's no target, don't build the sources. ifneq "$$(strip $${TARGET})" "" # if there's no sources, don't do the automatic object build ifneq "$$(strip $${SOURCES})" "" # This makefile builds one or more objects from source. Validate the # specified sources against the supported source file types. BAD_SRCS := $$(strip $$(filter-out $${ALL_SRC_EXTS},$${SOURCES})) ifneq "$${BAD_SRCS}" "" $$(error Unsupported source file(s) found in ${1} [$${BAD_SRCS}]) endif # Qualify and canonicalize paths. SOURCES := $$(call QUALIFY_PATH,$${DIR},$${SOURCES}) SOURCES := $$(call CANONICAL_PATH,$${SOURCES}) SRC_INCDIRS := $$(call QUALIFY_PATH,$${DIR},$${SRC_INCDIRS}) SRC_INCDIRS := $$(call CANONICAL_PATH,$${SRC_INCDIRS}) # Save the list of source files for this target. $${TGT}_SOURCES += $${SOURCES} # Convert the source file names to their corresponding object file # names. OBJS := $$(addprefix $${BUILD_DIR}/objs/,\ $$(addsuffix .${OBJ_EXT},$$(basename $${SOURCES}))) PLISTS := $$(addprefix $${BUILD_DIR}/plist/,\ $$(addsuffix .plist,$$(basename $${SOURCES}))) ALL_PLISTS += ${PLISTS} # Add the objects to the current target's list of objects, and create # target-specific variables for the objects based on any source # variables that were defined. $${TGT}_OBJS += $${OBJS} $${TGT}_PLISTS += $${PLISTS} $${TGT}_DEPS += $$(addprefix $${BUILD_DIR}/make/src/,\ $$(addsuffix .mk,$$(basename $${SOURCES}))) # A "hook" to define variables needed by the "legacy" makefiles. $$(eval $$(call ADD_LEGACY_VARIABLES,$$(dir ${1}),$${TGT})) $${OBJS}: SRC_CFLAGS := $${SRC_CFLAGS} $${OBJS}: SRC_CXXFLAGS := $${SRC_CXXFLAGS} $${OBJS}: SRC_DEFS := $$(addprefix -D,$${SRC_DEFS}) $${OBJS}: SRC_INCDIRS := $${SRC_INCDIRS} $${OBJS}: ${1} $${PLISTS}: SRC_CFLAGS := $${SRC_CFLAGS} $${PLISTS}: SRC_CXXFLAGS := $${SRC_CXXFLAGS} $${PLISTS}: SRC_DEFS := $$(addprefix -D,$${SRC_DEFS}) $${PLISTS}: SRC_INCDIRS := $${SRC_INCDIRS} $${PLISTS}: ${1} endif endif ifneq "$$(strip $${SUBMAKEFILES})" "" # This makefile has submakefiles. Recursively include them. $$(foreach MK,$${SUBMAKEFILES},\ $$(eval $$(call INCLUDE_SUBMAKEFILE,\ $$(call CANONICAL_PATH,\ $$(call QUALIFY_PATH,$${DIR},$${MK}))))) endif # Reset the "current" target to it's previous value. TGT_STACK := $$(call POP,$${TGT_STACK}) # If we're about to change targets, create the rules for the target ifneq "$${TGT}" "$$(call PEEK,$${TGT_STACK})" # add rules to build the target, and have "all" depend on it. $$(eval $$(call ADD_TARGET_TO_ALL,$${TGT})) # A "hook" to add rules for ${TARGET_DIR}/foo, if TARGET_DIR # is defined. Otherwise, we leave the source directory untouched. $$(eval $$(call ADD_TARGET_DIR,$${TGT})) # A "hook" to build the libtool target. $$(eval $$(call ADD_LIBTOOL_TARGET)) # Choose the correct linker. ifeq "$$(strip $$(filter $${CXX_SRC_EXTS},$${$${TGT}_SOURCES}))" "" ifeq "$${$${TGT}_LINKER}" "" $${TGT}_LINKER := ${LL}$${LINK.c} endif else ifeq "$${$${TGT}_LINKER}" "" $${TGT}_LINKER := ${LL}$${LINK.cxx} endif endif # add rules to build the target $$(eval $$(call ADD_TARGET_RULE$${$${TGT}_SUFFIX},$${TGT})) # generate the clean rule for this target. $$(eval $$(call ADD_CLEAN_RULE,$${TGT})) # Hook to add an installation target $$(eval $$(call ADD_INSTALL_TARGET,$${TGT})) # Hook to add a configuration target $$(eval $$(call ADD_TARGET_CONFIG,$${TGT})) # "hook" for legacy Makefiles $$(eval $$(call ADD_LEGACY_RULE,$${TGT})) endif TGT := $$(call PEEK,$${TGT_STACK}) # Reset the "current" directory to it's previous value. DIR_STACK := $$(call POP,$${DIR_STACK}) DIR := $$(call PEEK,$${DIR_STACK}) endef # MIN - Parameterized "function" that results in the minimum lexical value of # the two values given. define MIN $(firstword $(sort ${1} ${2})) endef # PEEK - Parameterized "function" that results in the value at the top of the # specified colon-delimited stack. define PEEK $(lastword $(subst :, ,${1})) endef # POP - Parameterized "function" that pops the top value off of the specified # colon-delimited stack, and results in the new value of the stack. Note that # the popped value cannot be obtained using this function; use peek for that. define POP ${1:%:$(lastword $(subst :, ,${1}))=%} endef # PUSH - Parameterized "function" that pushes a value onto the specified colon- # delimited stack, and results in the new value of the stack. define PUSH ${2:%=${1}:%} endef # QUALIFY_PATH - Given a "root" directory and one or more paths, qualifies the # paths using the "root" directory (i.e. appends the root directory name to # the paths) except for paths that are absolute. define QUALIFY_PATH $(addprefix ${1}/,$(filter-out /%,${2})) $(filter /%,${2}) endef ############################################################################### # # Start of Makefile Evaluation # ############################################################################### # Older versions of GNU Make lack capabilities needed by boilermake. # With older versions, "make" may simply output "nothing to do", likely leading # to confusion. To avoid this, check the version of GNU make up-front and # inform the user if their version of make doesn't meet the minimum required. MIN_MAKE_VERSION := 3.81 MIN_MAKE_VER_MSG := boilermake requires GNU Make ${MIN_MAKE_VERSION} or greater ifeq "${MAKE_VERSION}" "" $(info GNU Make not detected) $(error ${MIN_MAKE_VER_MSG}) endif ifneq "${MIN_MAKE_VERSION}" "$(call MIN,${MIN_MAKE_VERSION},${MAKE_VERSION})" $(info This is GNU Make version ${MAKE_VERSION}) $(error ${MIN_MAKE_VER_MSG}) endif # Define the source file extensions that we know how to handle. OBJ_EXT := o C_SRC_EXTS := %.c CXX_SRC_EXTS := %.C %.cc %.cp %.cpp %.CPP %.cxx %.c++ ALL_SRC_EXTS := ${C_SRC_EXTS} ${CXX_SRC_EXTS} # Initialize global variables. ALL_TGTS := DEFS := DIR_STACK := INCDIRS := TGT_STACK := ifeq "${top_builddir}" "" top_builddir := . endif # Ensure that valid values are set for BUILD_DIR ifeq "$(strip ${BUILD_DIR})" "" ifeq "${top_builddir}" "${PWD}" BUILD_DIR := build else BUILD_DIR := ${top_builddir}/build endif else BUILD_DIR := $(call CANONICAL_PATH,${BUILD_DIR}) endif .PHONY: $(BUILD_DIR) $(BUILD_DIR): @mkdir -p $@ # Define compilers and linkers # BOOTSTRAP_BUILD = COMPILE.c = ${CC} COMPILE.cxx = ${CXX} CPP = cc -E LINK.c = ${CC} LINK.cxx = ${CXX} # Set ECHO to "true" for *very* quiet builds ECHO = echo # Define the "all" target (which simply builds all user-defined targets) as the # default goal. .PHONY: all all: # Add "clean" rules to remove all build-generated files. .PHONY: clean clean: top_makedir := $(dir $(lastword ${MAKEFILE_LIST})) -include ${top_makedir}/install.mk -include ${top_makedir}/libtool.mk ifneq "${CPPCHECK}" "" CHECKFLAGS := -DCPPCHECK $(filter -isystem%,$(CPPFLAGS) $(CFLAGS)) $(filter -I%,$(CPPFLAGS) $(CFLAGS)) $(filter -D%,$(CPPFLAGS) $(CFLAGS)) endif # Include the main user-supplied submakefile. This also recursively includes # all other user-supplied submakefiles. $(eval $(call INCLUDE_SUBMAKEFILE,${top_builddir}/main.mk)) # Perform post-processing on global variables as needed. DEFS := $(addprefix -D,${DEFS}) INCDIRS := $(addprefix -I,$(call CANONICAL_PATH,${INCDIRS})) # Add pattern rule(s) for creating compiled object code from C source. $(foreach EXT,${C_SRC_EXTS},\ $(eval $(call ADD_OBJECT_RULE,${EXT},$${COMPILE_C_CMDS}))) ifneq "${ANALYZE.c}" "" $(foreach EXT,${C_SRC_EXTS},\ $(eval $(call ADD_ANALYZE_RULE,${EXT},$${ANALYZE_C_CMDS}))) endif # Add pattern rule(s) for creating compiled object code from C++ source. $(foreach EXT,${CXX_SRC_EXTS},\ $(eval $(call ADD_OBJECT_RULE,${EXT},$${COMPILE_CXX_CMDS}))) # Don't include the target dependencies if we're doing a "make clean" # Future: have a list of targets that don't require dependency generation, # and see if MAKECMDGOALS is one of them. ifneq "$(MAKECMDGOALS)" "clean" $(foreach TGT,${ALL_TGTS},\ $(eval -include ${${TGT}_DEPS})) endif # Build rules for installation subdirectories $(foreach D,$(patsubst %/,%,$(sort $(dir ${ALL_INSTALL}))),\ $(eval $(call ADD_INSTALL_RULE.dir,${D}))) scan: ${ALL_PLISTS} .PHONY: clean.scan clean.scan: $(Q)rm -rf ${ALL_PLISTS} clean: clean.scan