CONTRIB.build/    = $(BUILD/)contrib/
CONTRIB.download/ = $(SRC/)download/
CONTRIB.host      = $(if $(filter 1,$(BUILD.cross)),$(BUILD.spec))
CONTRIB.spec      = $(if $(filter 1,$(BUILD.cross)),$(HOST.spec))

###############################################################################

##
## $(1) = module name (uppercase)
##
define import.CONTRIB.defs
    ##
    ## keep a list of the enabled contrib packages
    ##
    CONTRIBS += $(1)

    ##
    ## import gcc/g++ support mainly so we can force contrib choice of
    ## gcc executable, and debug/optimization flags.
    ##
    $$(eval $$(call import.GCC,$(1)))

    ##
    ## common values useful across targets
    ##
    $(1).src/   = $$(SRC/)contrib/$($(1).dir)/
    $(1).build/ = $$(CONTRIB.build/)$($(1).dir)/
    ## add prerequisites and autotool modules for all contribs
    $(1).deps   = $$(foreach n,$($(1).prerequisites),$$($$n.INSTALL.target))
    $(1).build_dir =

    ##
    ## target: fetch
    ##
    $(1).FETCH.url      = FETCH_URL_IS_UNDEFINED
    $(1).FETCH.basename = $$(notdir $$(firstword $$($(1).FETCH.url)))
    $(1).FETCH.distfile = $$(CONTRIB.download/)$$($(1).FETCH.basename)
    $(1).FETCH.target   = $$($(1).FETCH.distfile)
    define $(1).FETCH
        $$(DF.FETCH.exe) --config $(BUILD/)distfile.cfg $$(if $$($(1).FETCH.sha256),--sha256 $$($(1).FETCH.sha256)) --output $$@ $$($(1).FETCH.url)
    endef
    define $(1).FETCH.test
        $$(DF.FETCH.exe) --config $(BUILD/)distfile.cfg $$(if $$($(1).FETCH.sha256),--sha256 $$($(1).FETCH.sha256)) --exhaust-url $$($(1).FETCH.url)
    endef

    ##
    ## target: verify
    ##
    $(1).VERIFY.target = $$($(1).build/).stamp.$$($(1).name).verify
    define $(1).VERIFY
        $$(DF.VERIFY.exe) --config $(BUILD/)distfile.cfg $$(if $$($(1).FETCH.sha256),--sha256 $$($(1).FETCH.sha256)) $$($(1).FETCH.distfile)
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: extract
    ##
    $(1).EXTRACT.tarbase = $$(strip $$(foreach x,tar.bz2 tar.gz,$$(patsubst %.$$(x),%,$$(filter %.$$(x),$$($(1).FETCH.basename)))))
    $(1).EXTRACT.dir/    = $$($(1).build/)$$($(1).EXTRACT.tarbase)/
    $(1).EXTRACT.target  = $$($(1).build/).stamp.$$($(1).name).extract
    define $(1).EXTRACT
        $$(RM.exe) -fr $$($(1).EXTRACT.dir/)
        $$(TAR.exe) xfC $$($(1).FETCH.distfile) $$($(1).build/)
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: patch
    ##
    $(1).PATCH.srcs = $$(sort $$(wildcard \
        $$($(1).src/)A??-*.patch \
        $$($(1).src/)P??-$$(BUILD.system)*.patch ))

    # extra line feed is required
    define $(1).PATCH.item
        $$(PATCH.exe) -t -N -p1 -d $$(1) < $$(2)

    endef

    $(1).PATCH.target = $$($(1).build/).stamp.$$($(1).name).patch
    define $(1).PATCH
        $$(foreach p,$$($(1).PATCH.srcs),$$(call $(1).PATCH.item,$$($(1).EXTRACT.dir/),$$(p)))
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: configure
    ##
    $(1).CONFIGURE.sete       = set -e;
    $(1).CONFIGURE.dir        = $$($(1).EXTRACT.dir/)$$($(1).build_dir)
    $(1).CONFIGURE.bootstrap  =
    $(1).CONFIGURE.exe        = ./configure
    $(1).CONFIGURE.host       = $$(CONTRIB.host)
    $(1).CONFIGURE.build      = $$(CONTRIB.spec)
    $(1).CONFIGURE.prefix     = $$(call fn.ABSOLUTE,$$(CONTRIB.build/))
    $(1).CONFIGURE.deps       = --disable-dependency-tracking
    $(1).CONFIGURE.shared     = --disable-shared
    $(1).CONFIGURE.static     = --enable-static
    $(1).CONFIGURE.extra      =

    $(1).CONFIGURE.args.dir    = $$(MKDIR.exe) -p $$(1); cd $$(1);
    $(1).CONFIGURE.args.host   = --host=$$(1)
    $(1).CONFIGURE.args.build  = --build=$$(1)
    $(1).CONFIGURE.args.prefix = --prefix=$$(1)

    $(1).CONFIGURE.args = !sete @dir !bootstrap !env !exe @host @build @prefix !deps !shared !static !extra

    $(1).CONFIGURE.env.LOCAL_PATH =
    $(1).CONFIGURE.env.CC       = CC=$$($(1).GCC.gcc)
    $(1).CONFIGURE.env.CXX      = CXX=$$($(1).GCC.gxx)
    ##
    ## Only add debug and optimization flags to contribs when 
    ## debug=max or optimizations=none.  Otherwise, use the contribs defaults
    ifeq (max,$$($(1).GCC.g))
        ifeq (none,$$($(1).GCC.O))
            $(1).CONFIGURE.env.CFLAGS   = CFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?c_std ?extra .g .O *D)"
            $(1).CONFIGURE.env.CXXFLAGS = CXXFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?cxx_std ?extra .g .O *D)"
        else
            $(1).CONFIGURE.env.CFLAGS   = CFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?c_std ?extra .g *D)"
            $(1).CONFIGURE.env.CXXFLAGS = CXXFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?cxx_std ?extra .g *D)"
        endif
    else
        $(1).CONFIGURE.env.CFLAGS   = CFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?c_std ?extra *D)"
        $(1).CONFIGURE.env.CXXFLAGS = CXXFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?cxx_std ?extra *D)"
    endif
    $(1).CONFIGURE.env.CPPFLAGS = CPPFLAGS="-I$$(call fn.ABSOLUTE,$(CONTRIB.build/))include $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver *D)"
    $(1).CONFIGURE.env.LDFLAGS  = LDFLAGS="-L$$(call fn.ABSOLUTE,$(CONTRIB.build/))lib $$(call fn.ARGS,$(1).GCC,*archs *sysroot *minver ?extra.exe *D)"
    $(1).CONFIGURE.env.PKG_CONFIG_PATH  = PKG_CONFIG_PATH="$$(call fn.ABSOLUTE,$$(CONTRIB.build/))lib/pkgconfig"

    $(1).CONFIGURE.env.args = !CC !CFLAGS !CXX !CXXFLAGS !CPPFLAGS !LD !LDFLAGS !PKG_CONFIG_PATH !LOCAL_PATH !CROSS
    $(1).CONFIGURE.env = $$(call fn.ARGS,$(1).CONFIGURE.env,$$($(1).CONFIGURE.env.args))

    $(1).CONFIGURE.target = $$($(1).build/).stamp.$$($(1).name).configure
    define $(1).CONFIGURE
        $$(call fn.ARGS,$(1).CONFIGURE,$$($(1).CONFIGURE.args))
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: build
    ##
    $(1).BUILD.env      =
    $(1).BUILD.make     = $$(MAKE)
    $(1).BUILD.dir      = $$($(1).EXTRACT.dir/)$$($(1).build_dir)
    $(1).BUILD.extra    =
    $(1).BUILD.ntargets =

    $(1).BUILD.args = !env !make @dir !extra !ntargets
    $(1).BUILD.args.dir = -C $$(1)

    $(1).BUILD.target = $$($(1).build/).stamp.$$($(1).name).build
    define $(1).BUILD
        $$(call fn.ARGS,$(1).BUILD,$$($(1).BUILD.args))
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: install
    ##
    $(1).INSTALL.make     = $$(MAKE)
    $(1).INSTALL.dir      = $$($(1).EXTRACT.dir/)$$($(1).build_dir)
    $(1).INSTALL.extra    =
    $(1).INSTALL.ntargets =

    $(1).INSTALL.args = !make @dir !extra !ntargets
    $(1).INSTALL.args.dir = -j 1 -C $$(1) install

    $(1).INSTALL.mkdirs = $$(CONTRIB.build/)lib/ $$(CONTRIB.build/)include/
    $(1).INSTALL.target = $$($(1).build/).stamp.$$($(1).name).install
    define $(1).INSTALL
        $$(call fn.ARGS,$(1).INSTALL,$$($(1).INSTALL.args))
        $$(TOUCH.exe) $$@
    endef

    ##
    ## target: uninstall
    ##
    $(1).UNINSTALL.make     = $$(MAKE)
    $(1).UNINSTALL.dir      = $$($(1).EXTRACT.dir/)$$($(1).build_dir)
    $(1).UNINSTALL.extra    =
    $(1).UNINSTALL.ntargets = uninstall

    $(1).UNINSTALL.args = !make @dir !extra !ntargets
    $(1).UNINSTALL.args.dir = -C $$(1)

    define $(1).UNINSTALL
        $$(call fn.ARGS,$(1).UNINSTALL,$$($(1).UNINSTALL.args))
        $$(RM.exe) -f $$($(1).INSTALL.target)
    endef

    ##
    ## target: clean
    ##
    $(1).CLEAN.make     = $$(MAKE)
    $(1).CLEAN.dir      = $$($(1).EXTRACT.dir/)$$($(1).build_dir)
    $(1).CLEAN.extra    =
    $(1).CLEAN.ntargets = clean

    $(1).CLEAN.args = !make @dir !extra !ntargets
    $(1).CLEAN.args.dir = -C $$(1)

    define $(1).CLEAN
        $$(call fn.ARGS,$(1).CLEAN,$$($(1).CLEAN.args))
        $$(RM.exe) -f $$($(1).BUILD.target)
    endef

    define $(1).XCLEAN
	    $$(RM.exe) -fr $$($(1).build/)
    endef

    ##
    ## other values used to aid prerequisite dirs and cleanup
    ##
    $(1).out += $$($(1).build/)
    $(1).out += $$($(1).FETCH.target)
    $(1).out += $$($(1).EXTRACT.target)
    $(1).out += $$($(1).PATCH.target)
    $(1).out += $$($(1).CONFIGURE.target)
    $(1).out += $$($(1).BUILD.target)
    $(1).out += $$($(1).INSTALL.mkdirs)
    $(1).out += $$($(1).INSTALL.target)

    BUILD.out += $$($(1).out)
