# Jamrules for presto
#
# Required environment:
#
# PRESTO = root of presto tree
# TOOLROOT = build tool directory ( PRESTO/tools is a good choice )
# ROOT = library/header root directory ( PRESTO/root is a good choice )
# MSVCNT = TOOLROOT
#

#
# Build settings
#
GLOBALDEFS = -D"WINDOWS" -D"WIN32" -D"_MBCS" ;
GLOBALFLAGS = -GX ;

RELEASEDEFS = -D"NDEBUG" ;
RELEASEFLAGS = ;

DEBUGDEFS = -D"_DEBUG" ;
DEBUGFLAGS = -Zi ;

if $(BUILD) = "RELEASE"
{
    ECHO Building using RELEASE settings ;
    OPTIM = /O2 ;
    C++FLAGS += -GX $(GLOBALDEFS) $(RELEASEDEFS) $(RELEASEFLAGS) ;
    LINKFLAGS += /RELEASE ;
    BUILDMODE = Release ;
}
else
{
    ECHO Building using DEBUG settings ;
    OPTIM = /Od ;
    C++FLAGS += -GX $(GLOBALDEFS) $(DEBUGDEFS) $(DEBUGFLAGS) ;
    LINKFLAGS += /DEBUG ;
    BIULDMODE = Debug ;
}

#
# Headers
#
STDHDRS = $(ROOT)/dxmsdk/include $(ROOT)/inc $(ROOT)/inc/atl $(ROOT)/inc/atl21 ;
HDRS = $(PRESTO) ;

#
# Default linker flags
#
LINKFLAGS += /NODEFAULTLIB:LIBC.LIB ;
LINKLIBS = 
    $(ROOT)/lib/i386/advapi32.lib
    $(ROOT)/lib/i386/ole32.lib
    $(ROOT)/lib/i386/user32.lib
    $(ROOT)/lib/i386/kernel32.lib
    $(ROOT)/lib/i386/gdi32.lib 
    ;

#
# Tool definitions
#
C++ = $(TOOLROOT)/cl /nologo ;
CC = $(C++) ;
LINK = $(TOOLROOT)/link /nologo ;
AR = $(TOOLROOT)/lib /nologo ;
RC = $(TOOLROOT)/rc ;

#
# User rules
#
rule UserObject
{
    switch $(>)
    {
        case *.rc   : ResourceCompiler $(<) : $(>) ;
        case *      : ECHO "Unknown suffix on " $(>) ;
    }
}

rule ResourceCompiler
{
    DEPENDS $(<) : $(>) ;
    Clean clean : $(<) ;
}

actions ResourceCompiler
{
    $(RC) /fo $(<) $(RCFLAGS) $(>)
}

rule Resources
    # Compiles .rc files in $(<) into .res files
{
	local i s ;

	# Add grist to file names

	makeGristedName s : $(<) ;

	for i in $(s)
	{
		Object $(i:S=.RES) : $(i) ;
		DEPENDS obj : $(i:S=.RES) ;
	}
}

rule MainWithResources
# $(1) - target
# $(2) - resource file
# $(3) - sources
{
    MainFromObjects $(1) : $(3:S=$(SUFOBJ)) $(2:S=.RES) ;
    Objects $(3) ;
    Resources $(2) ;
}

rule LibraryWithResources
# $(1) - target
# $(2) - resource file
# $(3) - sources
{
    LibraryFromObjects $(1) : $(3:S=$(SUFOBJ)) $(2:S=.RES) ;
    Objects $(3) ;

    if $(2)
    {
        Resources $(2) ;
    }
}

# jterrell's shared library rule
# $(1) is the lib to build
# $(2) is the .def file
# $(3) are the targets
# $(4) are the resources
rule SharedLibrary
{
    BuildLib $(1) : : $(2) : : $(LOCATE_TARGET) ;
    LibMember $(1) : $(3) : $(LOCATE_TARGET) ;
    if $(NEVER)
    {
    PREFLIB = lib ;
    SUFDLL  = .dll ;
    PREFDLL = "" ;

    #makeDirName LOCATE_TARGET : $(TOP) lib ;

    lib = $(PREFLIB)$(1) ;
    dll = $(PREFDLL)$(1:S=$(SUFDLL)) ;

    LibraryWithResources $(lib) :
        $(4) :
        $(3) 
        ;

    MainFromObjects $(dll) ;

    LinkLibraries $(dll) : $(lib) ;

    LINKFLAGS on $(dll) += /map /dll /machine:ix86 $(LINKFLAGS) ;
    }
}

