1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
|
// file : libbuild2/file.hxx -*- C++ -*-
// license : MIT; see accompanying LICENSE file
#ifndef LIBBUILD2_FILE_HXX
#define LIBBUILD2_FILE_HXX
#include <libbuild2/types.hxx>
#include <libbuild2/forward.hxx>
#include <libbuild2/utility.hxx>
#include <libbuild2/scope.hxx>
#include <libbuild2/target.hxx>
#include <libbuild2/variable.hxx> // list_value
#include <libbuild2/export.hxx>
namespace build2
{
class lexer;
class parser;
// The following filesystem entries in the build/ subdirectory are reserved
// by the build2 core:
//
// build/ -- build2 core-internal build state (e.g., recipes)
// bootstrap/ -- bootstrap state and hooks
// bootstrap.build -- bootstrap buildfile
// root/ -- root load hooks
// root.build -- root buildfile
// export.build -- export stub
// export/ -- exported buildfiles
//
// The build/, bootstrap/, root/, and config.build entries are in .gitignore
// as generated by bdep-new.
//
// The rest of the filesystem entries are shared between the project and the
// modules that it loads. In particular, if a project loads module named
// <mod>, then the <mod>.build, <mod>/, *.<mod> entries (spelled in any
// case) are reserved to this module and should not be used by the project
// unless explicitly allowed by the module. By convention, <mod>/build/ is
// for module-internal build state (e.g., C++ modules side-build) and is
// .gitignore'ed.
//
LIBBUILD2_SYMEXPORT extern const dir_path std_build_dir; // build/
// build/root.build
//
LIBBUILD2_SYMEXPORT extern const path std_root_file;
// build/bootstrap.build
//
LIBBUILD2_SYMEXPORT extern const path std_bootstrap_file;
LIBBUILD2_SYMEXPORT extern const path std_buildfile_file; // buildfile
LIBBUILD2_SYMEXPORT extern const path alt_buildfile_file; // build2file
// If the altn argument value is present, then it indicates whether we are
// using the standard or the alternative build file/directory naming.
//
// The overall plan is to run various "file exists" tests using the standard
// and the alternative names. The first test that succeeds determines the
// naming scheme (by setting altn) and from then on all the remaining tests
// only look for things in this scheme.
//
LIBBUILD2_SYMEXPORT bool
is_src_root (const dir_path&, optional<bool>& altn);
LIBBUILD2_SYMEXPORT bool
is_out_root (const dir_path&, optional<bool>& altn);
// Given an src_base directory, look for a project's src_root based on the
// presence of known special files. Return empty path if not found. Note
// that if the input is normalized/actualized, then the output will be as
// well.
//
LIBBUILD2_SYMEXPORT dir_path
find_src_root (const dir_path&, optional<bool>& altn);
// The same as above but for project's out. Note that we also check whether
// a directory happens to be src_root, in case this is an in source build with
// the result returned as the second half of the pair. Note also that if the
// input is normalized/actualized, then the output will be as well.
//
LIBBUILD2_SYMEXPORT pair<dir_path, bool>
find_out_root (const dir_path&, optional<bool>& altn);
// Look for a buildfile starting from the specified directory and continuing
// in the parent directories until root. Return nullopt if not found.
//
LIBBUILD2_SYMEXPORT optional<path>
find_buildfile (const dir_path& base,
const dir_path& root,
optional<bool>& altn,
const path& name = {});
// If the buildfile cannot be found in the target's directory itself, then
// this function can be used to try and find a nearest buildfile that could
// plausibly define this target. Return nullopt if not found and empty path
// if the implied buildfile in the target's directory should be assumed.
//
LIBBUILD2_SYMEXPORT optional<path>
find_plausible_buildfile (const name& tgt,
const scope& rs,
const dir_path& src_base,
const dir_path& src_root,
optional<bool>& altn,
const path& name = {});
// Project's loading stage during which the parsing is performed.
//
enum class load_stage
{
boot, // Loading bootstrap.build (or bootstrap pre/post hooks).
root, // Loading root.build (or root pre/post hooks).
rest // Loading the rest (ordinary buildfiles, command line, etc).
};
// If buildfile is '-', then read from STDIN.
//
LIBBUILD2_SYMEXPORT void
source (scope& root, scope& base, const path&);
// As above, but extract from a stream. The name argument is used for
// diagnostics.
//
LIBBUILD2_SYMEXPORT void
source (scope& root, scope& base, istream&, const path_name&);
// As above, but extract from a lexer (this could be useful for sourcing
// stdin that requires parse_variable()).
//
LIBBUILD2_SYMEXPORT void
source (scope& root, scope& base, lexer&, load_stage = load_stage::rest);
// As above but first check if this buildfile has already been sourced for
// the root scope. Return false if the file has already been sourced.
//
bool
source_once (scope& root, scope& base, const path&);
// As above but checks against the specified root scope rather than this
// root scope.
//
LIBBUILD2_SYMEXPORT bool
source_once (scope& root, scope& base, const path&, scope& once_root);
// Create project's root scope. Only set the src_root variable if the passed
// src_root value is not empty.
//
LIBBUILD2_SYMEXPORT scope_map::iterator
create_root (context&, const dir_path& out_root, const dir_path& src_root);
// Setup root scope. Note that it assumes the src_root variable has already
// been set.
//
LIBBUILD2_SYMEXPORT void
setup_root (scope&, bool forwarded);
// Setup the base scope (set *_base variables, etc).
//
LIBBUILD2_SYMEXPORT scope&
setup_base (scope_map::iterator,
const dir_path& out_base,
const dir_path& src_base);
// Return a scope for the specified directory (first). If project is true
// then switching to this scope might also involve switch to a new root
// scope (second) if the new scope is in another project. If project is
// false or the new scope is not in any project, then NULL is returned in
// second.
//
// Note that if switching the scope involved switching the project, then you
// may also need to switch to the new project's environment (see
// root_extra::environment).
//
LIBBUILD2_SYMEXPORT pair<scope&, scope*>
switch_scope (scope& root, const dir_path& out_base, bool project = true);
// Bootstrap and optionally load an ad hoc (sub)project (i.e., the kind that
// is not discovered and loaded automatically by bootstrap/load functions
// above).
//
// Note that we expect the outer project (if any) to be bootstrapped and
// loaded and currently we do not add the newly loaded subproject to the
// outer project's subprojects map.
//
LIBBUILD2_SYMEXPORT scope&
load_project (context&,
const dir_path& out_root,
const dir_path& src_root,
bool forwarded,
bool load = true);
// Bootstrap the project's forward. Return the forwarded-to out_root or
// src_root if there is no forward. See is_{src,out}_root() for the altn
// argument semantics.
//
LIBBUILD2_SYMEXPORT dir_path
bootstrap_fwd (context&, const dir_path& src_root, optional<bool>& altn);
// Bootstrap the project's root scope, the out part. Return the src_root
// variable value (which can be NULL).
//
LIBBUILD2_SYMEXPORT value&
bootstrap_out (scope& root, optional<bool>& altn);
// Bootstrap the project's root scope, the src part.
//
// If amalgamation is present, then use the specified directory as the
// amalgamation instead of discovering or extracting it from bootstrap.build
// (use empty directory to disable amalgamation). If subprojects is false,
// then do not discover or extract subprojects.
//
LIBBUILD2_SYMEXPORT void
bootstrap_src (scope& root, optional<bool>& altn,
optional<dir_path> amalgamation = nullopt,
bool subprojects = true);
// Return true if this scope has already been bootstrapped, that is, the
// following calls have already been made:
//
// bootstrap_out()
// setup_root()
// bootstrap_src()
//
LIBBUILD2_SYMEXPORT bool
bootstrapped (scope& root);
// Execute pre/post-bootstrap hooks. Similar to bootstrap_out/src(), should
// only be called once per project bootstrap.
//
LIBBUILD2_SYMEXPORT void
bootstrap_pre (scope& root, optional<bool>& altn);
LIBBUILD2_SYMEXPORT void
bootstrap_post (scope& root);
// Create and bootstrap outer root scopes, if any. Loading is done by
// load_root(). If subprojects is false, then do not discover or extract
// subprojects.
//
LIBBUILD2_SYMEXPORT void
create_bootstrap_outer (scope& root, bool subprojects = true);
// Create and bootstrap inner root scopes, if any, recursively.
//
// If out_base is not empty, then only bootstrap scope between root and base
// returning the innermost created root scope or root if none were created.
//
// Note that loading is done by load_root().
//
LIBBUILD2_SYMEXPORT scope&
create_bootstrap_inner (scope& root, const dir_path& out_base = dir_path ());
// Load project's root.build (and root pre/post hooks) unless already
// loaded. Also make sure all outer root scopes are loaded prior to loading
// this root scope.
//
// If pre/post functions are specified, they are called before/after
// pre/post hooks, respectively.
//
LIBBUILD2_SYMEXPORT void
load_root (scope& root,
const function<void (parser&)>& pre = nullptr,
const function<void (parser&)>& post = nullptr);
// Extract the specified variable value from a buildfile. It is expected to
// be the first non-blank/comment line and not to rely on any variable
// expansions other than those from the global scope or any variable
// overrides. Return nullopt if the variable was not found.
//
LIBBUILD2_SYMEXPORT optional<value>
extract_variable (context&, const path&, const variable&);
// As above, but extract from a stream. The path argument is used for
// diagnostics.
//
LIBBUILD2_SYMEXPORT optional<value>
extract_variable (context&, istream&, const path&, const variable&);
// As above, but extract from a lexer (this could be useful for extracting
// from stdin).
//
LIBBUILD2_SYMEXPORT optional<value>
extract_variable (context&, lexer&, const variable&);
// Import has two phases: the first is triggered by the import directive in
// the buildfile. It will try to find and load the project. Failed that, it
// will return the project-qualified name of the target which will be used
// to create a project-qualified prerequisite. This gives the rule that will
// be searching this prerequisite a chance to do some target-type specific
// search. For example, a C++ link rule can search for lib{} prerequisites
// in the C++ compiler default library search paths (so that we end up with
// functionality identical to -lfoo). If, however, the rule didn't do any of
// that (or failed to find anything usable), it calls the standard
// prerequisite search() function which sees this is a project-qualified
// prerequisite and goes straight to the second phase of import. Here,
// currently, we only have special handling of exe{} targets (search in
// PATH) simply failing for the rest. But in the future this coud be the
// place where we could call custom "last resort" import hooks. For example,
// we can hook a package manager that will say, "Hey, dude, I see you are
// trying to import foo and I see there is a package foo available in
// repository bar. Wanna, like, download and use it or something?" Though
// the latest thoughts indicate this is probably a bad idea (implicitness,
// complexity, etc).
//
// More specifically, we have the following kinds of import (tried in this
// order):
//
// ad hoc
//
// The target is imported by having its path specifed directly with
// config.import.<proj>.<name>[.<type>]. For example, this can be used to
// import an installed target.
//
// Note that this is also the kind assigned to an import that uses an
// unqualified absolute target name or a relative directory (which we also
// call ad hoc; in a sense it's the same thing, just the path is hardcoded
// directly in the buildfile).
//
//
// normal
//
// The target is imported from a project that was either specified with
// config.import.<proj> or was found via the subproject search. This also
// loads the target's dependency information.
//
//
// rule-specific
//
// The target was imported in a rule-specific manner (e.g., a library was
// found in the compiler's search paths).
//
//
// fallback/default
//
// The target was found by the second phase of import (e.g., an executable
// was found in PATH).
// Import phase 1. Return the imported target(s) as well as the kind of
// import that was performed with `fallback` indicating it was not found.
//
// If second is `fallback`, then first contains the original, project-
// qualified target. If second is `adhoc`, first may still contain a
// project-qualified target (which may or may not be the same as the
// original; see the config.import.<proj>.<name>[.<type>] logic for details)
// in which case it should still be passed to import phase 2.
//
// If phase2 is present then the phase 2 is performed right away (we call it
// immediate import). Note that if optional is true, phase2 must be present
// as well (and thus there is no rule-specific logic for optional imports).
// In case of optional, empty names value is returned if nothing was found.
// The value in phase2 is the optional rule hint that, if not empty, will be
// used to lookup a rule that will be asked to resolve the qualified target
// (see rule::import()). If it is empty, then built-in resolution logic will
// be used for some target types (currently only exe{}).
//
// If metadata is true, then load the target metadata. In this case phase2
// must be true as well.
//
// Note also that we return names rather than a single name: while normally
// it will be a single target name, it can be an out-qualified pair (if
// someone wants to return a source target) but it can also be a non-target
// since we don't restrict what users can import/export. If name has
// buildfile type, then the result is an absolute buildfile target to be
// included (once) at the point of importation.
//
// Finally, note that import is (and should be kept) idempotent or, more
// precisely, "accumulatively idempotent" in that additional steps may be
// performed (phase 2, loading of the metadata) unless already done.
//
enum class import_kind {adhoc, normal, fallback};
LIBBUILD2_SYMEXPORT pair<names, import_kind>
import (scope& base,
name,
const optional<string>& phase2,
bool optional,
bool metadata,
const location&);
// Import phase 2.
//
const target&
import2 (context&, const prerequisite_key&);
// As above but import the target "here and now" without waiting for phase 2
// (and thus omitting any rule-specific logic). This version of import is,
// for example, used by build system modules to perform an implicit import
// of the corresponding tool.
//
// If phase2 is absent, then the second phase's fallback/default logic is
// only invoked if the import was ad hoc (i.e., a relative path was
// specified via config.import.<proj>.<name>[.<type>]) with NULL returned
// otherwise.
//
// If phase2 is present and optional is true, then NULL is returned instead
// of failing if phase 2 could not find anything.
//
// If metadata is true, then load the target metadata. In this case phase2
// must be present as well.
//
// The what argument specifies what triggered the import (for example,
// "module load") and is used in diagnostics.
//
// This function also returns the stable exported target name (see
// target::as_name() for details) as well as the kind of import that was
// performed.
//
// Note: cannot be used to import buildfile targets (use import_buildfile()
// instead).
//
template <typename T>
struct import_result
{
const T* target;
names name;
import_kind kind;
};
// Print import_direct<exe>() result either as a target for a normal import
// or as a process path for ad hoc and fallback imports. Normally used in
// build system modules to print the configuration report.
//
LIBBUILD2_SYMEXPORT ostream&
operator<< (ostream&, const import_result<exe>&);
import_result<target>
import_direct (scope& base,
name,
const optional<string>& phase2,
bool optional,
bool metadata,
const location&,
const char* what = "import");
// As above but also return (in new_value) an indication of whether this
// import is based on a new config.* value. See config::lookup_config() for
// details. Note that a phase 2 fallback/default logic is not considered new
// (though this can be easily adjusted based on import kind).
//
LIBBUILD2_SYMEXPORT import_result<target>
import_direct (bool& new_value,
scope& base,
name,
const optional<string>& phase2,
bool optional,
bool metadata,
const location&,
const char* what = "import");
// As above but also cast the target and pass phase2 as bool (primarily
// for use in build system modules).
//
template <typename T>
import_result<T>
import_direct (scope&,
name, bool, bool, bool,
const location&, const char* = "import");
template <typename T>
import_result<T>
import_direct (bool&,
scope&,
name,
bool, bool, bool,
const location&, const char* = "import");
// The import_direct() equivalent for importing buildfile targets. Return
// empty name if optional and not found. Note that the returned file path is
// not necessarily checked for existence so sourcing it may still fail.
//
// Note also that this function can be used for an ad hoc import by passing
// an absolute target name as would be returned by the normal import (can be
// useful for importing own buildfiles).
//
LIBBUILD2_SYMEXPORT path
import_buildfile (scope& base, name, bool optional, const location&);
// As import phase 2 but only imports as an already existing target. But
// unlike it, this function can be called during the load and execute
// phases.
//
// Note: similar to search_existing().
//
const target*
import_existing (context&, const prerequisite_key&);
// Lower-level components of phase 1 (see implementation for details).
//
pair<name, optional<dir_path>>
import_search (scope& base,
name,
bool optional_,
const optional<string>& metadata, // False or metadata key.
bool subprojects,
const location&,
const char* what = "import");
// As above but also return (in new_value) an indication of whether this
// import is based on a new config.* value. See config::lookup_config()
// for details.
//
LIBBUILD2_SYMEXPORT pair<name, optional<dir_path>>
import_search (bool& new_value,
scope& base,
name,
bool optional_,
const optional<string>& metadata,
bool subprojects,
const location&,
const char* what = "import");
LIBBUILD2_SYMEXPORT pair<names, const scope&>
import_load (context&,
pair<name, optional<dir_path>>,
bool metadata,
const location&);
// Create a build system project in the specified directory.
//
LIBBUILD2_SYMEXPORT void
create_project (
const dir_path&,
const optional<dir_path>& amalgamation,
const strings& boot_modules, // Bootstrap modules.
const string& root_pre, // Extra root.build text.
const strings& root_modules, // Root modules.
const string& root_post, // Extra root.build text.
const optional<string>& config_module, // Config module to load.
const optional<string>& config_file, // Ad hoc config.build contents.
bool buildfile, // Create root buildfile.
const char* who, // Who is creating it.
uint16_t verbosity); // Diagnostic verbosity.
}
#include <libbuild2/file.ixx>
#endif // LIBBUILD2_FILE_HXX
|