endef

###############################################################################

##
## $(1) = module name
##
define import.CONTRIB.rules

##
## target: fetch
##
$($(1).name).fetch: $$($(1).FETCH.target)

$$($(1).FETCH.target): | $$(dir $$($(1).FETCH.target))
	@$$($(1).FETCH)

$($(1).name).fetch.test:
	@$$($(1).FETCH.test)

##
## target: verify
##
$($(1).name).verify: $$($(1).VERIFY.target)

$$($(1).VERIFY.target): | $$(dir $$($(1).VERIFY.target))
$$($(1).VERIFY.target): $$($(1).FETCH.target)
	@$$($(1).VERIFY)

$($(1).name).verify.touch:
	$$(TOUCH.exe) $$($(1).VERIFY.target)

$($(1).name).verify.untouch:
	$$(RM.exe) -f $$($(1).VERIFY.target)

##
## target: extract
## must touch dir after extraction because old timestamp is restored via tar.
##
$($(1).name).extract: $$($(1).EXTRACT.target)

$$($(1).EXTRACT.target): | $$(dir $$($(1).EXTRACT.target))
$$($(1).EXTRACT.target): $$($(1).VERIFY.target)
	$$($(1).EXTRACT)

$($(1).name).extract.touch:
	$$(TOUCH.exe) $$($(1).EXTRACT.target)

