• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright Rene Rivera 2015
2# Distributed under the Boost Software License, Version 1.0.
3# (See accompanying file LICENSE_1_0.txt or copy at
4# http://www.boost.org/LICENSE_1_0.txt)
5
6import path ;
7import project ;
8import modules ;
9import regex ;
10import type ;
11
12# Add a location, i.e. directory, where to search for libraries.
13# The optional 'prefix' indicates which rooted-prefixes the new
14# search dir applies to. The prefix defaults to '/'.
15rule add-location ( dir prefix ? : base-dir ? )
16{
17    process-args ;
18
19    prefix ?= "/" ;
20
21    # Dir path of caller to base paths from.
22    caller-module ?= [ CALLER_MODULE ] ;
23    local caller-dir = [ modules.peek $(caller-module) : __file__ ] ;
24    caller-dir = $(caller-dir:D) ;
25
26    base-dir ?= $(caller-dir) ;
27
28    .search-path-prefix += $(prefix) ;
29    .search-path.$(prefix) += [ path.root [ path.root $(dir) $(base-dir) ] [ path.pwd ] ] ;
30}
31
32# Declares additional definitions of a modular library target external
33# to the modular library build itself. This makes it possible to externally
34# define modular libraries without modifying the library. The passed in
35# values are added on demand when the named library is first declared.
36rule external (
37    name : sources * : requirements * : default-build * :
38    usage-requirements * )
39{
40    .external.($(name)).sources = $(sources) ;
41    .external.($(name)).requirements = $(requirements) ;
42    .external.($(name)).default-build = $(default-build) ;
43    .external.($(name)).usage-requirements = $(usage-requirements) ;
44}
45
46# Find, and declare, any modular libraries referenced in the target-refs.
47# This will both load the modular libraries, and declare/manufacture
48# the modular libraries as needed.
49rule find ( target-refs + )
50{
51    process-args ;
52
53    local caller-mod = [ CALLER_MODULE ] ;
54    local caller-dir = [ modules.peek $(caller-mod) : __file__ ] ;
55    caller-dir = $(caller-dir:D) ;
56    caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ;
57
58    local result-refs ;
59    for local target-ref in $(target-refs)
60    {
61        result-refs += [ resolve-reference $(target-ref)
62            : $(caller-mod) $(caller-dir) ] ;
63    }
64
65    return $(result-refs) ;
66}
67
68##############################################################################
69
70local rule resolve-reference ( target-ref : caller-mod caller-dir ? )
71{
72    # ECHO %%% modular.resolve-target-ref $(target-ref) :: $(caller-mod) $(caller-dir) ;
73    if ! $(caller-dir)
74    {
75        caller-dir = [ modules.peek $(caller-mod) : __file__ ] ;
76        caller-dir = $(caller-dir:D) ;
77        caller-dir = [ path.root $(caller-dir) [ path.pwd ] ] ;
78    }
79    local result-ref = $(target-ref) ;
80    local ref = [ MATCH ^(.*)//.* : $(target-ref:G=) ] ;
81    # if ! ( $(ref) in $(.target-refs) )
82    {
83        # .target-refs += $(ref) ;
84        local search-prefix ;
85        local search-sub ;
86        for local prefix in $(.search-path-prefix)
87        {
88            if ! $(search-prefix)
89            {
90                local search-match = [ MATCH ^($(prefix))/(.*)$ : $(ref) ] ;
91                search-prefix = $(search-match[1]) ;
92                search-sub = $(search-match[2]) ;
93            }
94        }
95
96        if $(search-prefix)
97        {
98            local found = [ path.glob $(.search-path.$(search-prefix)) : $(search-sub) ] ;
99            found = $(found[1]) ;
100            if $(found)
101            {
102                local lib-ref = [ regex.split $(search-sub) / ] ;
103                lib-ref = $(search-prefix)/$(lib-ref[1]) ;
104                local lib-path = [ path.relative-to $(caller-dir) $(found) ] ;
105                define-library $(lib-ref) $(caller-mod) : $(lib-path) ;
106            }
107        }
108    }
109    return $(result-ref) ;
110}
111
112local rule define-library ( name caller-module ? : root )
113{
114    # ECHO ~~~ modular.library $(name) $(caller-module) :: $(root) :: $(depends) ;
115
116    process-args ;
117
118    # Dir path of caller to base paths from.
119    caller-module ?= [ CALLER_MODULE ] ;
120    local caller-dir = [ modules.peek $(caller-module) : __file__ ] ;
121    caller-dir = $(caller-dir:D) ;
122
123    # Find the various parts of the library.
124    local lib-dir = [ path.root [ path.root $(root) $(caller-dir) ] [ path.pwd ] ] ;
125    local lib-contents = [ path.glob $(lib-dir) : "include" "build" ] ;
126    lib-contents = $(lib-contents:D=) ;
127
128    # "include" dir for library..
129    local include-dir ;
130    if "include" in $(lib-contents)
131    {
132        include-dir = $(root)/include ;
133    }
134
135    # If it has a build dir, i.e. it has targets to build,
136    # we root the project at the build dir to make it easy
137    # to refer to the build targets. This mirrors the regular
138    # Boost organization of the project aliases.
139    if "build" in $(lib-contents)
140    {
141        root = $(root)/build ;
142        build-dir = "." ;
143    }
144
145    # Shadow target declarations so that we can alter build targets
146    # to work in the standalone modular structure.
147    local lib-location = [ path.root [ path.make $(root) ] $(caller-dir) ] ;
148    local lib-module-name = [ project.module-name $(lib-location) ] ;
149    local modular-rules = [ RULENAMES modular-rules ] ;
150    IMPORT modular-rules : $(modular-rules) : $(lib-module-name) : $(modular-rules) ;
151
152    # Load/create/declare library project.
153    local lib-module = [ project.find $(root) : $(caller-dir) ] ;
154    if ! $(lib-module)
155    {
156        # If the find was unable to load the project we synthesize it.
157        lib-module = [ project.load $(lib-location) : synthesize ] ;
158    }
159    local lib-target = [ project.target $(lib-module) ] ;
160    if ! [ modules.peek $(lib-module) : __library__ ]
161    {
162        modules.poke $(lib-module) : __library__ : $(name) ;
163        for local type in [ modules.peek type : .types ]
164        {
165            main-rule-name = [ type.type-to-rule-name $(type) ] ;
166            IMPORT modular-rules : main-target-rule : $(lib-module-name) : $(main-rule-name) ;
167        }
168    }
169
170    # Declare project alternate ID.
171    modules.call-in $(caller-module) : use-project $(name) : $(root) ;
172
173    # Create a "library" target that has basic usage info if needed.
174    if ! [ $(lib-target).has-alternative-for-target library ]
175    {
176        include-dir = [ path.relative-to $(root) $(include-dir) ] ;
177
178        project.push-current $(lib-target) ;
179
180        # Declare the library alias.
181        modules.call-in $(lib-module) : library
182            : # Sources
183            : # Requirements
184            : # Default Build
185            : # Usage Requirements
186              <include>$(include-dir)
187            ;
188
189        project.pop-current ;
190    }
191}
192
193local rule process-args ( )
194{
195    if ! $(.did-process-args)
196    {
197        .did-process-args = yes ;
198        local argv = [ modules.peek : ARGV ] ;
199        local dirs = [ MATCH ^--modular-search-dir=(.*)$ : $(argv) ] ;
200        for local dir in $(dirs)
201        {
202            add-location $(dir) : [ path.pwd ] ;
203        }
204    }
205}
206
207rule apply-external (
208    mod : field : values * )
209{
210    local result ;
211    local name = [ modules.peek $(mod) : __library__ ] ;
212    values += $(.external.($(name)).$(field)) ;
213    for local value in $(values)
214    {
215        result += [ resolve-reference $(value) : $(mod) ] ;
216    }
217    return $(result) ;
218}
219
220module modular-rules
221{
222    import type ;
223    import targets ;
224    import builtin ;
225    import alias ;
226
227    # Avoids any form of installation for Boost modules.
228    rule boost-install ( libraries * ) { }
229
230    # Generic typed target rule to pre-process main target
231    # declarations to make them work within the standalone
232    # modular structure.
233    rule main-target-rule (
234        name : sources * : requirements * : default-build * :
235        usage-requirements * )
236    {
237        local mod = [ CALLER_MODULE ] ;
238
239        # ECHO @@@ [[$(mod)]] modular-rules.main-target-rule $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ;
240
241        # First discover the required target type based on the exact alias used to
242        # invoke this rule.
243        local bt = [ BACKTRACE 1 ] ;
244        local rulename = $(bt[4]) ;
245        local target-type = [ type.type-from-rule-name $(rulename) ] ;
246        return [ targets.create-typed-target $(target-type) : [ project.current ] :
247            $(name) : $(sources) : $(requirements) : $(default-build) :
248            $(usage-requirements) ] ;
249    }
250
251    rule lib ( names + : sources * : requirements * : default-build * :
252        usage-requirements * )
253    {
254        local mod = [ CALLER_MODULE ] ;
255        requirements += <use>library ;
256        usage-requirements += <use>library ;
257
258        # ECHO @@@ [[$(mod)]] modular-rules.lib $(names) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ;
259        return [ builtin.lib $(names) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ;
260    }
261
262    rule alias ( name : sources * : requirements * : default-build * :
263        usage-requirements * )
264    {
265        local mod = [ CALLER_MODULE ] ;
266
267        # ECHO @@@ [[$(mod)]] modular-rules.alias $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ;
268        return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ;
269    }
270
271    rule library ( name ? : sources * : requirements * : default-build * :
272        usage-requirements * )
273    {
274        import modular ;
275
276        local mod = [ CALLER_MODULE ] ;
277        sources = [ modular.apply-external $(mod) : sources : $(sources) ] ;
278        requirements = [ modular.apply-external $(mod) : requirements : $(requirements) ] ;
279        default-build = [ modular.apply-external $(mod) : default-build : $(default-build) ] ;
280        usage-requirements = [ modular.apply-external $(mod) : usage-requirements : $(usage-requirements) ] ;
281
282        name ?= library ;
283
284        # ECHO @@@ [[$(mod)]] modular-rules.library $(name) :: $(sources) :: $(requirements) :: $(default-build) :: $(usage-requirements) ;
285        return [ alias.alias $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ;
286    }
287}
288
289