# Copyright 2002-2017 Rene Rivera
# Copyright 2002-2017 Vladimir Prus
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at
# https://www.bfgroup.xyz/b2/LICENSE.txt)

import "class" : new ;
import generators ;
import param ;
import project ;
import targets ;

# The generator class for libraries (target type LIB). Depending on properties
# it will request building of the appropriate specific library type --
# -- SHARED_LIB, STATIC_LIB or SHARED_LIB.
#
class lib-generator : generator
{
    rule __init__ ( * : * )
    {
        generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8)
            : $(9) : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) :
            $(17) : $(18) : $(19) ;
    }

    rule run ( project name ? : property-set : sources * )
    {
        # The lib generator is composing, and can be only invoked with an
        # explicit name. This check is present in generator.run (and so in
        # builtin.linking-generator) but duplicated here to avoid doing extra
        # work.
        if $(name)
        {
            local properties = [ $(property-set).raw ] ;
            # Determine the needed target type.
            local actual-type ;
                # <source>files can be generated by <conditional>@rule feature
                # in which case we do not consider it a SEARCHED_LIB type.
            if ! <source> in $(properties:G) &&
               ( <search> in $(properties:G) || <name> in $(properties:G) )
            {
                actual-type = SEARCHED_LIB ;
            }
            else if <file> in $(properties:G)
            {
                actual-type = LIB ;
            }
            else if <link>shared in $(properties)
            {
                actual-type = SHARED_LIB ;
            }
            else
            {
                actual-type = STATIC_LIB ;
            }
            property-set = [ $(property-set).add-raw <main-target-type>LIB <relevant>link ] ;
            # Construct the target.
            local result = [ generators.construct $(project) $(name) : $(actual-type)
                : $(property-set) : $(sources) ] ;
            return [ $(result[1]).add-raw <relevant>link ] $(result[2-]) ;
        }
    }

    rule viable-source-types ( )
    {
        return * ;
    }
}

generators.register [ new lib-generator builtin.lib-generator :  : LIB ] ;

# The implementation of the 'lib' rule. Beyond standard syntax that rule allows
# simplified: "lib a b c ;".
#
rule lib ( names + : sources * : requirements * : default-build * :
    usage-requirements * )
{
    param.handle-named-params
        sources requirements default-build usage-requirements ;
    if $(names[2])
    {
        if <name> in $(requirements:G)
        {
            import errors ;
            errors.user-error "When several names are given to the 'lib' rule" :
                "it is not allowed to specify the <name> feature." ;
        }
        if $(sources)
        {
            import errors ;
            errors.user-error "When several names are given to the 'lib' rule" :
                "it is not allowed to specify sources." ;
        }
    }

    # This is a circular module dependency so it must be imported here.
    import targets ;

    local project = [ project.current ] ;
    local result ;

    for local name in $(names)
    {
        local r = $(requirements) ;
        # Support " lib a ; " and " lib a b c ; " syntax.
        if ! $(sources) && ! <name> in $(requirements:G)
                        && ! <file> in $(requirements:G)
        {
            r += <name>$(name) ;
        }
        result += [ targets.main-target-alternative
            [ new typed-target $(name) : $(project) : LIB
                : [ targets.main-target-sources $(sources) : $(name) ]
                : [ targets.main-target-requirements $(r) : $(project) ]
                : [ targets.main-target-default-build $(default-build) : $(project) ]
                : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ]
            ] ] ;
    }
    return $(result) ;
}
IMPORT $(__name__) : lib : : lib ;