$($(1).name).extract.untouch:
	$$(RM.exe) -f $$($(1).EXTRACT.target)

##
## target: patch
##
$($(1).name).patch: $$($(1).PATCH.target)

$$($(1).PATCH.target): | $$(dir $$($(1).PATCH.target))
$$($(1).PATCH.target): $$($(1).EXTRACT.target)
	$$($(1).PATCH)

$($(1).name).patch.touch:
	$$(TOUCH.exe) $$($(1).PATCH.target)

$($(1).name).patch.untouch:
	$$(RM.exe) -f $$($(1).PATCH.target)

##
## target: configure
##
$($(1).name).configure: $$($(1).CONFIGURE.target)

$$($(1).CONFIGURE.target): | $$(dir $$($(1).CONFIGURE.target))
$$($(1).CONFIGURE.target): $$($(1).deps)
$$($(1).CONFIGURE.target): $$($(1).PATCH.target)
	$$($(1).CONFIGURE)

$($(1).name).configure.touch:
	$$(TOUCH.exe) $$($(1).CONFIGURE.target)

$($(1).name).configure.untouch:
	$$(RM.exe) -f $$($(1).CONFIGURE.target)

##
## target: build
##
$($(1).name).build: $$($(1).BUILD.target)

$$($(1).BUILD.target): | $$(dir $$($(1).BUILD.target))
$$($(1).BUILD.target): $$($(1).CONFIGURE.target)
	-$$($(1).CLEAN)
	+$$($(1).BUILD)

