aboutsummaryrefslogtreecommitdiff
path: root/share/mk
diff options
context:
space:
mode:
Diffstat (limited to 'share/mk')
-rw-r--r--share/mk/Makefile.depend14
-rw-r--r--share/mk/auto.obj.mk57
-rw-r--r--share/mk/bsd.dep.mk11
-rw-r--r--share/mk/bsd.files.mk22
-rw-r--r--share/mk/bsd.incs.mk26
-rw-r--r--share/mk/bsd.init.mk9
-rw-r--r--share/mk/bsd.lib.mk28
-rw-r--r--share/mk/bsd.nls.mk11
-rw-r--r--share/mk/bsd.obj.mk9
-rw-r--r--share/mk/bsd.own.mk18
-rw-r--r--share/mk/bsd.prog.mk47
-rw-r--r--share/mk/bsd.subdir.mk11
-rw-r--r--share/mk/dirdeps.mk414
-rw-r--r--share/mk/gendirdeps.mk301
-rw-r--r--share/mk/host-target.mk31
-rw-r--r--share/mk/install-new.mk53
-rw-r--r--share/mk/local.autodep.mk24
-rw-r--r--share/mk/local.dirdeps.mk15
-rw-r--r--share/mk/local.gendirdeps.mk10
-rw-r--r--share/mk/local.init.mk18
-rw-r--r--share/mk/local.sys.mk214
-rw-r--r--share/mk/meta.autodep.mk261
-rw-r--r--share/mk/meta.stage.mk213
-rw-r--r--share/mk/meta.subdir.mk79
-rw-r--r--share/mk/meta.sys.mk139
-rwxr-xr-xshare/mk/meta2deps.py614
-rwxr-xr-xshare/mk/meta2deps.sh306
-rw-r--r--share/mk/sys.dependfile.mk47
28 files changed, 2998 insertions, 4 deletions
diff --git a/share/mk/Makefile.depend b/share/mk/Makefile.depend
new file mode 100644
index 000000000000..29fda55c252f
--- /dev/null
+++ b/share/mk/Makefile.depend
@@ -0,0 +1,14 @@
+# Autogenerated - do NOT edit!
+
+DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
+
+DEP_MACHINE := ${.PARSEFILE:E}
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/share/mk/auto.obj.mk b/share/mk/auto.obj.mk
new file mode 100644
index 000000000000..cd4b2b0fb0db
--- /dev/null
+++ b/share/mk/auto.obj.mk
@@ -0,0 +1,57 @@
+# $Id: auto.obj.mk,v 1.8 2011/08/08 17:35:20 sjg Exp $
+#
+# @(#) Copyright (c) 2004, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+ECHO_TRACE ?= echo
+
+.ifndef Mkdirs
+# A race condition in some versions of mkdir, means that it can bail
+# if another process made a dir that mkdir expected to.
+# We repeat the mkdir -p a number of times to try and work around this.
+# We stop looping as soon as the dir exists.
+# If we get to the end of the loop, a plain mkdir will issue an error.
+Mkdirs= Mkdirs() { \
+ for d in $$*; do \
+ for i in 1 2 3 4 5 6; do \
+ mkdir -p $$d; \
+ test -d $$d && return 0; \
+ done > /dev/null 2>&1; \
+ mkdir $$d || exit $$?; \
+ done; }
+.endif
+
+# if MKOBJDIRS is set to auto (and NOOBJ isn't defined) do some magic...
+# This will automatically create objdirs as needed.
+# Skip it if we are just doing 'clean'.
+.if !defined(NOOBJ) && !defined(NO_OBJ) && ${MKOBJDIRS:Uno} == auto
+# Use __objdir here so it is easier to tweak without impacting
+# the logic.
+__objdir?= ${MAKEOBJDIR}
+__objdir:= ${__objdir:tA}
+.if ${.OBJDIR} != ${__objdir}
+# We need to chdir, make the directory if needed
+.if !exists(${__objdir}/) && \
+ (${.TARGETS} == "" || ${.TARGETS:Nclean*:N*clean:Ndestroy*} != "")
+# This will actually make it...
+__objdir_made != echo ${__objdir}/; umask ${OBJDIR_UMASK:U002}; \
+ ${ECHO_TRACE} "[Creating objdir ${__objdir}...]" >&2; \
+ ${Mkdirs}; Mkdirs ${__objdir}
+.endif
+# This causes make to use the specified directory as .OBJDIR
+.OBJDIR: ${__objdir}
+.if ${.OBJDIR} != ${__objdir} && ${__objdir_made:Uno:M${__objdir}/*} != ""
+.error could not use ${__objdir}
+.endif
+.endif
+.endif
diff --git a/share/mk/bsd.dep.mk b/share/mk/bsd.dep.mk
index deac736c2d37..64e0d3ca529c 100644
--- a/share/mk/bsd.dep.mk
+++ b/share/mk/bsd.dep.mk
@@ -119,6 +119,17 @@ ${_YC:R}.o: ${_YC}
.endfor
.endif
+.if defined(.PARSEDIR)
+.if ${MK_META_MODE} == "yes"
+.include <meta.autodep.mk>
+# this depend: bypasses that below
+# the dependency helps when bootstrapping
+depend: beforedepend ${DPSRCS} ${SRCS} afterdepend
+beforedepend:
+afterdepend: beforedepend
+.endif
+.endif
+
.if !target(depend)
.if defined(SRCS)
depend: beforedepend ${DEPENDFILE} afterdepend
diff --git a/share/mk/bsd.files.mk b/share/mk/bsd.files.mk
index 240f958f1a9b..79b9d0346cb4 100644
--- a/share/mk/bsd.files.mk
+++ b/share/mk/bsd.files.mk
@@ -22,6 +22,11 @@ ${group}OWN?= ${SHAREOWN}
${group}GRP?= ${SHAREGRP}
${group}MODE?= ${SHAREMODE}
${group}DIR?= ${BINDIR}
+.if !make(buildincludes)
+STAGE_SETS+= ${group}
+.endif
+STAGE_DIR.${group}= ${STAGE_OBJTOP}${${group}DIR}
+STAGE_SYMLINKS_DIR.${group}= ${STAGE_OBJTOP}
_${group}FILES=
.for file in ${${group}}
@@ -37,6 +42,12 @@ ${group}NAME_${file:T}?= ${${group}NAME}
.else
${group}NAME_${file:T}?= ${file:T}
.endif
+.if !make(buildincludes)
+STAGE_AS_SETS+= ${group}
+.endif
+STAGE_AS_${file:T}= ${${group}NAME_${file:T}}
+stage_as.${group}: ${file}
+
installfiles: _${group}INS_${file:T}
_${group}INS_${file:T}: ${file}
${INSTALL} -o ${${group}OWN_${.ALLSRC:T}} \
@@ -48,6 +59,8 @@ _${group}FILES+= ${file}
.endif
.endfor
.if !empty(_${group}FILES)
+stage_files.${group}: ${_${group}FILES}
+
installfiles: _${group}INS
_${group}INS: ${_${group}FILES}
.if defined(${group}NAME)
@@ -67,3 +80,12 @@ _${group}INS: ${_${group}FILES}
realinstall: installfiles
.ORDER: beforeinstall installfiles
+
+.if ${MK_STAGING} != "no"
+.if !empty(STAGE_SETS)
+buildfiles: stage_files
+.if !empty(STAGE_AS_SETS)
+buildfiles: stage_as
+.endif
+.endif
+.endif
diff --git a/share/mk/bsd.incs.mk b/share/mk/bsd.incs.mk
index 74c378b62da8..2546dfdd8df8 100644
--- a/share/mk/bsd.incs.mk
+++ b/share/mk/bsd.incs.mk
@@ -24,12 +24,15 @@ ${group}OWN?= ${BINOWN}
${group}GRP?= ${BINGRP}
${group}MODE?= ${NOBINMODE}
${group}DIR?= ${INCLUDEDIR}
+STAGE_SETS+= ${group}
+STAGE_DIR.${group}= ${STAGE_OBJTOP}${${group}DIR}
+STAGE_SYMLINKS_DIR.${group}= ${STAGE_OBJTOP}
_${group}INCS=
.for header in ${${group}}
.if defined(${group}OWN_${header:T}) || defined(${group}GRP_${header:T}) || \
defined(${group}MODE_${header:T}) || defined(${group}DIR_${header:T}) || \
- defined(${group}NAME_${header:T})
+ defined(${group}NAME_${header:T}) || defined(${group}NAME)
${group}OWN_${header:T}?= ${${group}OWN}
${group}GRP_${header:T}?= ${${group}GRP}
${group}MODE_${header:T}?= ${${group}MODE}
@@ -39,6 +42,10 @@ ${group}NAME_${header:T}?= ${${group}NAME}
.else
${group}NAME_${header:T}?= ${header:T}
.endif
+STAGE_AS_SETS+= ${group}
+STAGE_AS_${header:T}= ${${group}NAME_${header:T}}
+stage_as.${group}: ${header}
+
installincludes: _${group}INS_${header:T}
_${group}INS_${header:T}: ${header}
${INSTALL} -C -o ${${group}OWN_${.ALLSRC:T}} \
@@ -50,6 +57,8 @@ _${group}INCS+= ${header}
.endif
.endfor
.if !empty(_${group}INCS)
+stage_files.${group}: ${_${group}INCS}
+
installincludes: _${group}INS
_${group}INS: ${_${group}INCS}
.if defined(${group}NAME)
@@ -81,4 +90,19 @@ installincludes:
realinstall: installincludes
.ORDER: beforeinstall installincludes
+.if ${MK_STAGING} != "no" && !defined(_SKIP_BUILD)
+.if !target(stage_includes)
+.if !empty(STAGE_SETS)
+buildincludes: stage_files
+.if !empty(STAGE_AS_SETS)
+buildincludes: stage_as
+.endif
+.if !empty(INCSLINKS)
+stage_files: stage_symlinks
+STAGE_SYMLINKS.INCS= ${INCSLINKS:S,${INCSDIR}/,,}
+.endif
+.endif
+.endif
+.endif
+
.endif # !defined(NO_INCS) && ${MK_TOOLCHAIN} != "no"
diff --git a/share/mk/bsd.init.mk b/share/mk/bsd.init.mk
index f5f4c66cfffc..ec325c04ac58 100644
--- a/share/mk/bsd.init.mk
+++ b/share/mk/bsd.init.mk
@@ -6,9 +6,18 @@
.if !target(__<bsd.init.mk>__)
__<bsd.init.mk>__:
+.sinclude "local.init.mk"
.if exists(${.CURDIR}/../Makefile.inc)
.include "${.CURDIR}/../Makefile.inc"
.endif
.include <bsd.own.mk>
.MAIN: all
+
+.if defined(.PARSEDIR)
+.if ${.MAKE.LEVEL:U1} == 0 && ${BUILD_AT_LEVEL0:Uyes:tl} == "no" && !make(clean*)
+# this tells lib.mk and prog.mk to not actually build anything
+_SKIP_BUILD = not building at level 0
+.endif
+.endif
+
.endif # !target(__<bsd.init.mk>__)
diff --git a/share/mk/bsd.lib.mk b/share/mk/bsd.lib.mk
index f406c231ade5..0f1de8854f3c 100644
--- a/share/mk/bsd.lib.mk
+++ b/share/mk/bsd.lib.mk
@@ -111,7 +111,14 @@ PO_FLAG=-pg
${CC} ${PICFLAG} -DPIC ${CFLAGS} ${ACFLAGS} -c ${.IMPSRC} -o ${.TARGET}
${CTFCONVERT_CMD}
-all: objwarn
+.if !defined(_SKIP_BUILD)
+all: prebuild .WAIT
+prebuild: objwarn
+.if !defined(.PARSEDIR)
+# this is a no-op
+.WAIT:
+.endif
+.endif
.include <bsd.symver.mk>
@@ -232,11 +239,15 @@ ${LINTLIB}: ${LINTOBJS}
.endif # !defined(INTERNALLIB)
+.if defined(_SKIP_BUILD)
+all:
+.else
all: ${_LIBS}
.if ${MK_MAN} != "no"
all: _manpages
.endif
+.endif
_EXTRADEPEND:
@TMP=_depend$$$$; \
@@ -418,3 +429,18 @@ clean:
.include <bsd.obj.mk>
.include <bsd.sys.mk>
+
+.if ${MK_STAGING} != "no"
+.if defined(_SKIP_BUILD)
+stage_libs stage_files stage_as:
+.else
+.if !empty(_LIBS) && !defined(INTERNALLIB)
+stage_libs: ${_LIBS}
+all: stage_libs
+.endif
+.if !empty(INCS) || !empty(INCSGROUPS)
+prebuild: buildincludes
+.endif
+.include <meta.stage.mk>
+.endif
+.endif
diff --git a/share/mk/bsd.nls.mk b/share/mk/bsd.nls.mk
index 48093ebf0838..3d2efc120e29 100644
--- a/share/mk/bsd.nls.mk
+++ b/share/mk/bsd.nls.mk
@@ -61,13 +61,22 @@ NLSDIR?= ${SHAREDIR}/nls
#
# installation rules
#
+.if ${MK_STAGING_PROG} == "yes"
+.if !defined(_SKIP_BUILD)
+all: stage_symlinks
+.endif
+STAGE_SYMLINKS.NLS= ${NLSSYMLINKS}
+STAGE_SYMLINKS_DIR.NLS= ${STAGE_OBJTOP}
+.else
+SYMLINKS+= ${NLSSYMLINKS}
+.endif
.for file in ${NLS}
NLSNAME_${file:T}= ${file:T:R}/${NLSNAME}.cat
.if defined(NLSLINKS_${file:R}) && !empty(NLSLINKS_${file:R})
NLSLINKS+= ${file:R}
.endif
.for dst in ${NLSLINKS_${file:R}}
-SYMLINKS+= ../${file:R}/${NLSNAME}.cat ${NLSDIR}/${dst}/${NLSNAME}.cat
+NLSSYMLINKS+= ../${file:R}/${NLSNAME}.cat ${NLSDIR}/${dst}/${NLSNAME}.cat
.endfor
.endfor
diff --git a/share/mk/bsd.obj.mk b/share/mk/bsd.obj.mk
index 634261eba594..38afcde9a35f 100644
--- a/share/mk/bsd.obj.mk
+++ b/share/mk/bsd.obj.mk
@@ -50,6 +50,15 @@ CANONICALOBJDIR:=${MAKEOBJDIR}
CANONICALOBJDIR:=/usr/obj${.CURDIR}
.endif
+.if defined(.PARSEDIR) && !defined(NO_OBJ) && !defined(NO_AUTO_OBJ)
+.if ${MK_AUTO_OBJ} == "yes"
+__objdir?= ${CANONICALOBJDIR}
+# this is what auto.obj.mk wants to see
+MKOBJDIRS=auto
+.include "auto.obj.mk"
+.endif
+.endif
+
#
# Warn of unorthodox object directory.
#
diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk
index d500586cccf0..8b3b5196afc3 100644
--- a/share/mk/bsd.own.mk
+++ b/share/mk/bsd.own.mk
@@ -354,6 +354,9 @@ __DEFAULT_YES_OPTIONS = \
__DEFAULT_NO_OPTIONS = \
ARM_EABI \
+ AUTO_OBJ \
+ BMAKE \
+ BSD_GREP \
BSD_PATCH \
BIND_IDN \
BIND_LARGE_FILE \
@@ -370,11 +373,14 @@ __DEFAULT_NO_OPTIONS = \
ICONV \
IDEA \
INSTALL_AS_USER \
+ META_MODE \
NMTREE \
NAND \
OFED \
OPENSSH_NONE_CIPHER \
- SHARED_TOOLCHAIN
+ SHARED_TOOLCHAIN \
+ STAGING \
+ STAGING_PROG
#
# Default behaviour of some options depends on the architecture. Unfortunately
@@ -532,6 +538,16 @@ MK_CLANG_FULL:= no
MK_CLANG_IS_CC:= no
.endif
+.if !defined(.PARSEDIR)
+MK_AUTO_OBJ:= no
+MK_META_MODE:= no
+.endif
+
+.if ${MK_META_MODE} == "no"
+MK_STAGING:= no
+MK_STAGING_PROG:= no
+.endif
+
#
# Set defaults for the MK_*_SUPPORT variables.
#
diff --git a/share/mk/bsd.prog.mk b/share/mk/bsd.prog.mk
index 801f80458056..3340394de119 100644
--- a/share/mk/bsd.prog.mk
+++ b/share/mk/bsd.prog.mk
@@ -101,10 +101,14 @@ MAN1= ${MAN}
.endif
.endif # defined(PROG)
+.if defined(_SKIP_BUILD)
+all:
+.else
all: objwarn ${PROG} ${SCRIPTS}
.if ${MK_MAN} != "no"
all: _manpages
.endif
+.endif
.if defined(PROG)
CLEANFILES+= ${PROG}
@@ -172,6 +176,10 @@ SCRIPTSOWN?= ${BINOWN}
SCRIPTSGRP?= ${BINGRP}
SCRIPTSMODE?= ${BINMODE}
+STAGE_AS_SETS+= scripts
+stage_as.scripts: ${SCRIPTS}
+FLAGS.stage_as.scripts= -m ${SCRIPTSMODE}
+STAGE_FILES_DIR.scripts= ${STAGE_OBJTOP}
.for script in ${SCRIPTS}
.if defined(SCRIPTSNAME)
SCRIPTSNAME_${script:T}?= ${SCRIPTSNAME}
@@ -182,6 +190,7 @@ SCRIPTSDIR_${script:T}?= ${SCRIPTSDIR}
SCRIPTSOWN_${script:T}?= ${SCRIPTSOWN}
SCRIPTSGRP_${script:T}?= ${SCRIPTSGRP}
SCRIPTSMODE_${script:T}?= ${SCRIPTSMODE}
+STAGE_AS_${script:T}= ${SCRIPTSDIR_${script:T}}/${SCRIPTSNAME_${script:T}}
_scriptsinstall: _SCRIPTSINS_${script:T}
_SCRIPTSINS_${script:T}: ${script}
${INSTALL} -o ${SCRIPTSOWN_${.ALLSRC:T}} \
@@ -229,3 +238,41 @@ ${OBJS}: ${SRCS:M*.h}
.if defined(PORTNAME)
.include <bsd.pkg.mk>
.endif
+
+.if ${MK_STAGING} != "no"
+.if defined(_SKIP_BUILD)
+stage_files stage_as:
+.else
+# normally only libs and includes are staged
+.if ${MK_STAGING_PROG:Uno} != "no"
+STAGE_DIR.prog= ${STAGE_OBJTOP}${BINDIR}
+
+.if defined(PROGNAME)
+STAGE_AS_SETS+= prog
+STAGE_AS_${PROG}= ${PROGNAME}
+stage_as.prog: ${PROG}
+.else
+STAGE_SETS+= prog
+stage_files.prog: ${PROG}
+.endif
+
+.if !empty(LINKS)
+all: stage_links
+STAGE_LINKS.prog= ${LINKS}
+.endif
+.if !empty(SYMLINKS)
+all: stage_symlinks
+STAGE_SYMLINKS.prog= ${SYMLINKS}
+.endif
+
+.if !empty(STAGE_AS_SETS)
+all: stage_as
+.endif
+.if !empty(STAGE_SETS)
+all: stage_files
+.endif
+
+.endif
+.include <meta.stage.mk>
+.endif
+.endif
diff --git a/share/mk/bsd.subdir.mk b/share/mk/bsd.subdir.mk
index 3d5fb61577da..0738ae8e9a83 100644
--- a/share/mk/bsd.subdir.mk
+++ b/share/mk/bsd.subdir.mk
@@ -34,6 +34,15 @@ __<bsd.subdir.mk>__:
.include <bsd.init.mk>
+.if defined(.PARSEDIR) && !defined(NEED_SUBDIR)
+.if ${.MAKE.LEVEL} == 0 && ${.MAKE.MODE:Mmeta*} != "" && !empty(SUBDIR) && !(make(clean*) || make(destroy*))
+.include <meta.subdir.mk>
+# ignore this
+_SUBDIR:
+.endif
+.endif
+.if !target(_SUBDIR)
+
DISTRIBUTION?= base
.if !target(distribute)
distribute:
@@ -85,6 +94,8 @@ ${__target}:
${_+_}set -e; cd ${.CURDIR}; ${MAKE} build${__target}; ${MAKE} install${__target}
.endfor
+.endif
+
.if !target(install)
.if !target(beforeinstall)
beforeinstall:
diff --git a/share/mk/dirdeps.mk b/share/mk/dirdeps.mk
new file mode 100644
index 000000000000..9f051e9203e7
--- /dev/null
+++ b/share/mk/dirdeps.mk
@@ -0,0 +1,414 @@
+# $Id: dirdeps.mk,v 1.23 2012/11/06 05:44:03 sjg Exp $
+
+# Copyright (c) 2010-2012, Juniper Networks, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Much of the complexity here is for supporting cross-building.
+# If a tree does not support that, simply using plain Makefile.depend
+# should provide sufficient clue.
+# Otherwise the recommendation is to use Makefile.depend.${MACHINE}
+# as expected below.
+
+# Note: this file gets multiply included.
+# This is what we do with DIRDEPS
+
+# DIRDEPS:
+# This is a list of directories - relative to SRCTOP, it is only
+# of interest to .MAKE.LEVEL 0.
+# In some cases the entry may be qualified with a .<machine>
+# suffix, for example to force building something for the pseudo
+# machines "host" or "common" regardless of current ${MACHINE}.
+# All unqualified entries end up being qualified with .${MACHINE}
+# and _DIRDEPS_USE below, uses the suffix to set MACHINE
+# correctly when visiting each entry.
+#
+# Each entry is also converted into a set of paths to look for
+# Makefile.depend.<machine> to learn the dependencies of each.
+# Each Makefile.depend.<machine> sets DEP_RELDIR to be the
+# the RELDIR (path relative to SRCTOP) for its directory, and
+# DEP_MACHINE to its suffix (<machine>), further since
+# each Makefile.depend.<machine> includes dirdeps.mk, this
+# processing is recursive and results in .MAKE.LEVEL 0 learning the
+# dependencies of the tree wrt the initial directory (_DEP_RELDIR).
+#
+# BUILD_AT_LEVEL0
+# Indicates whether .MAKE.LEVEL 0 builds anything:
+# if "no" sub-makes are used to build everything,
+# if "yes" sub-makes are only used to build for other machines.
+#
+# TARGET_SPEC_VARS
+# All the description above (and below) assumes <machine> is the
+# only data needed to control the build.
+# This is not always the case. So in addition to setting
+# MACHINE in the build environment we set TARGET_SPEC which is
+# composed of the values of TARGET_SPEC_VARS separated by
+# commas. The default is just MACHINE.
+#
+# If more that MACHINE is needed then sys.mk needs to decompose
+# TARGET_SPEC and set the relevant variables accordingly.
+# It is important that MACHINE be included in TARGET_SPEC_VARS
+# since if there is more the value passed as MACHINE will infact
+# be the TARGET_SPEC.
+# Note: TARGET_SPEC cannot contain any '.'s so the target
+# tripple used by compiler folk won't work (directly anyway).
+#
+# For example:
+#
+# # variables other than MACHINE might be optional
+# TARGET_SPEC_VARS = MACHINE TARGET_OS
+# .if ${TARGET_SPEC:Uno:M*,*} != ""
+# _tspec := ${TARGET_SPEC:S/,/ /g}
+# MACHINE := ${_tspec:[1]}
+# TARGET_OS := ${_tspec:[2]}
+# # etc.
+# .for v in ${TARGET_SPEC_VARS:O:u}
+# .if empty($v)
+# .undef $v
+# .endif
+# .endfor
+# .endif
+#
+
+.if ${.MAKE.LEVEL} == 0
+# only the first instance is interested in all this
+
+# First off, we want to know what ${MACHINE} to build for.
+# This can be complicated if we are using a mixture of ${MACHINE} specific
+# and non-specific Makefile.depend*
+
+.if !target(_DIRDEP_USE)
+# do some setup we only need once
+_CURDIR ?= ${.CURDIR}
+
+# If TARGET_SPEC_VARS is other than just MACHINE
+# it should be set by sys.mk or similar by now.
+# TARGET_SPEC must not contain any '.'s.
+TARGET_SPEC_VARS ?= MACHINE
+TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,}
+
+.if !defined(.MAKE.DEPENDFILE_PREFERENCE)
+# this makes the logic below neater?
+.MAKE.DEPENDFILE_PREFERENCE = ${_CURDIR}/${.MAKE.DEPENDFILE:T}
+.if ${.MAKE.DEPENDFILE:E} == "${TARGET_SPEC}"
+.if ${TARGET_SPEC} != ${MACHINE}
+.MAKE.DEPENDFILE_PREFERENCE += ${_CURDIR}/${.MAKE.DEPENDFILE:T:R}.$${MACHINE}
+.endif
+.MAKE.DEPENDFILE_PREFERENCE += ${_CURDIR}/${.MAKE.DEPENDFILE:T:R}
+.endif
+.endif
+
+_default_dependfile := ${.MAKE.DEPENDFILE_PREFERENCE:[1]:T}
+_machine_dependfiles := ${.MAKE.DEPENDFILE_PREFERENCE:M*.${TARGET_SPEC}} \
+ ${.MAKE.DEPENDFILE_PREFERENCE:M*.${MACHINE}}
+
+# for machine specific dependfiles we require ${MACHINE} to be at the end
+# also for the sake of sanity we require a common prefix
+.if !defined(.MAKE.DEPENDFILE_PREFIX)
+.if !empty(_machine_dependfiles)
+.MAKE.DEPENDFILE_PREFIX := ${_machine_dependfiles:[1]:T:R}
+.else
+.MAKE.DEPENDFILE_PREFIX := ${_default_dependfile:T}
+.endif
+.endif
+
+
+# this is how we identify non-machine specific dependfiles
+N_notmachine := ${.MAKE.DEPENDFILE_PREFERENCE:E:N${TARGET_SPEC}:N${MACHINE}:${M_ListToSkip}}
+
+.endif # !target(_DIRDEP_USE)
+
+_last_dependfile := ${.MAKE.MAKEFILES:M*/${.MAKE.DEPENDFILE_PREFIX}*:[-1]}
+
+# Note: if a makefile is read many times, the above
+# will not work, so we also test for DEP_MACHINE==depend below.
+.if empty(_last_dependfile)
+# we haven't included one yet
+DEP_MACHINE ?= ${TARGET_MACHINE:U${TARGET_SPEC}}
+# else it should be correctly set by ${.MAKE.DEPENDFILE}
+.elif ${_last_dependfile:E:${N_notmachine}} == "" || ${DEP_MACHINE:Uno:${N_notmachine}} == ""
+# don't rely on manually maintained files to be correct
+DEP_MACHINE := ${_DEP_MACHINE:U${TARGET_SPEC}}
+.else
+# just in case
+DEP_MACHINE ?= ${_last_dependfile:E}
+.endif
+
+# pickup customizations
+# as below you can use !target(_DIRDEP_USE) to protect things
+# which should only be done once.
+.-include "local.dirdeps.mk"
+
+# the first time we are included the _DIRDEP_USE target will not be defined
+# we can use this as a clue to do initialization and other one time things.
+.if !target(_DIRDEP_USE)
+# make sure this target exists
+dirdeps:
+
+# We normally expect to be included by Makefile.depend.*
+# which sets the DEP_* macros below.
+DEP_RELDIR ?= ${RELDIR}
+
+# this can cause lots of output!
+# set to a set of glob expressions that might match RELDIR
+DEBUG_DIRDEPS ?= no
+
+# remember the initial value of DEP_RELDIR - we test for it below.
+_DEP_RELDIR := ${DEP_RELDIR}
+
+# things we skip for host tools
+SKIP_HOSTDIR ?=
+
+NSkipHostDir = ${SKIP_HOSTDIR:N*.host:S,$,.host,:N.host:${M_ListToSkip}}
+NSkipHostDep = ${SKIP_HOSTDIR:R:@d@*/$d*.host@:${M_ListToSkip}}
+
+# things we always skip
+# SKIP_DIRDEPS allows for adding entries on command line.
+SKIP_DIR += .host *.WAIT ${SKIP_DIRDEPS}
+
+.ifdef HOSTPROG
+SKIP_DIR += ${SKIP_HOSTDIR}
+.endif
+
+NSkipDir = ${SKIP_DIR:${M_ListToSkip}}
+
+.if defined(NO_DIRDEPS) || defined(NODIRDEPS)
+# confine ourselves to the original dir
+DIRDEPS_FILTER += M${_DEP_RELDIR}*
+.endif
+
+# we supress SUBDIR when visiting the leaves
+# we assume sys.mk will set MACHINE_ARCH
+_DIRDEP_USE: .USE .MAKE
+ @for m in ${.MAKE.MAKEFILE_PREFERENCE}; do \
+ test -s ${.TARGET:R}/$$m || continue; \
+ echo "${TRACER}Checking ${.TARGET:R} for ${.TARGET:E} ..."; \
+ TARGET_SPEC=${.TARGET:E} \
+ MACHINE=${.TARGET:E} MACHINE_ARCH= NO_SUBDIR=1 \
+ ${.MAKE} -C ${.TARGET:R} || exit 1; \
+ break; \
+ done
+
+.ifdef ALL_MACHINES
+# this is how you limit it to only the machines we have been built for
+# previously.
+.if empty(ONLY_MACHINE_LIST)
+.if !empty(ALL_MACHINE_LIST)
+# ALL_MACHINE_LIST is the list of all legal machines - ignore anything else
+_machine_list != cd ${_CURDIR} && 'ls' -1 ${ALL_MACHINE_LIST:O:u:@m@${.MAKE.DEPENDFILE:T:R}.$m@} 2> /dev/null; echo
+.else
+_machine_list != 'ls' -1 ${_CURDIR}/${.MAKE.DEPENDFILE_PREFIX}.* 2> /dev/null; echo
+.endif
+_only_machines := ${_machine_list:${NIgnoreFiles:UN*.bak}:E:O:u}
+.else
+_only_machines := ${ONLY_MACHINE_LIST}
+.endif
+
+.if empty(_only_machines)
+# we must be boot-strapping
+_only_machines := ${TARGET_MACHINE:U${ALL_MACHINE_LIST:U${DEP_MACHINE}}}
+.endif
+
+.else # ! ALL_MACHINES
+# if ONLY_MACHINE_LIST is set, we are limited to that
+# if TARGET_MACHINE is set - it is really the same as ONLY_MACHINE_LIST
+# otherwise DEP_MACHINE is it - so DEP_MACHINE will match.
+_only_machines := ${ONLY_MACHINE_LIST:U${TARGET_MACHINE:U${DEP_MACHINE}}:M${DEP_MACHINE}}
+.endif
+
+.if !empty(NOT_MACHINE_LIST)
+_only_machines := ${_only_machines:${NOT_MACHINE_LIST:${M_ListToSkip}}}
+.endif
+
+# make sure we have a starting place?
+DIRDEPS ?= ${RELDIR}
+.endif # target
+
+_debug_reldir := ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.${DEP_MACHINE}:L:M$x}@}
+_debug_search := ${DEBUG_DIRDEPS:@x@${DEP_RELDIR:M$x}${${DEP_RELDIR}.depend:L:M$x}@}
+
+# the rest is done repeatedly for every Makefile.depend we read.
+# if we are anything but the original dir we care only about the
+# machine type we were included for..
+
+.if ${DEP_RELDIR} == "."
+_this_dir := ${SRCTOP}
+.else
+_this_dir := ${SRCTOP}/${DEP_RELDIR}
+.endif
+
+# on rare occasions, there can be a need for extra help
+_dep_hack := ${_this_dir}/${.MAKE.DEPENDFILE_PREFIX}.inc
+.-include "${_dep_hack}"
+
+.if ${DEP_RELDIR} != ${_DEP_RELDIR} || ${DEP_MACHINE} != ${TARGET_SPEC}
+# this should be all
+_machines := ${DEP_MACHINE}
+.else
+# this is the machine list we actually use below
+_machines := ${_only_machines}
+
+.if defined(HOSTPROG) || ${DEP_MACHINE} == "host"
+# we need to build this guy's dependencies for host as well.
+_machines += host
+.endif
+
+_machines := ${_machines:O:u}
+.endif
+
+# reset these each time through
+_build_dirs =
+_depdir_files =
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# pickup other machines for this dir if necessary
+.if ${BUILD_AT_LEVEL0:Uyes} == "no"
+_build_dirs += ${_machines:@m@${_CURDIR}.$m@}
+.else
+_build_dirs += ${_machines:N${DEP_MACHINE}:@m@${_CURDIR}.$m@}
+.if ${DEP_MACHINE} == ${TARGET_SPEC}
+# pickup local dependencies now
+.-include <.depend>
+.endif
+.endif
+.endif
+
+.if !empty(_debug_reldir)
+.info ${DEP_RELDIR}.${DEP_MACHINE}: _last_dependfile='${_last_dependfile}'
+.info ${DEP_RELDIR}.${DEP_MACHINE}: DIRDEPS='${DIRDEPS}'
+.info ${DEP_RELDIR}.${DEP_MACHINE}: _machines='${_machines}'
+.endif
+
+.if !empty(DIRDEPS)
+
+# this is what we start with
+__depdirs := ${DIRDEPS:${NSkipDir}:${DIRDEPS_FILTER:ts:}:O:u:@d@${SRCTOP}/$d@}
+
+# some entries may be qualified with .<machine>
+# the :M*/*/*.* just tries to limit the dirs we check to likely ones.
+# the ${d:E:M*/*} ensures we don't consider junos/usr.sbin/mgd
+__qual_depdirs := ${__depdirs:M*/*/*.*:@d@${exists($d):?:${"${d:E:M*/*}":?:${exists(${d:R}):?$d:}}}@}
+__unqual_depdirs := ${__depdirs:${__qual_depdirs:Uno:${M_ListToSkip}}}
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# if it was called out - we likely need it.
+__hostdpadd := ${DPADD:U.:M${HOST_OBJTOP}/*:S,${HOST_OBJTOP}/,,:H:${NSkipDir}:${DIRDEPS_FILTER:ts:}:S,$,.host,:N.*:@d@${SRCTOP}/$d@}
+__qual_depdirs += ${__hostdpadd}
+.endif
+
+.if !empty(_debug_reldir)
+.info depdirs=${__depdirs}
+.info qualified=${__qual_depdirs}
+.info unqualified=${__unqual_depdirs}
+.endif
+
+# _build_dirs is what we will feed to _DIRDEP_USE
+_build_dirs += \
+ ${__qual_depdirs:M*.host:${NSkipHostDir}:N.host} \
+ ${__qual_depdirs:N*.host} \
+ ${_machines:@m@${__unqual_depdirs:@d@$d.$m@}@}
+
+_build_dirs := ${_build_dirs:O:u}
+
+# this is where we will pick up more dependencies from
+# the inner inline loops look complex, but save a significant
+# amount of memory compared to a .for loop.
+_depdir_files =
+.for d in ${_build_dirs}
+.if exists($d)
+# easy, we're building for ${MACHINE}
+_depdir_files += ${.MAKE.DEPENDFILE_PREFERENCE:T:@m@${exists($d/$m):?$d/$m:}@:[1]}
+.elif exists(${d:R}) && ${d:R:T} == ${d:T:R}
+# a little more complex - building for another machine
+# we will ensure the file is qualified with a machine
+# so that if necessary _DEP_MACHINE can be set below
+_depdir_files += ${.MAKE.DEPENDFILE_PREFERENCE:T:S,.${TARGET_SPEC}$,.${d:E},:S,.${MACHINE}$,.${d:E},:@m@${exists(${d:R}/$m):?${d:R}/$m:}@:[1]:@m@${"${m:M*.${d:E}}":?$m:$m.${d:E}}@}
+.endif
+.endfor
+
+# clean up
+_depdir_files := ${_depdir_files:O:u}
+
+.endif # empty DIRDEPS
+
+# Normally if doing make -V something,
+# we do not want to waste time chasing DIRDEPS
+# but if we want to count the number of Makefile.depend* read, we do.
+.if ${.MAKEFLAGS:M-V${_V_READ_DIRDEPS}} == ""
+.if !empty(_build_dirs)
+# this makes it all happen
+dirdeps: ${_build_dirs}
+${_build_dirs}: _DIRDEP_USE
+
+.if !empty(_debug_reldir)
+.info ${DEP_RELDIR}.${DEP_MACHINE}: ${_build_dirs}
+.endif
+
+.for m in ${_machines}
+# it would be nice to do :N${.TARGET}
+.if !empty(__qual_depdirs)
+.for q in ${__qual_depdirs:E:O:u:N$m}
+.if !empty(_debug_reldir) || ${DEBUG_DIRDEPS:@x@${${DEP_RELDIR}.$m:L:M$x}${${DEP_RELDIR}.$q:L:M$x}@} != ""
+.info ${DEP_RELDIR}.$m: ${_build_dirs:M*.$q}
+.endif
+${_this_dir}.$m: ${_build_dirs:M*.$q}
+.endfor
+.endif
+.if !empty(_debug_reldir)
+.info ${DEP_RELDIR}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m}
+.endif
+${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m}
+.endfor
+
+.endif
+
+.for d in ${_depdir_files}
+.if ${.MAKE.MAKEFILES:M${d}} == ""
+.if !empty(_debug_search)
+.info Looking for $d
+.endif
+.if exists($d)
+.include <$d>
+.elif exists(${d:R})
+# an unqualified file exists, we qualified it above so we can set _DEP_MACHINE
+# it might be manually maintained and shared by all machine types
+# tell it the machine we are interested in.
+_DEP_MACHINE := ${d:E}
+.if !empty(_debug_reldir)
+.info loading ${d:R} for ${_DEP_MACHINE}
+.endif
+# pretend we read $d, so we don't come by here again.
+.MAKE.MAKEFILES += $d
+.include <${d:R}>
+.endif
+.endif
+.endfor
+.endif # -V
+
+.elif ${.MAKE.LEVEL} > 42
+.error You should have stopped recursing by now.
+.else
+_DEP_RELDIR := ${DEP_RELDIR}
+# pickup local dependencies
+.-include <.depend>
+.endif
+
diff --git a/share/mk/gendirdeps.mk b/share/mk/gendirdeps.mk
new file mode 100644
index 000000000000..890f4956f38e
--- /dev/null
+++ b/share/mk/gendirdeps.mk
@@ -0,0 +1,301 @@
+# $Id: gendirdeps.mk,v 1.10 2012/06/30 00:37:50 sjg Exp $
+
+# Copyright (c) 2010, Juniper Networks, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# This makefile [re]generates ${.MAKE.DEPENDFILE}
+#
+
+.include <install-new.mk>
+
+# Assumptions:
+# RELDIR is the relative path from ${SRCTOP} to ${_CURDIR}
+# (SRCTOP is ${SB}/src)
+# _CURDIR is the absolute version of ${.CURDIR}
+# _OBJDIR is the absolute version of ${.OBJDIR}
+# _objroot is realpath of ${_OBJTOP} without ${MACHINE}
+# this may be different from _OBJROOT if $SB/obj is a
+# symlink to another filesystem.
+# _objroot must be a prefix match for _objtop
+
+.MAIN: all
+
+# keep this simple
+.MAKE.MODE = compat
+
+all:
+
+_CURDIR ?= ${.CURDIR}
+_OBJDIR ?= ${.OBJDIR}
+_OBJTOP ?= ${OBJTOP}
+_OBJROOT ?= ${OBJROOT:U${_OBJTOP}}
+_objroot ?= ${_OBJROOT:tA}
+
+_this = ${.PARSEDIR}/${.PARSEFILE}
+
+# remember what to make
+_DEPENDFILE := ${_CURDIR}/${.MAKE.DEPENDFILE:T}
+
+# We do _not_ want to read our own output!
+.MAKE.DEPENDFILE = /dev/null
+
+# caller should have set this
+META_FILES ?= ${.MAKE.META.FILES}
+
+.if !empty(META_FILES)
+
+.if ${.MAKE.LEVEL} > 0 && !empty(GENDIRDEPS_FILTER)
+# so we can compare below
+.-include <${_DEPENDFILE}>
+# yes, I mean :U with no value
+_DIRDEPS := ${DIRDEPS:U:O:u}
+.endif
+
+META_FILES := ${META_FILES:T:O:u}
+.export META_FILES
+
+# pickup customizations
+.-include "local.gendirdeps.mk"
+
+# these are actually prefixes that we'll skip
+# they should all be absolute paths
+SKIP_GENDIRDEPS ?=
+.if !empty(SKIP_GENDIRDEPS)
+_skip_gendirdeps = egrep -v '^(${SKIP_GENDIRDEPS:O:u:ts|})' |
+.else
+_skip_gendirdeps =
+.endif
+
+# this (*should* be set in meta.sys.mk)
+# is the script that extracts what we want.
+META2DEPS ?= ${.PARSEDIR}/meta2deps.sh
+META2DEPS := ${META2DEPS}
+
+.if ${DEBUG_GENDIRDEPS:Uno:@x@${RELDIR:M$x}@} != "" && ${DEBUG_GENDIRDEPS:Uno:Mmeta2d*} != ""
+_time = time
+_sh_x = sh -x
+_py_d = -ddd
+.else
+_time =
+_sh_x =
+_py_d =
+.endif
+
+.if ${META2DEPS:E} == "py"
+# we can afford to do this all the time.
+DPDEPS ?= no
+META2DEPS_CMD = ${_time} ${PYTHON} ${META2DEPS} ${_py_d} \
+ -R ${RELDIR} -H ${HOST_TARGET} -O ${M2D_OBJROOT}
+.if ${DPDEPS:tl} != "no"
+META2DEPS_CMD += -D ${DPDEPS}
+.endif
+.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} == ""
+# meta2deps.py only groks objroot
+# so we need to give it what it expects
+M2D_OBJROOT = ${OBJTOP}/
+# and tell it not to add machine qualifiers
+META2DEPS_ARGS += MACHINE=none
+.else
+.if defined(SB_OBJROOT)
+M2D_OBJROOT ?= ${SB_OBJROOT}
+.else
+M2D_OBJROOT = ${OBJTOP}/
+.endif
+.endif
+.if defined(SB_BACKING_SB)
+META2DEPS_CMD += -S ${SB_BACKING_SB}/src -O ${SB_BACKING_SB}/${SB_OBJPREFIX}
+.endif
+META2DEPS_FILTER = sed 's,^src:,${SRCTOP}/,;s,^\([^/]\),${OBJTOP}/\1,' |
+.elif ${META2DEPS:E} == "sh"
+META2DEPS_CMD = ${_time} ${_sh_x} ${META2DEPS} \
+ OBJTOP=${_objtop} SB_OBJROOT=${_objroot}
+.else
+META2DEPS_CMD ?= ${META2DEPS}
+.endif
+
+# we are only interested in the dirs
+# sepecifically those we read something from.
+# we canonicalize them to keep things simple
+# if we are using a split-fs sandbox, it gets a little messier.
+_objtop := ${_OBJTOP:tA}
+dir_list != cd ${_OBJDIR} && \
+ ${META2DEPS_CMD} MACHINE=${MACHINE} \
+ SRCTOP=${SRCTOP} RELDIR=${RELDIR} CURDIR=${_CURDIR} \
+ ${META2DEPS_ARGS} \
+ ${META_FILES:O:u} | ${META2DEPS_FILTER} ${_skip_gendirdeps} \
+ sed 's,//*$$,,;s,\.${HOST_TARGET}$$,.host,'
+
+.if ${dir_list:M*ERROR\:*} != ""
+.warning ${dir_list:tW:C,.*(ERROR),\1,}
+.warning Skipping ${_DEPENDFILE:S,${SRCTOP}/,,}
+# we are not going to update anything
+.else
+
+.if !empty(DPADD)
+_nonlibs := ${DPADD:T:Nlib*:N*include}
+.if !empty(_nonlibs)
+dir_list += ${_nonlibs:@x@${DPADD:M*/$x}@:H:tA}
+.endif
+.endif
+
+# DIRDEPS represent things that had to have been built first
+# so they should all be undir OBJTOP.
+# Note that ${_OBJTOP}/bsd/include/machine will get reported
+# to us as $SRCTOP/bsd/sys/$MACHINE_ARCH/include meaning we
+# will want to visit bsd/include
+# so we add
+# ${"${dir_list:M*bsd/sys/${MACHINE_ARCH}/include}":?bsd/include:}
+# to GENDIRDEPS_DIR_LIST_XTRAS
+dirdep_list = \
+ ${dir_list:M${_objtop}*/*:C,${_objtop}[^/]*/,,} \
+ ${GENDIRDEPS_DIR_LIST_XTRAS}
+
+# anything we use from an object dir other than ours
+# needs to be qualified with its .<machine> suffix
+# (we used the pseudo machine "host" for the HOST_TARGET).
+qualdir_list = \
+ ${dir_list:M${_objroot}*/*/*:N${SRCTOP}*:N${_objtop}*:C,${_objroot}([^/]+)/(.*),\2.\1,:S,.${HOST_TARGET},.host,}
+
+.if ${_OBJROOT} != ${_objroot}
+dirdep_list += \
+ ${dir_list:M${_OBJTOP}*/*:C,${_OBJTOP}[^/]*/,,}
+
+qualdir_list += \
+ ${dir_list:M${_OBJROOT}*/*/*:N${SRCTOP}*:N${_OBJTOP}*:C,${_OBJROOT}([^/]+)/(.*),\2.\1,:S,.${HOST_TARGET},.host,}
+.endif
+
+dirdep_list := ${dirdep_list:O:u}
+qualdir_list := ${qualdir_list:O:u}
+
+DIRDEPS = \
+ ${dirdep_list:N${RELDIR}:N${RELDIR}/*} \
+ ${qualdir_list:N${RELDIR}.*:N${RELDIR}/*}
+
+# We only consider things below $RELDIR/ if they have a makefile.
+# This is the same test that _DIRDEPS_USE applies.
+# We have do a double test with dirdep_list as it _may_ contain
+# qualified dirs - if we got anything from a stage dir.
+# qualdir_list we know are all qualified.
+# It would be nice do peform this check for all of DIRDEPS,
+# but we cannot assume that all of the tree is present,
+# in fact we can only assume that RELDIR is.
+DIRDEPS += \
+ ${dirdep_list:M${RELDIR}/*:@d@${.MAKE.MAKEFILE_PREFERENCE:@m@${exists(${SRCTOP}/$d/$m):?$d:${exists(${SRCTOP}/${d:R}/$m):?$d:}}@}@} \
+ ${qualdir_list:M${RELDIR}/*:@d@${.MAKE.MAKEFILE_PREFERENCE:@m@${exists(${SRCTOP}/${d:R}/$m):?$d:}@}@}
+
+DIRDEPS := ${DIRDEPS:${GENDIRDEPS_FILTER:UNno:ts:}:O:u}
+
+.if ${DEBUG_GENDIRDEPS:Uno:@x@${RELDIR:M$x}@} != ""
+.info ${RELDIR}: dir_list='${dir_list}'
+.info ${RELDIR}: dirdep_list='${dirdep_list}'
+.info ${RELDIR}: qualdir_list='${qualdir_list}'
+.info ${RELDIR}: SKIP_GENDIRDEPS='${SKIP_GENDIRDEPS}'
+.info ${RELDIR}: GENDIRDEPS_FILTER='${GENDIRDEPS_FILTER}'
+.info ${RELDIR}: FORCE_DPADD='${DPADD}'
+.info ${RELDIR}: DIRDEPS='${DIRDEPS}'
+.endif
+
+# SRC_DIRDEPS is for checkout logic
+src_dirdep_list = \
+ ${dir_list:M${SRCTOP}/*:S,${SRCTOP}/,,}
+
+SRC_DIRDEPS = \
+ ${src_dirdep_list:N${RELDIR}:N${RELDIR}/*:C,(/h)/.*,,}
+
+SRC_DIRDEPS := ${SRC_DIRDEPS:${GENDIRDEPS_SRC_FILTER:UN/*:ts:}:O:u}
+
+# if you want to capture SRC_DIRDEPS in .MAKE.DEPENDFILE put
+# SRC_DIRDEPS_FILE = ${_DEPENDFILE}
+# in local.gendirdeps.mk
+.if ${SRC_DIRDEPS_FILE:Uno:tl} != "no"
+ECHO_SRC_DIRDEPS = echo 'SRC_DIRDEPS = \'; echo '${SRC_DIRDEPS:@d@ $d \\${.newline}@}'; echo;
+
+.if ${SRC_DIRDEPS_FILE:T} == ${_DEPENDFILE:T}
+_include_src_dirdeps = ${ECHO_SRC_DIRDEPS}
+.else
+all: ${SRC_DIRDEPS_FILE}
+.if !target(${SRC_DIRDEPS_FILE})
+${SRC_DIRDEPS_FILE}: ${META_FILES} ${_this} ${META2DEPS}
+ @(${ECHO_SRC_DIRDEPS}) > $@
+.endif
+.endif
+.endif
+_include_src_dirdeps ?=
+
+all: ${_DEPENDFILE}
+
+# if this is going to exist it would be there by now
+.if !exists(.depend)
+CAT_DEPEND = /dev/null
+.endif
+CAT_DEPEND ?= .depend
+
+.if !empty(_DIRDEPS) && ${DIRDEPS} != ${_DIRDEPS}
+# we may have changed a filter
+.PHONY: ${_DEPENDFILE}
+.endif
+
+# 'cat .depend' should suffice, but if we are mixing build modes
+# .depend may contain things we don't want.
+# The sed command at the end of the stream, allows for the filters
+# to output _{VAR} tokens which we will turn into proper ${VAR} references.
+${_DEPENDFILE}: ${CAT_DEPEND:M.depend} ${META_FILES:O:u:@m@${exists($m):?$m:}@} ${_this} ${META2DEPS}
+ @(echo '# Autogenerated - do NOT edit!'; echo; \
+ echo 'DEP_RELDIR := $${_PARSEDIR:S,$${SRCTOP}/,,}'; echo; \
+ echo 'DEP_MACHINE := $${.PARSEFILE:E}'; echo; \
+ echo 'DIRDEPS = \'; \
+ echo '${DIRDEPS:@d@ $d \\${.newline}@}'; echo; \
+ ${_include_src_dirdeps} \
+ echo '.include <dirdeps.mk>'; \
+ echo; \
+ echo '.if $${DEP_RELDIR} == $${_DEP_RELDIR}'; \
+ echo '# local dependencies - needed for -jN in clean tree'; \
+ [ -s ${CAT_DEPEND} ] && { grep : ${CAT_DEPEND} | grep -v '[/\\]'; }; \
+ echo '.endif' ) | sed 's,_\([{(]\),$$\1,g' > $@.new${.MAKE.PID}
+ @${InstallNew}; InstallNew -s $@.new${.MAKE.PID}
+
+.endif # meta2deps failed
+.elif !empty(SUBDIR)
+
+DIRDEPS := ${SUBDIR:S,^,${RELDIR}/,:O:u}
+
+all: ${_DEPENDFILE}
+
+${_DEPENDFILE}: ${MAKEFILE} ${_this}
+ @(echo '# Autogenerated - do NOT edit!'; echo; \
+ echo 'DEP_RELDIR := $${_PARSEDIR:S,$${SRCTOP}/,,}'; echo; \
+ echo 'DEP_MACHINE := $${.PARSEFILE:E}'; echo; \
+ echo 'DIRDEPS = \'; \
+ echo '${DIRDEPS:@d@ $d \\${.newline}@}'; echo; \
+ echo '.include <dirdeps.mk>'; \
+ echo ) | sed 's,_\([{(]\),$$\1,g' > $@.new
+ @${InstallNew}; InstallNew $@.new
+
+.else
+
+# nothing to do
+all ${_DEPENDFILE}:
+
+.endif
+${_DEPENDFILE}: .PRECIOUS
diff --git a/share/mk/host-target.mk b/share/mk/host-target.mk
new file mode 100644
index 000000000000..c6d4562bf15a
--- /dev/null
+++ b/share/mk/host-target.mk
@@ -0,0 +1,31 @@
+# RCSid:
+# $Id: host-target.mk,v 1.6 2011/03/02 05:05:21 sjg Exp $
+
+# Host platform information; may be overridden
+.if !defined(_HOST_OSNAME)
+_HOST_OSNAME != uname -s
+.export _HOST_OSNAME
+.endif
+.if !defined(_HOST_OSREL)
+_HOST_OSREL != uname -r
+.export _HOST_OSREL
+.endif
+.if !defined(_HOST_ARCH)
+_HOST_ARCH != uname -p 2>/dev/null || uname -m
+# uname -p may produce garbage on linux
+.if ${_HOST_ARCH:[\#]} > 1
+_HOST_ARCH != uname -m
+.endif
+.export _HOST_ARCH
+.endif
+
+HOST_OSMAJOR := ${_HOST_OSREL:C/[^0-9].*//}
+HOST_OSTYPE := ${_HOST_OSNAME}-${_HOST_OSREL:C/\([^\)]*\)//}-${_HOST_ARCH}
+HOST_OS := ${_HOST_OSNAME}
+host_os := ${_HOST_OSNAME:tl}
+HOST_TARGET := ${host_os}${HOST_OSMAJOR}-${_HOST_ARCH}
+
+# tr is insanely non-portable, accommodate the lowest common denominator
+TR ?= tr
+toLower = ${TR} 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'
+toUpper = ${TR} 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
diff --git a/share/mk/install-new.mk b/share/mk/install-new.mk
new file mode 100644
index 000000000000..ddfff20e3b85
--- /dev/null
+++ b/share/mk/install-new.mk
@@ -0,0 +1,53 @@
+# $Id: install-new.mk,v 1.3 2012/03/24 18:25:49 sjg Exp $
+#
+# @(#) Copyright (c) 2009, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+.if !defined(InstallNew)
+
+# copy if src and target are different making a backup if desired
+CmpCp= CmpCp() { \
+ src=$$1 target=$$2 _bak=$$3; \
+ if ! test -s $$target || ! cmp -s $$target $$src; then \
+ trap "" 1 2 3 15; \
+ if test -s $$target; then \
+ if test "x$$_bak" != x; then \
+ rm -f $$target$$_bak; \
+ mv $$target $$target$$_bak; \
+ else \
+ rm -f $$target; \
+ fi; \
+ fi; \
+ cp $$src $$target; \
+ fi; }
+
+# If the .new file is different, we want it.
+# Note: this function will work as is for *.new$RANDOM"
+InstallNew= ${CmpCp}; InstallNew() { \
+ _t=-e; _bak=; \
+ while :; do \
+ case "$$1" in \
+ -?) _t=$$1; shift;; \
+ --bak) _bak=$$2; shift 2;; \
+ *) break;; \
+ esac; \
+ done; \
+ for new in "$$@"; do \
+ if test $$_t $$new; then \
+ target=`expr $$new : '\(.*\).new'`; \
+ CmpCp $$new $$target $$_bak; \
+ fi; \
+ rm -f $$new; \
+ done; :; }
+
+.endif
diff --git a/share/mk/local.autodep.mk b/share/mk/local.autodep.mk
new file mode 100644
index 000000000000..a123e9bc7649
--- /dev/null
+++ b/share/mk/local.autodep.mk
@@ -0,0 +1,24 @@
+
+.if ${.MAKE.DEPENDFILE:M*.${MACHINE}} == ""
+# by default only MACHINE0 does updates
+UPDATE_DEPENDFILE_MACHINE?= ${MACHINE0}
+.if ${MACHINE} != ${UPDATE_DEPENDFILE_MACHINE}
+UPDATE_DEPENDFILE= no
+.endif
+.endif
+
+CFLAGS+= ${CFLAGS_LAST}
+CXXFLAGS+= ${CXXFLAGS_LAST}
+LDFLAGS+= ${LDFLAGS_LAST}
+
+CLEANFILES+= .depend
+
+# handy for debugging
+.SUFFIXES: .S .c .cc .cpp .cpp-out
+
+
+.S.cpp-out .c.cpp-out: .NOMETA
+ @${CC} -E ${CFLAGS} ${.IMPSRC} | grep -v '^[[:space:]]*$$'
+
+.cc.cpp-out: .NOMETA
+ @${CXX} -E ${CXXFLAGS} ${.IMPSRC} | grep -v '^[[:space:]]*$$'
diff --git a/share/mk/local.dirdeps.mk b/share/mk/local.dirdeps.mk
new file mode 100644
index 000000000000..dedf9e274134
--- /dev/null
+++ b/share/mk/local.dirdeps.mk
@@ -0,0 +1,15 @@
+.if !target(_DIRDEP_USE)
+# first time read
+.if ${MACHINE} == "host"
+DIRDEPS_FILTER+= \
+ Ninclude* \
+ Nlib/* \
+ Ngnu/lib/* \
+
+.endif
+.endif
+
+# this is how we can handle optional dependencies
+.if ${MK_SSP:Uno} != "no" && defined(PROG)
+DIRDEPS += gnu/lib/libssp/libssp_nonshared
+.endif
diff --git a/share/mk/local.gendirdeps.mk b/share/mk/local.gendirdeps.mk
new file mode 100644
index 000000000000..88c11e9db194
--- /dev/null
+++ b/share/mk/local.gendirdeps.mk
@@ -0,0 +1,10 @@
+# supress optional dependecies
+# local.dirdeps.mk will put them in if necessary
+GENDIRDEPS_FILTER+= Ngnu/lib/libssp/libssp_nonshared
+
+# gendirdeps.mk will turn _{VAR} into ${VAR} which keeps this simple
+GENDIRDEPS_FILTER+= ${CSU_DIR:L:@v@S,/${$v},/_{${v}},@}
+
+# this could easily get confused
+GENDIRDEPS_FILTER+= ${MACHINE_CPUARCH MACHINE_CPU MACHINE_ARCH MACHINE:L:@v@S,/${$v}/,/_{${v}}/,@:NS,//,*:u}
+
diff --git a/share/mk/local.init.mk b/share/mk/local.init.mk
new file mode 100644
index 000000000000..eb15b1ee9fa5
--- /dev/null
+++ b/share/mk/local.init.mk
@@ -0,0 +1,18 @@
+
+.if defined(.PARSEDIR)
+.if ${.MAKE.MODE:Mmeta*} != ""
+.if !empty(SUBDIR) && !defined(LIB) && !defined(PROG) && ${.MAKE.MAKEFILES:M*bsd.prog.mk} == ""
+.if ${.MAKE.MODE:Mleaf*} != ""
+# we only want leaf dirs to build in meta mode... and we are not one
+.MAKE.MODE = normal
+.endif
+.endif
+.endif
+.endif
+
+.if ${MACHINE} == "host"
+HOST_CC?= /usr/bin/cc
+HOST_CFLAGS+= -DHOSTPROG
+CC= ${HOST_CC}
+CFLAGS+= ${HOST_CFLAGS}
+.endif
diff --git a/share/mk/local.sys.mk b/share/mk/local.sys.mk
new file mode 100644
index 000000000000..d1362013dafe
--- /dev/null
+++ b/share/mk/local.sys.mk
@@ -0,0 +1,214 @@
+WITH_INSTALL_AS_USER= yes
+
+.if defined(.PARSEDIR) # bmake
+
+# some handy macros
+_this = ${.PARSEDIR:tA}/${.PARSEFILE}
+# some useful modifiers
+
+# A useful trick for testing multiple :M's against something
+# :L says to use the variable's name as its value - ie. literal
+# got = ${clean* destroy:${M_ListToMatch:S,V,.TARGETS,}}
+M_ListToMatch = L:@m@$${V:M$$m}@
+# match against our initial targets (see above)
+M_L_TARGETS = ${M_ListToMatch:S,V,_TARGETS,}
+
+# turn a list into a set of :N modifiers
+# NskipFoo = ${Foo:${M_ListToSkip}}
+M_ListToSkip= O:u:ts::S,:,:N,g:S,^,N,
+
+# type should be a builtin in any sh since about 1980,
+# AUTOCONF := ${autoconf:L:${M_whence}}
+M_type = @x@(type $$x 2> /dev/null); echo;@:sh:[0]:N* found*:[@]:C,[()],,g
+M_whence = ${M_type}:M/*
+
+# convert a path to a valid shell variable
+M_P2V = tu:C,[./-],_,g
+
+# convert path to absolute
+.if ${MAKE_VERSION:U0} > 20100408
+M_tA = tA
+.else
+M_tA = C,.*,('cd' & \&\& 'pwd') 2> /dev/null || echo &,:sh
+.endif
+
+# this is handy for forcing a space into something.
+AnEmptyVar=
+
+# absoulte path to what we are reading.
+_PARSEDIR = ${.PARSEDIR:${M_tA}}
+
+.if !empty(SB)
+SB_SRC ?= ${SB}/src
+SB_OBJROOT ?= ${SB}/obj
+# this is what we use below
+SRCTOP ?= ${SB_SRC}
+OBJROOT ?= ${SB_OBJROOT}
+.endif
+
+.if empty(SRCTOP)
+SRCTOP := ${_PARSEDIR:H:H}
+.export SRCTOP
+OBJROOT ?= ${SRCTOP:H}/obj/
+.endif
+
+# we need HOST_TARGET etc below.
+.include <host-target.mk>
+
+OBJTOP ?= ${OBJROOT}${MACHINE}
+
+.if !defined(_TARGETS)
+# some things we do only once
+_TARGETS := ${.TARGETS}
+.-include <sys.env.mk>
+.if !empty(OBJROOT)
+.if ${OBJROOT:M*/} != ""
+OBJROOT:= ${OBJROOT:tA}/
+.else
+OBJROOT:= ${OBJROOT:H:tA}/${OBJROOT:T}
+.endif
+.export OBJROOT
+.endif
+.endif
+
+.if !empty(SRCTOP)
+.if ${.CURDIR} == ${SRCTOP}
+RELDIR = .
+.elif ${.CURDIR:M${SRCTOP}/*}
+RELDIR := ${.CURDIR:S,${SRCTOP}/,,}
+.endif
+.endif
+
+HOST_OBJTOP ?= ${OBJROOT}${HOST_TARGET}
+
+.if ${OBJTOP} == ${HOST_OBJTOP} || ${REQUESTED_MACHINE:U${MACHINE}} == "host"
+MACHINE= host
+.endif
+.if ${MACHINE} == "host"
+OBJTOP := ${HOST_OBJTOP}
+.endif
+
+# if you want objdirs make them automatic
+.if ${MKOBJDIRS:Uno} == "auto"
+WITH_AUTO_OBJ= yes
+.include <auto.obj.mk>
+.endif
+
+# the logic in bsd.own.mk forces this dance
+.ifndef WITHOUT_META_MODE
+WITH_META_MODE= yes
+
+.ifndef WITHOUT_STAGING
+WITH_STAGING= yes
+.ifndef WITHOUT_STAGING_PROG
+WITH_STAGING_PROG= yes
+.endif
+.endif
+
+PYTHON ?= /usr/local/bin/python
+
+.if ${.MAKE.LEVEL} == 0
+# this works best if share/mk is ready for it.
+BUILD_AT_LEVEL0= no
+# By default only MACHINE0 updates dependencies
+# see local.autodep.mk
+MACHINE0 := ${MACHINE}
+.export MACHINE0
+.export PYTHON
+.endif
+
+# we want to end up with a singe stage tree for all machines
+.ifndef WITHOUT_STAGING
+.if empty(STAGE_ROOT)
+STAGE_ROOT?= ${OBJROOT}stage
+.export STAGE_ROOT
+.endif
+.endif
+
+.if !empty(STAGE_ROOT)
+.if ${MACHINE} == "host"
+STAGE_MACHINE= ${HOST_TARGET}
+.else
+STAGE_MACHINE= ${MACHINE}
+.endif
+STAGE_OBJTOP= ${STAGE_ROOT}/${STAGE_MACHINE}
+STAGE_COMMON_OBJTOP= ${STAGE_ROOT}/common
+STAGE_HOST_OBJTOP= ${STAGE_ROOT}/${HOST_TARGET}
+
+STAGE_LIBDIR= ${STAGE_OBJTOP}${LIBDIR:U/lib}
+# this is not the same as INCLUDEDIR
+STAGE_INCSDIR= ${STAGE_OBJTOP}${INCSDIR:U/include}
+# the target is usually an absolute path
+STAGE_SYMLINKS_DIR= ${STAGE_OBJTOP}
+
+.ifndef WITH_SYSROOT
+.if ${MACHINE} != "host"
+CFLAGS_LAST+= -nostdinc
+.endif
+CFLAGS_LAST+= -isystem ${STAGE_OBJTOP}/usr/include -isystem ${STAGE_OBJTOP}/include
+LDFLAGS_LAST+= -B${STAGE_LIBDIR} -L${STAGE_LIBDIR}
+CXXFLAGS_LAST+= -isystem ${STAGE_OBJTOP}/usr/include/c++/${GCCVER:U4.2}
+.else
+# if ld suppored sysroot, this would suffice
+CFLAGS_LAST+= --sysroot=${STAGE_OBJTOP} -isystem ${STAGE_OBJTOP}/include
+.endif
+.endif
+.if ${USE_META:Uyes} == "yes"
+.include "meta.sys.mk"
+.endif
+
+# most dirs can be satisfied with one Makefile.depend
+.undef .MAKE.DEPENDFILE
+.MAKE.DEPENDFILE_PREFERENCE = \
+ ${.MAKE.DEPENDFILE_PREFIX} \
+ ${.MAKE.DEPENDFILE_PREFIX}.${MACHINE}
+
+.include "sys.dependfile.mk"
+
+.if ${MACHINE} == "host"
+# need a machine specific file
+.MAKE.DEPENDFILE= ${.MAKE.DEPENDFILE_PREFIX}.${MACHINE}
+.endif
+
+.MAKE.META.BAILIWICK = ${SB} ${OBJROOT} ${STAGE_ROOT}
+
+.endif # meta mode
+
+# ensure we have a value
+.MAKE.MODE ?= normal
+
+# don't rely on MACHINE_ARCH being set or valid
+
+MACHINE_ARCH.host = ${_HOST_ARCH}
+MACHINE_ARCH.${MACHINE} ?= ${MACHINE}
+MACHINE_ARCH := ${MACHINE_ARCH.${MACHINE}}
+
+CSU_DIR.i386 = csu/i386-elf
+CSU_DIR.${MACHINE_ARCH} ?= csu/${MACHINE_ARCH}
+CSU_DIR := ${CSU_DIR.${MACHINE_ARCH}}
+
+MAKE_PRINT_VAR_ON_ERROR+= \
+ .CURDIR \
+ .MAKE \
+ .OBJDIR \
+ .TARGETS \
+ DESTDIR \
+ LD_LIBRARY_PATH \
+ MACHINE \
+ MACHINE_ARCH \
+ MAKEOBJDIRPREFIX \
+ MAKESYSPATH \
+ MAKE_VERSION\
+ OBJTOP \
+ ${MAKE_PRINT_VAR_ON_ERROR_XTRAS}
+
+# these are handy
+# we can use this for a cheap timestamp at the start of a target's script,
+# but not at the end - since make will expand both at the same time.
+TIME_STAMP_FMT = @ %s [%Y-%m-%d %T]
+TIME_STAMP = ${TIME_STAMP_FMT:localtime}
+# this will produce the same output but as of when date(1) is run.
+TIME_STAMP_DATE = `date '+${TIME_STAMP_FMT}'`
+TIME_STAMP_END?= ${TIME_STAMP_DATE}
+
+.endif # bmake
diff --git a/share/mk/meta.autodep.mk b/share/mk/meta.autodep.mk
new file mode 100644
index 000000000000..f063837ca980
--- /dev/null
+++ b/share/mk/meta.autodep.mk
@@ -0,0 +1,261 @@
+# $Id: meta.autodep.mk,v 1.28 2012/07/13 15:38:16 sjg Exp $
+
+#
+# @(#) Copyright (c) 2010, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+_this ?= ${.PARSEFILE}
+.if !target(__${_this}__)
+__${_this}__: .NOTMAIN
+
+.-include "local.autodep.mk"
+
+.if defined(SRCS)
+# it would be nice to be able to query .SUFFIXES
+OBJ_EXTENSIONS+= .o .po .lo .So
+
+# explicit dependencies help short-circuit .SUFFIX searches
+SRCS_DEP_FILTER+= N*.[hly]
+.for s in ${SRCS:${SRCS_DEP_FILTER:O:u:ts:}}
+.for e in ${OBJ_EXTENSIONS:O:u}
+.if !target(${s:T:R}$e)
+${s:T:R}$e: $s
+.endif
+.endfor
+.endfor
+.endif
+
+.if make(gendirdeps)
+# you are supposed to know what you are doing!
+UPDATE_DEPENDFILE = yes
+.elif !empty(.TARGETS) && !make(all)
+# do not update the *depend* files
+# unless we are building the entire directory or the default target.
+# NO means don't update .depend - or Makefile.depend*
+# no means update .depend but not Makefile.depend*
+UPDATE_DEPENDFILE = NO
+.elif ${.MAKEFLAGS:M-k} != ""
+# it is a bad idea to update anything
+UPDATE_DEPENDFILE = NO
+.endif
+
+_CURDIR ?= ${.CURDIR}
+_DEPENDFILE := ${_CURDIR}/${.MAKE.DEPENDFILE:T}
+
+.if ${.MAKE.LEVEL} == 0
+.if ${BUILD_AT_LEVEL0:Uyes:tl} == "no"
+UPDATE_DEPENDFILE = NO
+.endif
+.endif
+.if !exists(${_DEPENDFILE})
+_bootstrap_dirdeps = yes
+.endif
+_bootstrap_dirdeps ?= no
+UPDATE_DEPENDFILE ?= yes
+
+.if ${DEBUG_AUTODEP:Uno:@m@${RELDIR:M$m}@} != ""
+.info ${_DEPENDFILE:S,${SRCTOP}/,,} update=${UPDATE_DEPENDFILE}
+.endif
+
+.if !empty(XMAKE_META_FILE)
+.if exists(${.OBJDIR}/${XMAKE_META_FILE})
+# we cannot get accurate dependencies from an update build
+UPDATE_DEPENDFILE = NO
+.else
+META_XTRAS += ${XMAKE_META_FILE}
+.endif
+.endif
+
+.if ${_bootstrap_dirdeps} == "yes" || exists(${_DEPENDFILE})
+# if it isn't supposed to be touched by us the Makefile should have
+# UPDATE_DEPENDFILE = no
+WANT_UPDATE_DEPENDFILE ?= yes
+.endif
+
+.if ${WANT_UPDATE_DEPENDFILE:Uno:tl} != "no"
+.if ${.MAKE.MODE:Mmeta*} == "" || ${.MAKE.MODE:M*read*} != ""
+UPDATE_DEPENDFILE = no
+.endif
+
+.if ${DEBUG_AUTODEP:Uno:@m@${RELDIR:M$m}@} != ""
+.info ${_DEPENDFILE:S,${SRCTOP}/,,} update=${UPDATE_DEPENDFILE}
+.endif
+
+.if ${UPDATE_DEPENDFILE:tl} == "yes"
+# sometimes we want .meta files generated to aid debugging/error detection
+# but do not want to consider them for dependencies
+# for example the result of running configure
+# just make sure this is not empty
+META_FILE_FILTER ?= N.meta
+
+.if !empty(DPADD)
+# if we have any non-libs in DPADD,
+# they probably need to be paid attention to
+.if !empty(DPLIBS)
+FORCE_DPADD = ${DPADD:${DPLIBS:${M_ListToSkip}}:${DPADD_LAST:${M_ListToSkip}}}
+.else
+_nonlibs := ${DPADD:T:Nlib*:N*include}
+.if !empty(_nonlibs)
+FORCE_DPADD += ${_nonlibs:@x@${DPADD:M*/$x}@}
+.endif
+.endif
+.endif
+
+.if !make(gendirdeps)
+.END: gendirdeps
+.endif
+
+# if we don't have OBJS, then .depend isn't useful
+.if !target(.depend) && (!empty(OBJS) || ${.ALLTARGETS:M*.o} != "")
+# some makefiles and/or targets contain
+# circular dependencies if you dig too deep
+# (as meta mode is apt to do)
+# so we provide a means of supressing them.
+# the input to the loop below is target: dependency
+# with just one dependency per line.
+# Also some targets are not really local, or use random names.
+# Use local.autodep.mk to provide local additions!
+SUPPRESS_DEPEND += \
+ ${SB:S,/,_,g}* \
+ *:y.tab.c \
+ *.c:*.c \
+ *.h:*.h
+
+.NOPATH: .depend
+# we use ${.MAKE.META.CREATED} to trigger an update but
+# we process using ${.MAKE.META.FILES}
+# the double $$ defers initial evaluation
+# if necessary, we fake .po dependencies, just so the result
+# in Makefile.depend* is stable
+# The current objdir may be refered to in various ways
+OBJDIR_REFS += ${.OBJDIR} ${.OBJDIR:tA} ${_OBJDIR} ${RELOBJTOP}/${RELDIR}
+_depend = .depend
+# it would be nice to be able to get .SUFFIXES as ${.SUFFIXES}
+# we actually only care about the .SUFFIXES of files that might be
+# generated by tools like yacc.
+DEPEND_SUFFIXES += .c .h .cpp .hpp .cxx .hxx .cc .hh
+.depend: .NOMETA $${.MAKE.META.CREATED} ${_this}
+ @echo "Updating $@: ${.OODATE:T:[1..8]}"
+ @egrep -i '^R .*\.(${DEPEND_SUFFIXES:tl:O:u:S,^.,,:ts|})$$' /dev/null ${.MAKE.META.FILES:T:O:u:${META_FILE_FILTER:ts:}:M*o.meta} | \
+ sed -e 's, \./, ,${OBJDIR_REFS:O:u:@d@;s, $d/, ,@};/\//d' \
+ -e 's,^\([^/][^/]*\).meta...[0-9]* ,\1: ,' | \
+ sort -u | \
+ while read t d; do \
+ case "$$d:" in $$t) continue;; esac; \
+ case "$$t$$d" in ${SUPPRESS_DEPEND:U.:O:u:ts|}) continue;; esac; \
+ echo $$t $$d; \
+ done > $@.${.MAKE.PID}
+ @case "${.MAKE.META.FILES:T:M*.po.*}" in \
+ *.po.*) mv $@.${.MAKE.PID} $@;; \
+ *) { cat $@.${.MAKE.PID}; \
+ sed 's,\.So:,.o:,;s,\.o:,.po:,' $@.${.MAKE.PID}; } | sort -u > $@; \
+ rm -f $@.${.MAKE.PID};; \
+ esac
+.else
+# make sure this exists
+.depend:
+# do _not_ assume that .depend is in any fit state for us to use
+CAT_DEPEND = /dev/null
+.if ${.MAKE.LEVEL} > 0
+.export CAT_DEPEND
+.endif
+_depend =
+.endif
+
+.if ${DEBUG_AUTODEP:Uno:@m@${RELDIR:M$m}@} != ""
+.info ${_DEPENDFILE:S,${SRCTOP}/,,} _depend=${_depend}
+.endif
+
+gendirdeps: ${_DEPENDFILE}
+
+.if !target(${_DEPENDFILE})
+.if ${_bootstrap_dirdeps} == "yes"
+# We are boot-strapping a new directory
+# Use DPADD to seed DIRDEPS
+.if !empty(DPADD)
+# anything which matches ${_OBJROOT}* but not ${_OBJTOP}*
+# needs to be qualified in DIRDEPS
+# The pseudo machine "host" is used for HOST_TARGET
+DIRDEPS = \
+ ${DPADD:M${_OBJTOP}*:H:C,${_OBJTOP}[^/]*/,,:N.:O:u} \
+ ${DPADD:M${_OBJROOT}*:N${_OBJTOP}*:H:S,${_OBJROOT},,:C,^([^/]+)/(.*),\2.\1,:S,${HOST_TARGET}$,host,:N.*:O:u}
+
+.endif
+.endif
+
+_gendirdeps_mutex =
+.if defined(NEED_GENDIRDEPS_MUTEX)
+# If a src dir gets built with multiple object dirs,
+# we need a mutex. Obviously, this is best avoided.
+# Note if .MAKE.DEPENDFILE is common for all ${MACHINE}
+# you either need to mutex, or ensure only one machine builds at a time!
+# lockf is an example of a suitable tool
+LOCKF ?= /usr/bin/lockf
+.if exists(${LOCKF})
+GENDIRDEPS_MUTEXER ?= ${LOCKF} -k
+.endif
+.if empty(GENDIRDEPS_MUTEXER)
+.error NEED_GENDIRDEPS_MUTEX defined, but GENDIRDEPS_MUTEXER not set
+.else
+_gendirdeps_mutex = ${GENDIRDEPS_MUTEXER} ${GENDIRDEPS_MUTEX:U${_CURDIR}/Makefile}
+.endif
+.endif
+
+# If we have META_XTRAS we most likely did not create them
+# but we need to behave as if we did.
+# Avoid adding glob patterns to .MAKE.META.CREATED though.
+.MAKE.META.CREATED += ${META_XTRAS:N*\**:O:u}
+
+.if make(gendirdeps)
+META_FILES = *.meta
+.elif ${OPTIMIZE_OBJECT_META_FILES:Uno:tl} == "no"
+META_FILES = ${.MAKE.META.FILES:T:N.depend*:O:u}
+.else
+# if we have 1000's of .o.meta, .So.meta etc we need only look at one set
+# it is left as an exercise for the reader to work out what this does
+META_FILES = ${.MAKE.META.FILES:T:N.depend*:N*o.meta:O:u} \
+ ${.MAKE.META.FILES:T:M*.${.MAKE.META.FILES:M*o.meta:R:E:O:u:[1]}.meta:O:u}
+.endif
+
+.if ${DEBUG_AUTODEP:Uno:@m@${RELDIR:M$m}@} != ""
+.info ${_DEPENDFILE:S,${SRCTOP}/,,}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} xtras=${META_XTRAS}
+.endif
+
+.if ${.MAKE.LEVEL} > 0 && !empty(GENDIRDEPS_FILTER)
+.export GENDIRDEPS_FILTER
+.endif
+
+_makesyspath:= ${_PARSEDIR}
+${_DEPENDFILE}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.META.CREATED}
+ @echo Checking $@: ${.OODATE:T:[1..8]}
+ @(cd . && \
+ SKIP_GENDIRDEPS='${SKIP_GENDIRDEPS:O:u}' \
+ DPADD='${FORCE_DPADD:O:u}' ${_gendirdeps_mutex} \
+ MAKESYSPATH=${_makesyspath} \
+ ${.MAKE} -f gendirdeps.mk RELDIR=${RELDIR} _DEPENDFILE=${_DEPENDFILE} \
+ META_FILES='${META_XTRAS:T:O:u} ${META_FILES:T:O:u:${META_FILE_FILTER:ts:}}')
+ @test -s $@ && touch $@; :
+.endif
+
+.endif
+.endif
+
+.if ${_bootstrap_dirdeps} == "yes"
+# make sure this is included at least once
+.include <dirdeps.mk>
+.else
+${_DEPENDFILE}: .PRECIOUS
+.endif
+
+CLEANFILES += *.meta filemon.* *.db
+.endif
diff --git a/share/mk/meta.stage.mk b/share/mk/meta.stage.mk
new file mode 100644
index 000000000000..303e7b8afd7d
--- /dev/null
+++ b/share/mk/meta.stage.mk
@@ -0,0 +1,213 @@
+# $Id: meta.stage.mk,v 1.15 2012/10/14 02:50:38 sjg Exp $
+#
+# @(#) Copyright (c) 2011, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+.if !target(__${.PARSEFILE}__)
+__${.PARSEFILE}__:
+
+.if ${.MAKE.DEPENDFILE_PREFERENCE:U${.MAKE.DEPENDFILE}:M*.${MACHINE}} != ""
+# this is generally safer anyway
+_dirdep = ${RELDIR}.${MACHINE}
+.else
+_dirdep = ${RELDIR}
+.endif
+
+# this allows us to trace dependencies back to their src dir
+.dirdep:
+ @echo '${_dirdep}' > $@
+
+.if defined(NO_POSIX_SHELL) || ${type printf:L:sh:Mbuiltin} == ""
+_stage_file_basename = `basename $$f`
+_stage_target_dirname = `dirname $$t`
+.else
+_stage_file_basename = $${f\#\#*/}
+_stage_target_dirname = $${t%/*}
+.endif
+
+_objroot ?= ${_OBJROOT:tA}
+# make sure this is global
+_STAGED_DIRS ?=
+.export _STAGED_DIRS
+# add each dir we stage to to _STAGED_DIRS
+# and make sure we have absolute paths so that bmake
+# will match against .MAKE.META.BAILIWICK
+STAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@
+# convert _STAGED_DIRS into suitable filters
+GENDIRDEPS_FILTER += Nnot-empty-is-important \
+ ${_STAGED_DIRS:O:u:M${OBJTOP}*:S,${OBJTOP}/,N,} \
+ ${_STAGED_DIRS:O:u:N${OBJTOP}*:S,${_objroot},,:C,^([^/]+)/(.*),N\2.\1,:S,${HOST_TARGET},.host,}
+
+# it is an error for more than one src dir to try and stage
+# the same file
+STAGE_DIRDEP_SCRIPT = StageDirdep() { \
+ t=$$1; \
+ if [ -s $$t.dirdep ]; then \
+ cmp -s .dirdep $$t.dirdep && return; \
+ echo "ERROR: $$t installed by `cat $$t.dirdep` not ${_dirdep}" >&2; \
+ exit 1; \
+ fi; \
+ ln .dirdep $$t.dirdep 2> /dev/null || \
+ cp .dirdep $$t.dirdep; }
+
+# common logic for staging files
+# this all relies on RELDIR being set to a subdir of SRCTOP
+# we use ln(1) if we can, else cp(1)
+STAGE_FILE_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageFiles() { \
+ case "$$1" in -m) mode=$$2; shift 2;; *) mode=;; esac; \
+ dest=$$1; shift; \
+ mkdir -p $$dest; \
+ [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
+ for f in "$$@"; do \
+ case "$$f" in */*) t=$$dest/${_stage_file_basename};; *) t=$$dest/$$f;; esac; \
+ StageDirdep $$t; \
+ rm -f $$t; \
+ { ln $$f $$t 2> /dev/null || \
+ cp -p $$f $$t; }; \
+ $${mode:+chmod $$mode $$t}; \
+ done; :; }
+
+STAGE_LINKS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageLinks() { \
+ case "$$1" in --) shift;; -*) ldest= lnf=$$1; shift;; /*) ldest=$$1/;; esac; \
+ dest=$$1; shift; \
+ mkdir -p $$dest; \
+ [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
+ while test $$\# -ge 2; do \
+ l=$$ldest$$1; shift; \
+ t=$$dest/$$1; \
+ case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
+ shift; \
+ StageDirdep $$t; \
+ rm -f $$t 2>/dev/null; \
+ ln $$lnf $$l $$t; \
+ done; :; }
+
+STAGE_AS_SCRIPT = ${STAGE_DIRDEP_SCRIPT}; StageAs() { \
+ case "$$1" in -m) mode=$$2; shift 2;; *) mode=;; esac; \
+ dest=$$1; shift; \
+ mkdir -p $$dest; \
+ [ -s .dirdep ] || echo '${_dirdep}' > .dirdep; \
+ while test $$\# -ge 2; do \
+ s=$$1; shift; \
+ t=$$dest/$$1; \
+ case "$$1" in */*) mkdir -p ${_stage_target_dirname};; esac; \
+ shift; \
+ StageDirdep $$t; \
+ rm -f $$t; \
+ { ln $$s $$t 2> /dev/null || \
+ cp -p $$s $$t; }; \
+ $${mode:+chmod $$mode $$t}; \
+ done; :; }
+
+# this is simple, a list of the "staged" files depends on this,
+_STAGE_BASENAME_USE: .USE ${.TARGET:T}
+ @${STAGE_FILE_SCRIPT}; StageFiles ${.TARGET:H:${STAGE_DIR_FILTER}} ${.TARGET:T}
+
+.if !empty(STAGE_INCSDIR)
+CLEANFILES += stage_incs
+
+STAGE_INCS ?= ${.ALLSRC:N.dirdep}
+
+stage_incs: .dirdep
+ @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_INCSDIR:${STAGE_DIR_FILTER}} ${STAGE_INCS}
+ @touch $@
+.endif
+
+.if !empty(STAGE_LIBDIR)
+CLEANFILES += stage_libs
+
+STAGE_LIBS ?= ${.ALLSRC:N.dirdep}
+
+stage_libs: .dirdep
+ @${STAGE_FILE_SCRIPT}; StageFiles ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${STAGE_LIBS}
+.if !empty(SHLIB_LINKS)
+ @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \
+ ${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@}
+.elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME)
+ @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} ${SYMLINKS:T}
+.endif
+ @touch $@
+.endif
+
+.if !empty(STAGE_DIR)
+STAGE_SETS += _default
+STAGE_DIR._default = ${STAGE_DIR}
+STAGE_LINKS_DIR._default = ${STAGE_LINKS_DIR:U${STAGE_OBJTOP}}
+STAGE_SYMLINKS_DIR._default = ${STAGE_SYMLINKS_DIR:U${STAGE_OBJTOP}}
+STAGE_FILES._default = ${STAGE_FILES}
+STAGE_LINKS._default = ${STAGE_LINKS}
+STAGE_SYMLINKS._default = ${STAGE_SYMLINKS}
+STAGE_FILES ?= ${.ALLSRC:N.dirdep:Nstage_*}
+STAGE_SYMLINKS ?= ${.ALLSRC:T:N.dirdep:Nstage_*}
+.endif
+
+.if !empty(STAGE_SETS)
+
+CLEANFILES += ${STAGE_SETS:@s@stage*$s@}
+
+# some makefiles need to populate multiple directories
+.for s in ${STAGE_SETS:O:u}
+STAGE_FILES.$s ?= ${.ALLSRC:N.dirdep}
+STAGE_SYMLINKS.$s ?= ${.ALLSRC:N.dirdep}
+STAGE_LINKS_DIR.$s ?= ${STAGE_OBJTOP}
+STAGE_SYMLINKS_DIR.$s ?= ${STAGE_OBJTOP}
+
+.if $s != "_default"
+stage_files: stage_files.$s
+stage_files.$s: .dirdep
+.else
+stage_files: .dirdep
+.endif
+ @${STAGE_FILE_SCRIPT}; StageFiles ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_FILES.$s}
+ @touch $@
+
+.if $s != "_default"
+stage_links: stage_links.$s
+stage_links.$s: .dirdep
+.else
+stage_links: .dirdep
+.endif
+ @${STAGE_LINKS_SCRIPT}; StageLinks ${STAGE_LINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_LINKS.$s}
+ @touch $@
+
+.if $s != "_default"
+stage_symlinks: stage_symlinks.$s
+stage_symlinks.$s: .dirdep
+.else
+stage_symlinks: .dirdep
+.endif
+ @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_SYMLINKS_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_SYMLINKS.$s}
+ @touch $@
+
+.endfor
+.endif
+
+.if !empty(STAGE_AS_SETS)
+
+CLEANFILES += ${STAGE_AS_SETS:@s@stage*$s@}
+
+# sometimes things need to be renamed as they are staged
+# each ${file} will be staged as ${STAGE_AS_${file:T}}
+# one could achieve the same with SYMLINKS
+.for s in ${STAGE_AS_SETS:O:u}
+STAGE_AS.$s ?= ${.ALLSRC:N.dirdep}
+
+stage_as: stage_as.$s
+stage_as.$s: .dirdep
+ @${STAGE_AS_SCRIPT}; StageAs ${FLAGS.$@} ${STAGE_FILES_DIR.$s:U${STAGE_DIR.$s}:${STAGE_DIR_FILTER}} ${STAGE_AS.$s:@f@$f ${STAGE_AS_${f:T}:U${f:T}}@}
+ @touch $@
+
+.endfor
+.endif
+
+.endif
diff --git a/share/mk/meta.subdir.mk b/share/mk/meta.subdir.mk
new file mode 100644
index 000000000000..1a77b44abc3c
--- /dev/null
+++ b/share/mk/meta.subdir.mk
@@ -0,0 +1,79 @@
+# $Id: meta.subdir.mk,v 1.8 2011/11/09 22:27:25 sjg Exp $
+
+#
+# @(#) Copyright (c) 2010, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+.if !defined(NO_SUBDIR) && !empty(SUBDIR)
+.if make(destroy*) || make(clean*)
+.MAKE.MODE = compat
+.if !commands(destroy)
+.-include <bsd.obj.mk>
+.endif
+.elif ${.MAKE.LEVEL} == 0
+
+.MAIN: all
+
+.if !exists(${.CURDIR}/${.MAKE.DEPENDFILE:T}) || make(gendirdeps)
+# start with this
+DIRDEPS = ${SUBDIR:N.WAIT:O:u:@d@${RELDIR}/$d@}
+
+.if make(gendirdeps)
+.include <meta.autodep.mk>
+.else
+# this is the cunning bit
+# actually it is probably a bit risky
+# since we may pickup subdirs which are not relevant
+# the alternative is a walk through the tree though
+# which is difficult without a sub-make.
+
+.if defined(BOOTSTRAP_DEPENDFILES)
+_find_name = ${.MAKE.MAKEFILE_PREFERENCE:@m@-o -name $m@:S,^-o,,1}
+DIRDEPS = ${_subdeps:H:O:u:@d@${RELDIR}/$d@}
+.elif ${.MAKE.DEPENDFILE:E} == ${MACHINE} && defined(ALL_MACHINES)
+# we want to find Makefile.depend.* ie for all machines
+# and turn the dirs into dir.<machine>
+_find_name = -name '${.MAKE.DEPENDFILE:T:R}*'
+DIRDEPS = ${_subdeps:O:u:${NIgnoreFiles}:@d@${RELDIR}/${d:H}.${d:E}@:S,.${MACHINE}$,,:S,.depend$,,}
+.else
+# much simpler
+_find_name = -name ${.MAKE.DEPENDFILE:T}
+.if ${.MAKE.DEPENDFILE:E} == ${MACHINE}
+_find_name += -o -name ${.MAKE.DEPENDFILE:T:R}
+.endif
+DIRDEPS = ${_subdeps:H:O:u:@d@${RELDIR}/$d@}
+.endif
+
+_subdeps != cd ${.CURDIR} && \
+ find ${SUBDIR:N.WAIT} -type f \( ${_find_name} \) -print -o \
+ -name .svn -prune 2> /dev/null; echo
+
+.if empty(_subdeps)
+DIRDEPS =
+.else
+# clean up if needed
+DIRDEPS := ${DIRDEPS:S,^./,,:S,/./,/,g:${SUBDIREPS_FILTER:Uu}}
+.endif
+# we just dealt with it, if we leave it defined,
+# dirdeps.mk will compute some interesting combinations.
+.undef ALL_MACHINES
+
+DEP_RELDIR = ${RELDIR}
+.include <dirdeps.mk>
+.endif
+.endif
+.else
+all: .PHONY
+.endif
+
+.endif
diff --git a/share/mk/meta.sys.mk b/share/mk/meta.sys.mk
new file mode 100644
index 000000000000..379e3385f3fb
--- /dev/null
+++ b/share/mk/meta.sys.mk
@@ -0,0 +1,139 @@
+# $Id: meta.sys.mk,v 1.14 2011/10/02 00:40:56 sjg Exp $
+
+#
+# @(#) Copyright (c) 2010, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+# include this if you want to enable meta mode
+# for maximum benefit, requires filemon(4) driver.
+
+.if ${MAKE_VERSION:U0} > 20100901
+.if !target(.ERROR)
+
+
+META_MODE += meta verbose
+.MAKE.MODE ?= ${META_MODE}
+
+.if ${.MAKE.LEVEL} == 0
+_make_mode := ${.MAKE.MODE} ${META_MODE}
+.if ${_make_mode:M*read*} != "" || ${_make_mode:M*nofilemon*} != ""
+# tell everyone we are not updating Makefile.depend*
+UPDATE_DEPENDFILE = NO
+.export UPDATE_DEPENDFILE
+.endif
+.if ${UPDATE_DEPENDFILE:Uyes:tl} == "no" && !exists(/dev/filemon)
+# we should not get upset
+META_MODE += nofilemon
+.export META_MODE
+.endif
+.endif
+
+.if !defined(NO_SILENT)
+.if ${MAKE_VERSION} > 20110818
+# only be silent when we have a .meta file
+META_MODE += silent=yes
+.else
+.SILENT:
+.endif
+.endif
+
+# make defaults .MAKE.DEPENDFILE to .depend
+# that won't work for us.
+.if ${.MAKE.DEPENDFILE} == ".depend"
+.undef .MAKE.DEPENDFILE
+.endif
+
+# if you don't cross build for multiple MACHINEs concurrently, then
+# .MAKE.DEPENDFILE = Makefile.depend
+# probably makes sense - you can set that in local.sys.mk
+.MAKE.DEPENDFILE ?= Makefile.depend.${MACHINE}
+
+# we use the pseudo machine "host" for the build host.
+# this should be taken care of before we get here
+.if ${OBJTOP:Ua} == ${HOST_OBJTOP:Ub}
+MACHINE = host
+.endif
+
+.if ${.MAKE.LEVEL} == 0
+# it can be handy to know which MACHINE kicked off the build
+# for example, if using Makefild.depend for multiple machines,
+# allowing only MACHINE0 to update can keep things simple.
+MACHINE0 := ${MACHINE}
+
+.if defined(PYTHON) && exists(${PYTHON})
+# we prefer the python version of this - it is much faster
+META2DEPS ?= ${.PARSEDIR}/meta2deps.py
+.else
+META2DEPS ?= ${.PARSEDIR}/meta2deps.sh
+.endif
+META2DEPS := ${META2DEPS}
+.export META2DEPS
+.endif
+
+MAKE_PRINT_VAR_ON_ERROR += \
+ .ERROR_TARGET \
+ .ERROR_META_FILE \
+ .MAKE.LEVEL \
+ MAKEFILE \
+ .MAKE.MODE
+
+.if !defined(SB) && defined(SRCTOP)
+SB = ${SRCTOP:H}
+.endif
+ERROR_LOGDIR ?= ${SB}/error
+meta_error_log = ${ERROR_LOGDIR}/meta-${.MAKE.PID}.log
+
+# we are not interested in make telling us a failure happened elsewhere
+.ERROR: _metaError
+_metaError: .NOMETA .NOTMAIN
+ -@[ "${.ERROR_META_FILE}" ] && { \
+ grep -q 'failure has been detected in another branch' ${.ERROR_META_FILE} && exit 0; \
+ mkdir -p ${meta_error_log:H}; \
+ cp ${.ERROR_META_FILE} ${meta_error_log}; \
+ echo "ERROR: log ${meta_error_log}" >&2; }; :
+
+.endif
+
+# Are we, after all, in meta mode?
+.if ${.MAKE.MODE:Mmeta*} != ""
+MKDEP = meta.autodep
+
+.if ${.MAKE.LEVEL} == 0
+# make sure dirdeps target exists and do it first
+all: dirdeps .WAIT
+dirdeps:
+.NOPATH: dirdeps
+
+.if defined(ALL_MACHINES)
+# the first .MAIN: is what counts
+# by default dirdeps is all we want at level0
+.MAIN: dirdeps
+# tell dirdeps.mk what we want
+BUILD_AT_LEVEL0 = no
+.endif
+
+.if ${.MAKE.DEPENDFILE:E} == ${MACHINE}
+# it works best if we do everything via sub-makes
+BUILD_AT_LEVEL0 ?= no
+.endif
+BUILD_AT_LEVEL0 ?= yes
+.endif
+
+# if we think we are updating dependencies,
+# then filemon had better be present
+.if ${UPDATE_DEPENDFILE:Uyes:tl} != "no" && !exists(/dev/filemon)
+.error ${.newline}ERROR: The filemon module (/dev/filemon) is not loaded.
+.endif
+
+.endif
+.endif
diff --git a/share/mk/meta2deps.py b/share/mk/meta2deps.py
new file mode 100755
index 000000000000..cb6d3213b221
--- /dev/null
+++ b/share/mk/meta2deps.py
@@ -0,0 +1,614 @@
+#!/usr/bin/env python
+
+"""
+This script parses each "meta" file and extracts the
+information needed to deduce build and src dependencies.
+
+It works much the same as the original shell script, but is
+*much* more efficient.
+
+The parsing work is handled by the class MetaFile.
+We only pay attention to a subset of the information in the
+"meta" files. Specifically:
+
+'CWD' to initialize our notion.
+
+'C' to track chdir(2) on a per process basis
+
+'R' files read are what we really care about.
+ directories read, provide a clue to resolving
+ subsequent relative paths. That is if we cannot find
+ them relative to 'cwd', we check relative to the last
+ dir read.
+
+'W' files opened for write or read-write,
+ for filemon V3 and earlier.
+
+'E' files executed.
+
+'L' files linked
+
+'V' the filemon version, this record is used as a clue
+ that we have reached the interesting bit.
+
+"""
+
+"""
+RCSid:
+ $Id: meta2deps.py,v 1.7 2012/11/06 05:44:03 sjg Exp $
+
+ Copyright (c) 2011, Juniper Networks, Inc.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+
+import os, re, sys
+
+def getv(dict, key, d=None):
+ """Lookup key in dict and return value or the supplied default."""
+ if key in dict:
+ return dict[key]
+ return d
+
+def resolve(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
+ """
+ Return an absolute path, resolving via cwd or last_dir if needed.
+ """
+ if path.endswith('/.'):
+ path = path[0:-2]
+ if path[0] == '/':
+ return path
+ if path == '.':
+ return cwd
+ if path.startswith('./'):
+ return cwd + path[1:]
+ if last_dir == cwd:
+ last_dir = None
+ for d in [last_dir, cwd]:
+ if not d:
+ continue
+ p = '/'.join([d,path])
+ if debug > 2:
+ print >> debug_out, "looking for:", p,
+ if not os.path.exists(p):
+ if debug > 2:
+ print >> debug_out, "nope"
+ p = None
+ continue
+ if debug > 2:
+ print >> debug_out, "found:", p
+ return p
+ return None
+
+def abspath(path, cwd, last_dir=None, debug=0, debug_out=sys.stderr):
+ """
+ Return an absolute path, resolving via cwd or last_dir if needed.
+ this gets called a lot, so we try to avoid calling realpath
+ until we know we have something.
+ """
+ path = resolve(path, cwd, last_dir, debug, debug_out)
+ if path and (path.find('./') > 0 or
+ path.endswith('/..') or
+ os.path.islink(path)):
+ return os.path.realpath(path)
+ return path
+
+def sort_unique(list, cmp=None, key=None, reverse=False):
+ list.sort(cmp, key, reverse)
+ nl = []
+ le = None
+ for e in list:
+ if e == le:
+ continue
+ nl.append(e)
+ return nl
+
+class MetaFile:
+ """class to parse meta files generated by bmake."""
+
+ conf = None
+ dirdep_re = None
+ host_target = None
+ srctops = []
+ objroots = []
+
+ seen = {}
+ obj_deps = []
+ src_deps = []
+ file_deps = []
+
+ def __init__(self, name, conf={}):
+ """if name is set we will parse it now.
+ conf can have the follwing keys:
+
+ SRCTOPS list of tops of the src tree(s).
+
+ CURDIR the src directory 'bmake' was run from.
+
+ RELDIR the relative path from SRCTOP to CURDIR
+
+ MACHINE the machine we built for.
+ set to 'none' if we are not cross-building.
+
+ HOST_TARGET
+ when we build for the psuedo machine 'host'
+ the object tree uses HOST_TARGET rather than MACHINE.
+
+ OBJROOTS a list of the common prefix for all obj dirs it might
+ end in '/' or '-'.
+
+ DPDEPS names an optional file to which per file dependencies
+ will be appended.
+ For example if 'some/path/foo.h' is read from SRCTOP
+ then 'DPDEPS_some/path/foo.h +=' "RELDIR" is output.
+ This can allow 'bmake' to learn all the dirs within
+ the tree that depend on 'foo.h'
+
+ debug desired debug level
+
+ debug_out open file to send debug output to (sys.stderr)
+
+ """
+
+ self.name = name
+ self.debug = getv(conf, 'debug', 0)
+ self.debug_out = getv(conf, 'debug_out', sys.stderr)
+
+ if not self.conf:
+ # some of the steps below we want to do only once
+ self.conf = conf
+ self.host_target = getv(conf, 'HOST_TARGET')
+ for srctop in getv(conf, 'SRCTOPS', []):
+ if srctop[-1] != '/':
+ srctop += '/'
+ if not srctop in self.srctops:
+ self.srctops.append(srctop)
+ _srctop = os.path.realpath(srctop)
+ if _srctop[-1] != '/':
+ _srctop += '/'
+ if not _srctop in self.srctops:
+ self.srctops.append(_srctop)
+
+ for objroot in getv(conf, 'OBJROOTS', []):
+ if not objroot in self.objroots:
+ self.objroots.append(objroot)
+ _objroot = os.path.realpath(objroot)
+ if objroot[-1] == '/':
+ _objroot += '/'
+ if not _objroot in self.objroots:
+ self.objroots.append(_objroot)
+
+ if self.debug:
+ print >> self.debug_out, "host_target=", self.host_target
+ print >> self.debug_out, "srctops=", self.srctops
+ print >> self.debug_out, "objroots=", self.objroots
+
+ self.dirdep_re = re.compile(r'([^/]+)/(.+)')
+
+ self.curdir = getv(conf, 'CURDIR')
+ self.machine = getv(conf, 'MACHINE', '')
+ self.reldir = getv(conf, 'RELDIR')
+ self.dpdeps = getv(conf, 'DPDEPS')
+ if self.dpdeps and not self.reldir:
+ if self.debug:
+ print >> self.debug_out, "need reldir:",
+ if self.curdir:
+ srctop = self.find_top(self.curdir, self.srctops)
+ if srctop:
+ self.reldir = self.curdir.replace(srctop,'')
+ if self.debug:
+ print >> self.debug_out, self.reldir
+ if not self.reldir:
+ self.dpdeps = None # we cannot do it?
+
+ if name:
+ self.parse()
+
+ def reset(self):
+ """reset state if we are being passed meta files from multiple directories."""
+ self.seen = {}
+ self.obj_deps = []
+ self.src_deps = []
+ self.file_deps = []
+
+ def dirdeps(self, sep='\n'):
+ """return DIRDEPS"""
+ return sep.strip() + sep.join(self.obj_deps)
+
+ def src_dirdeps(self, sep='\n'):
+ """return SRC_DIRDEPS"""
+ return sep.strip() + sep.join(self.src_deps)
+
+ def file_depends(self, out=None):
+ """Append DPDEPS_${file} += ${RELDIR}
+ for each file we saw, to the output file."""
+ if not self.reldir:
+ return None
+ for f in sort_unique(self.file_deps):
+ print >> out, 'DPDEPS_%s += %s' % (f, self.reldir)
+
+ def seenit(self, dir):
+ """rememer that we have seen dir."""
+ self.seen[dir] = 1
+
+ def add(self, list, data, clue=''):
+ """add data to list if it isn't already there."""
+ if data not in list:
+ list.append(data)
+ if self.debug:
+ print >> self.debug_out, "%s: %sAdd: %s" % (self.name, clue, data)
+
+ def find_top(self, path, list):
+ """the logical tree may be split accross multiple trees"""
+ for top in list:
+ if path.startswith(top):
+ if self.debug > 2:
+ print >> self.debug_out, "found in", top
+ return top
+ return None
+
+ def find_obj(self, objroot, dir, path, input):
+ """return path within objroot, taking care of .dirdep files"""
+ ddep = None
+ for ddepf in [path + '.dirdep', dir + '/.dirdep']:
+ if not ddep and os.path.exists(ddepf):
+ ddep = open(ddepf, 'rb').readline().strip('# \n')
+ if self.debug > 1:
+ print >> self.debug_out, "found %s: %s\n" % (ddepf, ddep)
+ if ddep.endswith(self.machine):
+ ddep = ddep[0:-(1+len(self.machine))]
+
+ if not ddep:
+ # no .dirdeps, so remember that we've seen the raw input
+ self.seenit(input)
+ self.seenit(dir)
+ if self.machine == 'none':
+ if dir.startswith(objroot):
+ return dir.replace(objroot,'')
+ return None
+ m = self.dirdep_re.match(dir.replace(objroot,''))
+ if m:
+ ddep = m.group(2)
+ dmachine = m.group(1)
+ if dmachine != self.machine:
+ if not (self.machine == 'host' and
+ dmachine == self.host_target):
+ if self.debug > 2:
+ print >> self.debug_out, "adding .%s to %s" % (dmachine, ddep)
+ ddep += '.' + dmachine
+
+ return ddep
+
+ def parse(self, name=None, file=None):
+ """A meta file looks like:
+
+ # Meta data file "path"
+ CMD "command-line"
+ CWD "cwd"
+ TARGET "target"
+ -- command output --
+ -- filemon acquired metadata --
+ # buildmon version 3
+ V 3
+ C "pid" "cwd"
+ E "pid" "path"
+ F "pid" "child"
+ R "pid" "path"
+ W "pid" "path"
+ X "pid" "status"
+ D "pid" "path"
+ L "pid" "src" "target"
+ M "pid" "old" "new"
+ S "pid" "path"
+ # Bye bye
+
+ We go to some effort to avoid processing a dependency more than once.
+ Of the above record types only C,E,F,L,R,V and W are of interest.
+ """
+
+ version = 0 # unknown
+ if name:
+ self.name = name;
+ if file:
+ f = file
+ cwd = last_dir = self.cwd
+ else:
+ f = open(self.name, 'rb')
+ skip = True
+ pid_cwd = {}
+ pid_last_dir = {}
+ last_pid = 0
+
+ if self.curdir:
+ self.seenit(self.curdir) # we ignore this
+
+ interesting = 'CEFLRV'
+ for line in f:
+ # ignore anything we don't care about
+ if not line[0] in interesting:
+ continue
+ if self.debug > 2:
+ print >> self.debug_out, "input:", line,
+ w = line.split()
+
+ if skip:
+ if w[0] == 'V':
+ skip = False
+ version = int(w[1])
+ """
+ if version < 4:
+ # we cannot ignore 'W' records
+ # as they may be 'rw'
+ interesting += 'W'
+ """
+ elif w[0] == 'CWD':
+ self.cwd = cwd = last_dir = w[1]
+ self.seenit(cwd) # ignore this
+ if self.debug:
+ print >> self.debug_out, "%s: CWD=%s" % (self.name, cwd)
+ continue
+
+ pid = int(w[1])
+ if pid != last_pid:
+ if last_pid:
+ pid_cwd[last_pid] = cwd
+ pid_last_dir[last_pid] = last_dir
+ cwd = getv(pid_cwd, pid, self.cwd)
+ last_dir = getv(pid_last_dir, pid, self.cwd)
+ last_pid = pid
+
+ # process operations
+ if w[0] == 'F':
+ npid = int(w[2])
+ pid_cwd[npid] = cwd
+ pid_last_dir[npid] = cwd
+ last_pid = npid
+ continue
+ elif w[0] == 'C':
+ cwd = abspath(w[2], cwd, None, self.debug, self.debug_out)
+ if cwd.endswith('/.'):
+ cwd = cwd[0:-2]
+ last_dir = cwd
+ if self.debug > 1:
+ print >> self.debug_out, "cwd=", cwd
+ continue
+
+ if w[2] in self.seen:
+ if self.debug > 2:
+ print >> self.debug_out, "seen:", w[2]
+ continue
+ # file operations
+ if w[0] in 'ML':
+ path = w[2].strip("'")
+ else:
+ path = w[2]
+ # we are never interested in .dirdep files as dependencies
+ if path.endswith('.dirdep'):
+ continue
+ # we don't want to resolve the last component if it is
+ # a symlink
+ path = resolve(path, cwd, last_dir, self.debug, self.debug_out)
+ if not path:
+ continue
+ dir,base = os.path.split(path)
+ if dir in self.seen:
+ if self.debug > 2:
+ print >> self.debug_out, "seen:", dir
+ continue
+ # we can have a path in an objdir which is a link
+ # to the src dir, we may need to add dependencies for each
+ rdir = dir
+ dir = abspath(dir, cwd, last_dir, self.debug, self.debug_out)
+ if rdir == dir or rdir.find('./') > 0:
+ rdir = None
+ # now put path back together
+ path = '/'.join([dir,base])
+ if self.debug > 1:
+ print >> self.debug_out, "raw=%s rdir=%s dir=%s path=%s" % (w[2], rdir, dir, path)
+ if w[0] in 'SRWL':
+ if w[0] == 'W' and path.endswith('.dirdep'):
+ continue
+ if path in [last_dir, cwd, self.cwd, self.curdir]:
+ if self.debug > 1:
+ print >> self.debug_out, "skipping:", path
+ continue
+ if os.path.isdir(path):
+ if w[0] in 'RW':
+ last_dir = path;
+ if self.debug > 1:
+ print >> self.debug_out, "ldir=", last_dir
+ continue
+
+ if w[0] in 'REWML':
+ # finally, we get down to it
+ if dir == self.cwd or dir == self.curdir:
+ continue
+ srctop = self.find_top(path, self.srctops)
+ if srctop:
+ if self.dpdeps:
+ self.add(self.file_deps, path.replace(srctop,''), 'file')
+ self.add(self.src_deps, dir.replace(srctop,''), 'src')
+ self.seenit(w[2])
+ self.seenit(dir)
+ if rdir and not rdir.startswith(srctop):
+ dir = rdir # for below
+ rdir = None
+ else:
+ continue
+
+ objroot = None
+ for dir in [dir,rdir]:
+ if not dir:
+ continue
+ objroot = self.find_top(dir, self.objroots)
+ if objroot:
+ break
+ if objroot:
+ ddep = self.find_obj(objroot, dir, path, w[2])
+ if ddep:
+ self.add(self.obj_deps, ddep, 'obj')
+ else:
+ # don't waste time looking again
+ self.seenit(w[2])
+ self.seenit(dir)
+ if not file:
+ f.close()
+
+
+def main(argv, klass=MetaFile, xopts='', xoptf=None):
+ """Simple driver for class MetaFile.
+
+ Usage:
+ script [options] [key=value ...] "meta" ...
+
+ Options and key=value pairs contribute to the
+ dictionary passed to MetaFile.
+
+ -S "SRCTOP"
+ add "SRCTOP" to the "SRCTOPS" list.
+
+ -C "CURDIR"
+
+ -O "OBJROOT"
+ add "OBJROOT" to the "OBJROOTS" list.
+
+ -m "MACHINE"
+
+ -H "HOST_TARGET"
+
+ -D "DPDEPS"
+
+ -d bumps debug level
+
+ """
+ import getopt
+
+ # import Psyco if we can
+ # it can speed things up quite a bit
+ have_psyco = 0
+ try:
+ import psyco
+ psyco.full()
+ have_psyco = 1
+ except:
+ pass
+
+ conf = {
+ 'SRCTOPS': [],
+ 'OBJROOTS': [],
+ }
+
+ try:
+ machine = os.environ['MACHINE']
+ if machine:
+ conf['MACHINE'] = machine
+ srctop = os.environ['SB_SRC']
+ if srctop:
+ conf['SRCTOPS'].append(srctop)
+ objroot = os.environ['SB_OBJROOT']
+ if objroot:
+ conf['OBJROOTS'].append(objroot)
+ except:
+ pass
+
+ debug = 0
+ output = True
+
+ opts, args = getopt.getopt(argv[1:], 'dS:C:O:R:m:D:H:q' + xopts)
+ for o, a in opts:
+ if o == '-d':
+ debug += 1
+ elif o == '-q':
+ output = False
+ elif o == '-H':
+ conf['HOST_TARGET'] = a
+ elif o == '-S':
+ if a not in conf['SRCTOPS']:
+ conf['SRCTOPS'].append(a)
+ elif o == '-C':
+ conf['CURDIR'] = a
+ elif o == '-O':
+ if a not in conf['OBJROOTS']:
+ conf['OBJROOTS'].append(a)
+ elif o == '-R':
+ conf['RELDIR'] = a
+ elif o == '-D':
+ conf['DPDEPS'] = a
+ elif o == '-m':
+ conf['MACHINE'] = a
+ elif xoptf:
+ xoptf(o, a, conf)
+
+ conf['debug'] = debug
+
+ # get any var=val assignments
+ eaten = []
+ for a in args:
+ if a.find('=') > 0:
+ k,v = a.split('=')
+ if k in ['SRCTOP','OBJROOT','SRCTOPS','OBJROOTS']:
+ if k == 'SRCTOP':
+ k = 'SRCTOPS'
+ elif k == 'OBJROOT':
+ k = 'OBJROOTS'
+ if v not in conf[k]:
+ conf[k].append(v)
+ else:
+ conf[k] = v
+ eaten.append(a)
+ continue
+ break
+
+ for a in eaten:
+ args.remove(a)
+
+ debug_out = getv(conf, 'debug_out', sys.stderr)
+
+ if debug:
+ print >> debug_out, "config:"
+ print >> debug_out, "psyco=", have_psyco
+ for k,v in conf.items():
+ print >> debug_out, "%s=%s" % (k,v)
+
+ for a in args:
+ m = klass(a, conf)
+
+ if output:
+ print m.dirdeps()
+
+ print m.src_dirdeps('\nsrc:')
+
+ dpdeps = getv(conf, 'DPDEPS')
+ if dpdeps:
+ m.file_depends(open(dpdeps, 'wb'))
+
+ return m
+
+if __name__ == '__main__':
+ try:
+ main(sys.argv)
+ except:
+ # yes, this goes to stdout
+ print "ERROR: ", sys.exc_info()[1]
+ raise
+
diff --git a/share/mk/meta2deps.sh b/share/mk/meta2deps.sh
new file mode 100755
index 000000000000..2fec368103bc
--- /dev/null
+++ b/share/mk/meta2deps.sh
@@ -0,0 +1,306 @@
+#!/bin/sh
+
+# NAME:
+# meta2deps.sh - extract useful info from .meta files
+#
+# SYNOPSIS:
+# meta2deps.sh SB="SB" "meta" ...
+#
+# DESCRIPTION:
+# This script looks each "meta" file and extracts the
+# information needed to deduce build and src dependencies.
+#
+# To do this, we extract the 'CWD' record as well as all the
+# syscall traces which describe 'R'ead, 'C'hdir and 'E'xec
+# syscalls.
+#
+# The typical meta file looks like::
+#.nf
+#
+# # Meta data file "path"
+# CMD "command-line"
+# CWD "cwd"
+# TARGET "target"
+# -- command output --
+# -- filemon acquired metadata --
+# # buildmon version 2
+# V 2
+# E "pid" "path"
+# R "pid" "path"
+# C "pid" "cwd"
+# R "pid" "path"
+# X "pid" "status"
+#.fi
+#
+# The fact that all the syscall entry lines start with a single
+# character make these files quite easy to process using sed(1).
+#
+# To simplify the logic the 'CWD' line is made to look like a
+# normal 'C'hdir entry, and "cwd" is remembered so that it can
+# be prefixed to any "path" which is not absolute.
+#
+# If the "path" being read ends in '.srcrel' it is the content
+# of (actually the first line of) that file that we are
+# interested in.
+#
+# Any "path" which lies outside of the sandbox "SB" is generally
+# not of interest and is ignored.
+#
+# The output, is a set of absolute paths with "SB" like:
+#.nf
+#
+# $SB/obj-i386/bsd/gnu/lib/csu
+# $SB/obj-i386/bsd/gnu/lib/libgcc
+# $SB/obj-i386/bsd/include
+# $SB/obj-i386/bsd/lib/csu/i386-elf
+# $SB/obj-i386/bsd/lib/libc
+# $SB/src/bsd/include
+# $SB/src/bsd/sys/i386/include
+# $SB/src/bsd/sys/sys
+# $SB/src/pan-release/rtsock
+# $SB/src/pfe-shared/include/jnx
+#.fi
+#
+# Which can then be further processed by 'gendirdeps.mk'
+#
+# If we are passed 'DPDEPS='"dpdeps", then for each src file
+# outside of "CURDIR" we read, we output a line like:
+#.nf
+#
+# DPDEPS_$path += $RELDIR
+#.fi
+#
+# with "$path" geting turned into reldir's, so that we can end
+# up with a list of all the directories which depend on each src
+# file in another directory. This can allow for efficient yet
+# complete testing of changes.
+
+
+# RCSid:
+# $Id: meta2deps.sh,v 1.2 2011/10/02 00:34:47 sjg Exp $
+
+# Copyright (c) 2010, Juniper Networks, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+meta2src() {
+ cat /dev/null "$@" |
+ sed -n '/^R .*\.[chyl]$/s,^..[0-9]* ,,p' |
+ sort -u
+}
+
+meta2dirs() {
+ cat /dev/null "$@" |
+ sed -n '/^R .*\/.*\.[a-z0-9][^\/]*$/s,^..[0-9]* \(.*\)/[^/]*$,\1,p' |
+ sort -u
+}
+
+meta2deps() {
+ DPDEPS=
+ while :
+ do
+ case "$1" in
+ *=*) eval export "$1"; shift;;
+ *) break;;
+ esac
+ done
+
+ [ -z "$RELDIR" ] && unset DPDEPS
+ tf=/tmp/m2d$$-$USER
+ rm -f $tf.*
+ trap 'rm -f $tf.*; trap 0' 0
+
+ > $tf.dirdep
+ > $tf.qual
+ > $tf.srcdep
+ > $tf.srcrel
+ > $tf.dpdeps
+
+ seenit=
+ seensrc=
+ lpid=
+ cat /dev/null "$@" |
+ sed -e 's,^CWD,C C,;/^[CREFL] /!d' -e "s,',,g" |
+ while read op pid path junk
+ do
+ : op=$op pid=$pid path=$path
+ # we track cwd and ldir (of interest) per pid
+ # CWD is bmake's cwd
+ case "$lpid,$pid" in
+ ,C) CWD=$path cwd=$path ldir=$path
+ if [ -z "$SB" ]; then
+ SB=`echo $CWD | sed 's,/obj.*,,'`
+ fi
+ SRCTOP=${SRCTOP:-$SB/src}
+ continue
+ ;;
+ $pid,$pid) ;;
+ *)
+ case "$lpid" in
+ "") ;;
+ *) eval ldir_$lpid=$ldir cwd_$lpid=$cwd;;
+ esac
+ eval ldir=\${ldir_$pid:-$CWD} cwd=\${cwd_$pid:-$CWD}
+ lpid=$pid
+ ;;
+ esac
+
+ case "$op,$path" in
+ W,*srcrel) continue;;
+ C,*)
+ case "$path" in
+ /*) cwd=$path;;
+ *) cwd=`cd $cwd/$path 2> /dev/null && /bin/pwd`;;
+ esac
+ # watch out for temp dirs that no longer exist
+ test -d ${cwd:-/dev/null/no/such} || cwd=$CWD
+ continue
+ ;;
+ F,*) eval cwd_$path=$cwd ldir_$path=$ldir
+ continue
+ ;;
+ *) dir=${path%/*}
+ case "$path" in
+ $SB/*|${SB_BACKING_SB:-$SB}/*) ;;
+ $SB_OBJROOT*) ;;
+ /*/stage/*) ;;
+ /*) continue;;
+ *) for path in $ldir/$path $cwd/$path
+ do
+ test -e $path && break
+ done
+ dir=${path%/*}
+ ;;
+ esac
+ ;;
+ esac
+ # avoid repeating ourselves...
+ case "$DPDEPS,$seensrc," in
+ ,*)
+ case ",$seenit," in
+ *,$dir,*) continue;;
+ esac
+ ;;
+ *,$path,*) continue;;
+ esac
+ # canonicalize if needed
+ case "/$dir/" in
+ */../*|*/./*)
+ rdir=$dir
+ dir=`cd $dir 2> /dev/null && /bin/pwd`
+ seen="$rdir,$dir"
+ ;;
+ *) seen=$dir;;
+ esac
+ case "$dir" in
+ ${CURDIR:-.}|${CURDIR:-.}/*|"") continue;;
+ $SRCTOP/*|${SB_BACKING_SB:-$SB}/src/*)
+ # avoid repeating ourselves...
+ case "$DPDEPS,$seensrc," in
+ ,*)
+ case ",$seenit," in
+ *,$dir,*) continue;;
+ esac
+ ;;
+ esac
+ ;;
+ *)
+ case ",$seenit," in
+ *,$dir,*) continue;;
+ esac
+ ;;
+ esac
+ if [ -d $path ]; then
+ case "$path" in
+ */..) ldir=${dir%/*};;
+ *) ldir=$path;;
+ esac
+ continue
+ fi
+ [ -f $path ] || continue
+ case "$dir" in
+ $CWD) continue;; # ignore
+ $SRCTOP/*|${SB_BACKING_SB:-$SB}/src/*)
+ seenit="$seenit,$seen"
+ echo $dir >> $tf.srcdep
+ case "$DPDEPS,$reldir,$seensrc," in
+ ,*) ;;
+ *) seensrc="$seensrc,$path"
+ echo "DPDEPS_$dir/${path##*/} += $RELDIR" >> $tf.dpdeps
+ ;;
+ esac
+ continue
+ ;;
+ esac
+ # if there is a .dirdep we cannot skip
+ # just because we've seen the dir before.
+ if [ -s $path.dirdep ]; then
+ # this file contains:
+ # '# ${RELDIR}.<machine>'
+ echo $path.dirdep >> $tf.qual
+ continue
+ elif [ -s $dir.dirdep ]; then
+ echo $dir.dirdep >> $tf.qual
+ seenit="$seenit,$seen"
+ continue
+ fi
+ seenit="$seenit,$seen"
+ case "$dir" in
+ $SB/*|${SB_OBJROOT:-$SB/}*|${SB_BACKING_SB:-$SB}/*)
+ echo $dir;;
+ esac
+ done > $tf.dirdep
+ _nl=echo
+ for f in $tf.dirdep $tf.qual $tf.srcdep
+ do
+ [ -s $f ] || continue
+ case $f in
+ *qual) # a list of .dirdep files
+ # we can prefix everthing with $OBJTOP to
+ # tell gendirdeps.mk that these are
+ # DIRDEP entries, since they are already
+ # qualified with .<machine> as needed.
+ # We strip .$MACHINE though
+ xargs cat < $f | sort -u |
+ sed "s,^# ,,;s,^,$OBJTOP/,;s,\.$MACHINE\$,,"
+ ;;
+ *) sort -u $f;;
+ esac
+ _nl=:
+ done
+ if [ -s $tf.dpdeps ]; then
+ case "$DPDEPS" in
+ */*) ;;
+ *) echo > $DPDEPS;; # the echo is needed!
+ esac
+ sort -u $tf.dpdeps |
+ sed "s,${SRCTOP}/,,;s,${SB_BACKING_SB:-$SB}/src/,," >> $DPDEPS
+ fi
+ # ensure we produce _something_ else egrep -v gets upset
+ $_nl
+}
+
+case /$0 in
+*/meta2dep*) meta2deps "$@";;
+*/meta2dirs*) meta2dirs "$@";;
+*/meta2src*) meta2src "$@";;
+esac
diff --git a/share/mk/sys.dependfile.mk b/share/mk/sys.dependfile.mk
new file mode 100644
index 000000000000..432cc4fabb98
--- /dev/null
+++ b/share/mk/sys.dependfile.mk
@@ -0,0 +1,47 @@
+# $Id: sys.dependfile.mk,v 1.3 2012/04/25 15:45:04 sjg Exp $
+#
+# @(#) Copyright (c) 2012, Simon J. Gerraty
+#
+# This file is provided in the hope that it will
+# be of use. There is absolutely NO WARRANTY.
+# Permission to copy, redistribute or otherwise
+# use this file is hereby granted provided that
+# the above copyright notice and this notice are
+# left intact.
+#
+# Please send copies of changes and bug-fixes to:
+# sjg@crufty.net
+#
+
+# This only makes sense in meta mode.
+# This allows a mixture of auto generated as well as manually edited
+# dependency files, which can be differentiated by their names.
+# As per dirdeps.mk we only require:
+# 1. a common prefix
+# 2. that machine specific files end in .${MACHINE}
+#
+# The .MAKE.DEPENDFILE_PREFERENCE below is an example.
+
+# All depend file names should start with this
+.MAKE.DEPENDFILE_PREFIX ?= Makefile.depend
+
+# The order of preference: we will use the first one of these we find
+# otherwise the 1st entry will be used by default.
+.MAKE.DEPENDFILE_PREFERENCE ?= \
+ ${.CURDIR}/${.MAKE.DEPENDFILE_PREFIX}.${MACHINE} \
+ ${.CURDIR}/${.MAKE.DEPENDFILE_PREFIX}
+
+_e := ${.MAKE.DEPENDFILE_PREFERENCE:@m@${exists($m):?$m:}@}
+.if !empty(_e)
+.MAKE.DEPENDFILE := ${_e:[1]}
+.elif ${.MAKE.DEPENDFILE_PREFERENCE:M*${MACHINE}} != "" && ${.MAKE.DEPENDFILE_PREFERENCE:[1]:E} != ${MACHINE}
+# MACHINE specific depend files are supported, but *not* default.
+# If any already exist, we should follow suit.
+_aml = ${ALL_MACHINE_LIST:Uarm amd64 i386 powerpc:N${MACHINE}} ${MACHINE}
+# MACHINE must be the last entry in _aml ;-)
+_e := ${_aml:@MACHINE@${.MAKE.DEPENDFILE_PREFERENCE:@m@${exists($m):?$m:}@}@}
+.if !empty(_e)
+.MAKE.DEPENDFILE ?= ${.MAKE.DEPENDFILE_PREFERENCE:M*${MACHINE}:[1]}
+.endif
+.endif
+.MAKE.DEPENDFILE ?= ${.MAKE.DEPENDFILE_PREFERENCE:[1]}