diff --git a/src/contrib/modular.jam b/src/contrib/modular.jam index 917dfbaa5..cba517048 100644 --- a/src/contrib/modular.jam +++ b/src/contrib/modular.jam @@ -3,108 +3,11 @@ # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -#alias library -# : -# : : : include -# ; - import path ; import project ; import modules ; import regex ; - -rule find ( target-refs + ) -{ - process-args ; - - local caller-mod = [ CALLER_MODULE ] ; - local caller-dir = [ modules.peek $(caller-mod) : __file__ ] ; - caller-dir = $(caller-dir:D) ; - caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ; - - for local target-ref in $(target-refs) - { - local ref = [ MATCH ^(.*)//.* : $(target-ref:G=) ] ; - local search-prefix ; - local search-sub ; - for local prefix in $(.search-path-prefix) - { - if ! $(search-prefix) - { - local search-match = [ MATCH ^($(prefix))/(.*)$ : $(ref) ] ; - search-prefix = $(search-match[1]) ; - search-sub = $(search-match[2]) ; - } - } - local found = [ path.glob $(.search-path.$(search-prefix)) : $(search-sub) ] ; - found = $(found[1]) ; - if $(found) - { - local lib-ref = [ regex.split $(search-sub) / ] ; - lib-ref = $(search-prefix)/$(lib-ref[1]) ; - local lib-path = [ path.relative-to $(caller-dir) $(found) ] ; - library $(lib-ref) $(caller-mod) : $(lib-path) ; - } - } - - return $(target-refs) ; -} - -rule library ( name caller-module ? : root ) -{ - process-args ; - - # Dir path of caller to base paths from. - caller-module ?= [ CALLER_MODULE ] ; - local caller-dir = [ modules.peek $(caller-module) : __file__ ] ; - caller-dir = $(caller-dir:D) ; - - # Find the various parts of the library. - local lib-dir = [ path.root [ path.root $(root) $(caller-dir) ] [ path.pwd ] ] ; - local lib-contents = [ path.glob $(lib-dir) : "include" "build" ] ; - lib-contents = $(lib-contents:D=) ; - # "include" dir for library.. - local include-dir ; - if "include" in $(lib-contents) - { - include-dir = include ; - } - - # Does it look like a library? - if $(include-dir) - { - # Load/create/declare library project. - local lib-module = [ project.find $(root) : $(caller-dir) ] ; - if ! $(lib-module) - { - lib-module = [ project.load - [ path.root [ path.make $(root) ] $(caller-dir) ] : synthesize ] ; - } - local lib-target = [ project.target $(lib-module) ] ; - - # We move to the library project module to define the various - # targets others use for the library. - if ! [ modules.peek $(lib-module) : __library__ ] - { - modules.poke $(lib-module) : __library__ : $(name) ; - project.push-current $(lib-target) ; - - # Declare the library alias. - modules.call-in $(lib-module) : alias library - : # Sources - : # Requirements - : # Default Build - : # Usage Requirements - $(include-dir) - ; - - project.pop-current ; - } - - # Declare project alternate ID. - modules.call-in $(caller-module) : use-project $(name) : $(root) ; - } -} +import type ; # Add a location, i.e. directory, where to search for libraries. # The optional 'prefix' indicates which rooted-prefixes the new @@ -126,6 +29,167 @@ rule add-location ( dir prefix ? : base-dir ? ) .search-path.$(prefix) += [ path.root [ path.root $(dir) $(base-dir) ] [ path.pwd ] ] ; } +# Declares additional definitions of a modular library target external +# to the modular library build itself. This makes it possible to externally +# define modular libraries without modifying the library. The passed in +# values are added on demand when the named library is first declared. +rule external ( + name : sources * : requirements * : default-build * : + usage-requirements * ) +{ + .external.($(name)).sources = $(sources) ; + .external.($(name)).requirements = $(requirements) ; + .external.($(name)).default-build = $(default-build) ; + .external.($(name)).usage-requirements = $(usage-requirements) ; +} + +# Find, and declare, any modular libraries referenced in the target-refs. +# This will both load the modular libraries, and declare/manufacture +# the modular libraries as needed. +rule find ( target-refs + ) +{ + process-args ; + + local caller-mod = [ CALLER_MODULE ] ; + local caller-dir = [ modules.peek $(caller-mod) : __file__ ] ; + caller-dir = $(caller-dir:D) ; + caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ; + + local result-refs ; + for local target-ref in $(target-refs) + { + result-refs += [ resolve-reference $(target-ref) + : $(caller-mod) $(caller-dir) ] ; + } + + return $(result-refs) ; +} + +############################################################################## + +local rule resolve-reference ( target-ref : caller-mod caller-dir ? ) +{ + # ECHO %%% modular.resolve-target-ref $(target-ref) :: $(caller-mod) $(caller-dir) ; + if ! $(caller-dir) + { + caller-dir = [ modules.peek $(caller-mod) : __file__ ] ; + caller-dir = $(caller-dir:D) ; + caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ; + } + local result-ref = $(target-ref) ; + local ref = [ MATCH ^(.*)//.* : $(target-ref:G=) ] ; + # if ! ( $(ref) in $(.target-refs) ) + { + # .target-refs += $(ref) ; + local search-prefix ; + local search-sub ; + for local prefix in $(.search-path-prefix) + { + if ! $(search-prefix) + { + local search-match = [ MATCH ^($(prefix))/(.*)$ : $(ref) ] ; + search-prefix = $(search-match[1]) ; + search-sub = $(search-match[2]) ; + } + } + + if $(search-prefix) + { + local found = [ path.glob $(.search-path.$(search-prefix)) : $(search-sub) ] ; + found = $(found[1]) ; + if $(found) + { + local lib-ref = [ regex.split $(search-sub) / ] ; + lib-ref = $(search-prefix)/$(lib-ref[1]) ; + local lib-path = [ path.relative-to $(caller-dir) $(found) ] ; + define-library $(lib-ref) $(caller-mod) : $(lib-path) ; + } + } + } + return $(result-ref) ; +} + +local rule define-library ( name caller-module ? : root ) +{ + # ECHO ~~~ modular.library $(name) $(caller-module) :: $(root) :: $(depends) ; + + process-args ; + + # Dir path of caller to base paths from. + caller-module ?= [ CALLER_MODULE ] ; + local caller-dir = [ modules.peek $(caller-module) : __file__ ] ; + caller-dir = $(caller-dir:D) ; + + # Find the various parts of the library. + local lib-dir = [ path.root [ path.root $(root) $(caller-dir) ] [ path.pwd ] ] ; + local lib-contents = [ path.glob $(lib-dir) : "include" "build" ] ; + lib-contents = $(lib-contents:D=) ; + + # "include" dir for library.. + local include-dir ; + if "include" in $(lib-contents) + { + include-dir = $(root)/include ; + } + + # If it has a build dir, i.e. it has targets to build, + # we root the project at the build dir to make it easy + # to refer to the build targets. This mirrors the regular + # Boost organization of the project aliases. + if "build" in $(lib-contents) + { + root = $(root)/build ; + build-dir = "." ; + } + + # Shadow target declarations so that we can alter build targets + # to work in the standalone modular structure. + local lib-location = [ path.root [ path.make $(root) ] $(caller-dir) ] ; + local lib-module-name = [ project.module-name $(lib-location) ] ; + local modular-rules = [ RULENAMES modular-rules ] ; + IMPORT modular-rules : $(modular-rules) : $(lib-module-name) : $(modular-rules) ; + + # Load/create/declare library project. + local lib-module = [ project.find $(root) : $(caller-dir) ] ; + if ! $(lib-module) + { + # If the find was unable to load the project we synthesize it. + lib-module = [ project.load $(lib-location) : synthesize ] ; + } + local lib-target = [ project.target $(lib-module) ] ; + if ! [ modules.peek $(lib-module) : __library__ ] + { + modules.poke $(lib-module) : __library__ : $(name) ; + for local type in [ modules.peek type : .types ] + { + main-rule-name = [ type.type-to-rule-name $(type) ] ; + IMPORT modular-rules : main-target-rule : $(lib-module-name) : $(main-rule-name) ; + } + } + + # Declare project alternate ID. + modules.call-in $(caller-module) : use-project $(name) : $(root) ; + + # Create a "library" target that has basic usage info if needed. + if ! [ $(lib-target).has-alternative-for-target library ] + { + include-dir = [ path.relative-to $(root) $(include-dir) ] ; + + project.push-current $(lib-target) ; + + # Declare the library alias. + modules.call-in $(lib-module) : library + : # Sources + : # Requirements + : # Default Build + : # Usage Requirements + $(include-dir) + ; + + project.pop-current ; + } +} + local rule process-args ( ) { if ! $(.did-process-args) @@ -139,3 +203,86 @@ local rule process-args ( ) } } } + +rule apply-external ( + mod : field : values * ) +{ + local result ; + local name = [ modules.peek $(mod) : __library__ ] ; + values += $(.external.($(name)).$(field)) ; + for local value in $(values) + { + result += [ resolve-reference $(value) : $(mod) ] ; + } + return $(result) ; +} + +module modular-rules +{ + import type ; + import targets ; + import builtin ; + import alias ; + + # Avoids any form of installation for Boost modules. + rule boost-install ( libraries * ) { } + + # Generic typed target rule to pre-process main target + # declarations to make them work within the standalone + # modular structure. + rule main-target-rule ( + name : sources * : requirements * : default-build * : + usage-requirements * ) + { + local mod = [ CALLER_MODULE ] ; + + # ECHO @@@ [[$(mod)]] modular-rules.main-target-rule $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; + + # First discover the required target type based on the exact alias used to + # invoke this rule. + local bt = [ BACKTRACE 1 ] ; + local rulename = $(bt[4]) ; + local target-type = [ type.type-from-rule-name $(rulename) ] ; + return [ targets.create-typed-target $(target-type) : [ project.current ] : + $(name) : $(sources) : $(requirements) : $(default-build) : + $(usage-requirements) ] ; + } + + rule lib ( names + : sources * : requirements * : default-build * : + usage-requirements * ) + { + local mod = [ CALLER_MODULE ] ; + requirements += library ; + usage-requirements += library ; + + # ECHO @@@ [[$(mod)]] modular-rules.lib $(names) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; + return [ builtin.lib $(names) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; + } + + rule alias ( name : sources * : requirements * : default-build * : + usage-requirements * ) + { + local mod = [ CALLER_MODULE ] ; + + # ECHO @@@ [[$(mod)]] modular-rules.alias $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; + return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; + } + + rule library ( name ? : sources * : requirements * : default-build * : + usage-requirements * ) + { + import modular ; + + local mod = [ CALLER_MODULE ] ; + sources = [ modular.apply-external $(mod) : sources : $(sources) ] ; + requirements = [ modular.apply-external $(mod) : requirements : $(requirements) ] ; + default-build = [ modular.apply-external $(mod) : default-build : $(default-build) ] ; + usage-requirements = [ modular.apply-external $(mod) : usage-requirements : $(usage-requirements) ] ; + + name ?= library ; + + # ECHO @@@ [[$(mod)]] modular-rules.library $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ; + return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ; + } +} +