NOTFILE libs dlls objs lists ;

ALL_LIBS_TO_BUILD ?= libs dlls ;

BUILDMODE     ?= obj ;
LIBPREFIX     ?= lib ;
LIBLISTSUFFIX ?= .list ;
TOUCH          = touch ;

if $(UNIX)
{
  PUSHD          = "( cd" ;
  POPD           = ")" ;
  LDSHARE       ?= ld ;
  LDSHARE_FLAGS ?= -G ;
  SUFLIBSHR     ?= .so ;
  ECHO           = echo ;
}
else if $(BEOS)
{
}

makeDirName LIBDIR : $(TOP) $(BUILDMODE) ;

rule LibMember
{
# $(1) is short name of lib these sources are destined for.
# $(2) is list of source files.

  local l o ;

  SOURCE_GRIST = ; # (Implicit grist is a pain.)

    makeDirName LOCATE_TARGET : $(LIBDIR) lib$(1) ;
#
# e.g., binaries for 'foo' library go in $TOP/debug/libfoo
# directory.

  Objects $(2) ; 

# Set up a list file for this library:

  getLibListName l : $(1) ;
  LOCATE on $(l) = $(LIBDIR) ;
# 
# e.g., for the 'foo' library, the list file is 
# $TOP/debug/libfoo.list.

  if ! $(LIST-STARTED-$(<))
  {
    LIST-STARTED-$(<) = true ;
    RemoveExistingFile $(l) : $(l) ;
#
# The RemoveTarget rule has to be invoked once only,
# and before any of the EchoToFile rules are invoked.
  }

  o = $(2:S=$(SUFOBJ):G=:D=lib$(1)) ;
  NOTFILE $(o) ;
#
# $(o) is a list of object file names, sans grist, and
# qualified by the subdir in which it is stored. Thus,
# each element of $(o) uniquely identifies a compiled object
# associated with a built library. Elements of $(o) will be
# used as dependencies but are not bindable.

  EchoToFile $(l) : $(o) ;
  Depends $(l) : $(2:S=$(SUFOBJ)) ;
#
# The list file depends on the compiled objects. If any
# of them are newer, the list file gets recreated. Seems odd,
# but it works, because a list is only updated when you're
# updating a library.

  Depends objs : $(2:S=$(SUFOBJ)) ;
}

rule BuildLib
{
# $(1) is short name of lib to build.
# $(2) is list of dependent lib short names
# $(3) is .def file, for NT.
# $(4) is list of join lib short names. 

  local list libs ;

  SOURCE_GRIST = ;

  if $(LIB$(1)) 
  {
    Exit BuildLib used more than once on $(1) ;
  }
  LIB$(1) = $(LIBPREFIX)$(1)$(SUFLIB) ;
  DLL$(1) = $(LIBPREFIX)$(1)$(SUFLIBSHR) ;
  libs = $(LIB$(1)) $(DLL$(1)) ;
  MakeLocate $(libs) : $(LIBDIR) ;

  if $(4)
  {
    getLibListName list : $(4) ;
  }
  else
  {
    getLibListName list : $(1) ;
    MakeLocate $(list) : $(LIBDIR) ;
    Clean clean : $(list) ;
    Depends lists : $(list) ;
  }

  Depends $(libs) : $(list) ;

  LIBLIST on $(libs) = $(list) ;

  LDSHARE_FLAGS on $(DLL$(1)) += $(LDSHARE_FLAGS) ;

  if $(BEOS)
  {
  }
  else
  {
    LinkDynamicLib $(DLL$(1)) ;
    RemoveExistingFile $(LIB$(1)) : $(LIB$(1)) ;
    ArchiveStaticLib $(LIB$(1)) ;

    if $(RANLIB)
    {
      Ranlib $(LIB$(<)) ;
    }
  }

  Depends libs : $(LIB$(1)) ;
  Depends dlls : $(DLL$(1)) ;

  Depends all : $(ALL_LIBS_TO_BUILD) ;

  Clean clean : $(libs) ;
}

actions quietly existing RemoveExistingFile
{
  $(RM) $(>)
}

actions quietly together piecemeal EchoToFile
{
  $(ECHO) $(>) >> $(<)
}

rule getLibListName
{
# $(1) is var to set.
# $(2) is lib short name.
#
# E.g., "getLibListName l : foo ;" sets
# l to libfoo.list.

  $(1) = lib$(2:S=$(LIBLISTSUFFIX)) ;
}

if $(UNIX)
{
  actions LinkDynamicLib
  {
    $(PUSHD) $(<:D)
      $(LDSHARE) $(LDSHARE_FLAGS) $(LDSHARE_NAME_FLAG)$(<:BS) -o $(<:BS) `cat $(LIBLIST:BS) `
      $(POPD)
  }

  actions ArchiveStaticLib
  {
    $(PUSHD) $(<:D)
      $(AR) $(<:BS) `cat $(LIBLIST:BS) `  
      $(POPD)
  }
}
else if $(BEOS)
{
  actions LinkDynamicLib
  {
  }

  actions ArchiveStaticLib
  {
  }
}

actions quietly TouchFile
{
  $(TOUCH) $(<)
}