$($(1).name).build.touch:
	$$(TOUCH.exe) $$($(1).BUILD.target)

$($(1).name).build.untouch:
	$$(RM.exe) -f $$($(1).BUILD.target)

##
## target: install
##
$($(1).name).install: $$($(1).INSTALL.target)

$$($(1).INSTALL.target): | $$(dir $$($(1).INSTALL.target)) $$($(1).INSTALL.mkdirs)
$$($(1).INSTALL.target): $$($(1).BUILD.target)
	$$($(1).INSTALL)

$($(1).name).install.touch:
	$$(TOUCH.exe) $$($(1).INSTALL.target)

$($(1).name).install.untouch:
	$$(RM.exe) -f $$($(1).INSTALL.target)

##
## target: uninstall
##
$($(1).name).uninstall:
	-$$($(1).UNINSTALL)

##
## target: clean
##
$($(1).name).clean:
	-$$($(1).CLEAN)

##
## target: xclean
##
$($(1).name).xclean: $($(1).name).uninstall
	-$$($(1).XCLEAN)

##
## alias: module name is same as build
##
$($(1).name): $($(1).name).build

##
## participate with global convenience targets
##
contrib.fetch: $($(1).name).fetch
contrib.fetch.test: $($(1).name).fetch.test
contrib.verify: $($(1).name).verify
contrib.verify.touch: $($(1).name).verify.touch
contrib.verify.untouch: $($(1).name).verify.untouch
contrib.extract: $($(1).name).extract
contrib.patch: $($(1).name).patch
contrib.configure: $($(1).name).configure
contrib.build: $($(1).name).build
contrib.install: $($(1).name).install
contrib.uninstall: $($(1).name).uninstall
contrib.clean: $($(1).name).clean
contrib.xclean: $($(1).name).xclean

endef
