#============================================================================
# Rules for plugin creation
# Copyright (C)2003 by Matze Braun <matzebraun@users.sourceforge.net>
#
#    This library is free software; you can redistribute it and/or modify it
#    under the terms of the GNU Library General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or (at your
#    option) any later version.
#
#    This library is distributed in the hope that it will be useful, but
#    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
#    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
#    License for more details.
#
#    You should have received a copy of the GNU Library General Public License
#    along with this library; if not, write to the Free Software Foundation,
#    Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#============================================================================

SUFMETA ?= .csplugin ;
GRISTMETA ?= pluginmeta ;

##  Plugin pluginname : sources [ : options ]
##    Build a plugin out of sourcefiles. All sourcefiles will be passed
##    to the Objects rule which tries to compile them into object-files. You
##    can create rules for your own filetypes with the UserObject rule. Header
##    files will just be ignored. They are only used for MSVC projectfile
##    generator.
##    You can specify the noinstall option if you don't want that an install
##    target is created.
##    Options:
##	noinstall: Don't setup a default installation target.
##	independent: The target will not be made a dependency of the plugins
##		     and all target.
##	nohelp: Do not invoke Help for this target.
##      notest: Do not set up unit-testing support for this target.
rule Plugin
{
  # check options
  CheckOptions noinstall independent nohelp notest : $(3) : $(<) ;

  local metafile ;
  metafile = [ FAppendSuffix $(<) : $(SUFMETA) ] ;
  SEARCH on $(metafile) = $(SEARCH_SOURCE) ;

  local target = [ ConstructPluginTarget $(<) : $(3) ] ;
  local sources = [ DoSourceGrist $(>) ] ;
  local objects = [ CompileObjects $(sources) ] ;

  $(<)_TYPE = plugin ;
  $(<)_OBJECTS = $(objects) ;
  $(<)_SOURCES = $(sources) ;
  $(<)_TARGET = $(target) ;
  $(<)_METAFILE = $(metafile) ;

  # Create a target for eventual static linking
  if ! $(NO_STATIC_LINKING)
  {
    SubVariant static ;
    local staticreginfoobject = [ BuildStaticRegFile $(<) : $(statictarget) ] ;

    # Add objects to the list of candidates for potential inclusion in a
    # monolithic static library containing objects for all plugins (useful for
    # statically linking the plugins into an application if the client so
    # desires).
    local staticobjects = [ CompileObjects $(sources) : $(<) ] ;

    local obj_remain = $(objects) ;
    local staticobj_remain = $(staticobjects) ;
    
    while $(obj_remain)
    {
      local obj = $(obj_remain[1]) ;
      local staticobj = $(staticobj_remain[1]) ;
    
      STATICPLUGINS.OBJECTS.$(staticobj) = $(obj) ;

      obj_remain = $(obj_remain[2-]) ;
      staticobj_remain = $(staticobj_remain[2-]) ;
    }

    MakeLocate $(staticobjects) : $(LOCATE_TARGET) ;
    STATICPLUGINS.OBJECTS.$(<) += $(staticreginfoobject) ;
    STATICPLUGINS.OBJECTS.$(<)  += $(staticobjects) ;
    STATICPLUGINS.SUBTARGETS += $(<) ;
    
    SubVariant ;
  }

  # so 'jam foo' works when it's really foo.dll (Windows) or foo.csbundle
  # (MacOS/X)
  if $(target) != $(<)
  {
    Depends $(<) : $(target) ;
    NotFile $(<) ;
  }

  if ! [ IsElem independent : $(3) ]
  {
    Depends plugins : $(<) ;
  }

  # construct install target
  if ! [ IsElem noinstall : $(3) ]
  {
    SystemInstallPlugin $(target) ;
  }

  # Link
  MakeLocate $(target) : $(LOCATE.TARGETS) ;
  SystemLinkPlugin $(<) : $(objects) : $(3) ;
  
  local cleanextra ;
  if $(LINK.DEBUG.INFO.SEPARATE) = "yes"
  {
    local debugfile = [ SplitDebugInfo $(target) ] ;
    cleanextra += $(debugfile) ;
    if ! [ IsElem noinstall : $(3) ]
    {
      NoCare $(debugfile) ;
      Depends install_plugin : [ DoInstall $(debugfile) : $(plugindir) : $(INSTALL_DATA) ] ;
    }
  }

  CFlags $(<) : $(PLUGIN.CFLAGS) : nostatic ;
  LFlags $(<) : $(LINKLIBS) $(PLUGIN.LFLAGS) : nostatic ;

  # create target clean rule
  Always $(<)clean ;
  NotFile $(<)clean ;
  Clean $(<)clean : $(objects) $(cleanextra) ;
  Clean clean : $(cleanextra) ;

  if ! [ IsElem nohelp : $(3) ]
  {
    local desc = [ Description $(<) ] ;
    if ! $(desc) { desc = "$(<) plugin" ; }
    Help $(<) : "Build the $(desc)" ;
  }

  if ! [ IsElem notest : $(options) ]
  {
    # @@@ Disabled for now; see docs/todo_jam.txt
    #UnitTest $(<) ;
  }
}

#----------------------------------------------------------------------------
# private rules

#  PluginMetaData pluginname : metafile [ : options ]
#    Copy a plugin's meta file so that it resides alongside the generated
#    plugin module.  This utility rule may be used by SystemLinkPlugin rules
#    which employ the default behavior of having a plugin's meta-data file
#    reside alongside the plugin executable (as opposed to bundling the
#    metadata directly into the plugin).
#    Options:
#	noinstall: Don't setup a default installation target.
rule PluginMetaData
{
  local target = $(>:G=$(GRISTMETA)) ;
  Depends $(<) : $(target) ;
  Depends $(target) : $(>) ;
  MakeLocate $(target) : $(LOCATE.TARGETS) ;
  Copy $(target) : $(>) ;
  Clean clean : $(target) ;
  Clean $(<)clean : $(target) ;

  if ! [ IsElem noinstall : $(3) ]
  {
    Depends install_plugin : [ DoInstall $(target) : $(plugindir) ] ;
  }
}

# Construct pseudo target plugins
Depends exe : plugins ;
NotFile plugins ;
Help plugins : "Build all plugin modules" ;