###############################################################
#
# Nasty shared library rules taken from JAM mailing list
#
###############################################################
NOTFILE libs dlls objs lists ;

ALL_LIBS_TO_BUILD ?= libs dlls ;

BUILDMODE         ?= debug ;
LIBLISTSUFFIX     ?= .list ;
TOUCH              = touch ;

PUSHD           = pushd ;
POPD            = popd ;
LDSHARE        ?= $(MSLINK) ;
LDSHARE_FLAGS  ?= /nologo /MAP /DLL ;
SUFLIBSHR       = .dll ;
ECHO            = echo. ;

# JWT 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 ;
   
    # JWT
    LIBDIR = $(3) ;

    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. 
    # $(5) is the target directory
    local list libs ;

    SOURCE_GRIST = ;

    LIBDIR = $(5) ;

    if $(LIB$(1)) 
    {
        #Exit BuildLib used more than once on $(1) ;
    }

    LIB$(1) = $(1)$(SUFLIB) ;
    DLL$(1) = $(1)$(SUFLIBSHR) ;
    MAP$(1) = $(1).map ;
    EXP$(1) = $(1).exp ;
    
    libs = $(LIB$(1)) $(DLL$(1)) $(MAP$(1)) $(EXP$(1)) ;

    # Make $(LIBDIR) and build $(libs) into it...
    MakeLocate $(libs) : $(LIBDIR) ;

    # $(4) is list of join lib short names
    if $(4)
    {
        # list = lib$(4).lst
        getLibListName list : $(4) ;
    }
    else
    {
        # list = lib$(1).lst
        getLibListName list : $(1) ;

        # Make $(LIBDIR) and build $(list) into it...
        MakeLocate $(list) : $(LIBDIR) ;

        # Removes $(list) when clean is built...
        Clean clean : $(list) ;

        # lists is a dependency of $(list)
        Depends lists : $(list) ;
    }

    # $(libs) is a dependency of $(list)
    Depends $(libs) : $(list) ;

    LIBLIST on $(libs) = $(list) ;
    LDSHARE_FLAGS on $(DLL$(1)) += $(LDSHARE_FLAGS) ;

    local lp ;
    makeString lp : .; $(LIBDIR); $(EXTLIBDIRS); ;
    NTLIBPATH on $(DLL$(1)) += $(lp) ;

    # Lib to build is in $(1)
    if $(1) in $(STATIC_LIB_ONLY)
    {
        RemoveExistingFile $(LIB$(1)) : $(LIB$(1)) ;
        ArchiveStaticLib $(LIB$(1)) ;
    }
    else
    {
        LinkDynamicLib $(DLL$(1)) ;
        TouchFile $(LIB$(1)) ;
        Depends $(LIB$(1)) : $(DLL$(1)) ;
    }

    # List of dependent short lib names is in $(2)
    if $(2)
    {
        local deps ;
        deps = $(2)$(SUFLIB) ;
        NEEDLIBS on $(DLL$(1)) += $(deps) ;
        Depends $(DLL$(1)) : $(deps) ;
        LOCATE on $(deps) = $(LIBDIR) ;
    }

    # .def file is in $(3)
    if $(3) 
    {
        local def ;
        def = $(3:G=copied) ;
        File $(def) : $(3) ;
        LOCATE on $(def) = $(LIBDIR) ;
        DEFFILE on $(DLL$(1)) = $(def:G=) ;
        Depends $(DLL$(1)) : $(def) ;
        Clean clean : $(def) ;
    }

    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 $(NT)
{
    actions LinkDynamicLib
    {
	set LIB=$(NTLIBPATH);%LIB%||exit
	$(PUSHD) $(<:D) || goto :pushd_failed
	$(LDSHARE) $(LDSHARE_FLAGS) /out:$(<:BS) /def:$(DEFFILE) @$(LIBLIST) $(NEEDLIBS:BS) $(LINKSYSLIBS) || goto :link_failed
	$(POPD)
    }

    actions ArchiveStaticLib
    {
        $(PUSHD) $(<:D) || goto :pushd_failed
        $(MSLIB) /out:$(<:BS) @$(LIBLIST) || goto :link_failed
	$(POPD)
    }
}

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

