]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/tools/build/src/engine/jam.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / tools / build / src / engine / jam.cpp
CommitLineData
7c673cae
FG
1/*
2 * /+\
3 * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
4 * \+/
5 *
6 * This file is part of jam.
7 *
8 * License is hereby granted to use this software and distribute it freely, as
9 * long as this copyright notice is retained and modifications are clearly
10 * marked.
11 *
12 * ALL WARRANTIES ARE HEREBY DISCLAIMED.
13 */
14
15/* This file is ALSO:
16 * Copyright 2001-2004 David Abrahams.
92f5a8d4 17 * Copyright 2018 Rene Rivera
7c673cae 18 * Distributed under the Boost Software License, Version 1.0.
1e59de90
TL
19 * (See accompanying file LICENSE.txt or copy at
20 * https://www.bfgroup.xyz/b2/LICENSE.txt)
7c673cae
FG
21 */
22
23/*
24 * jam.c - make redux
25 *
26 * See Jam.html for usage information.
27 *
28 * These comments document the code.
29 *
30 * The top half of the code is structured such:
31 *
32 * jam
33 * / | \
34 * +---+ | \
35 * / | \
36 * jamgram option \
37 * / | \ \
38 * / | \ \
39 * / | \ |
40 * scan | compile make
41 * | | / | \ / | \
42 * | | / | \ / | \
43 * | | / | \ / | \
44 * jambase parse | rules search make1
45 * | | | \
46 * | | | \
47 * | | | \
48 * builtins timestamp command execute
49 * |
50 * |
51 * |
52 * filesys
53 *
54 *
55 * The support routines are called by all of the above, but themselves are
56 * layered thus:
57 *
58 * variable|expand
59 * / | |
60 * / | |
61 * / | |
62 * lists | pathsys
63 * \ |
64 * \ hash
65 * \ |
66 * \ |
67 * \ |
68 * \ |
69 * \ |
70 * object
71 *
72 * Roughly, the modules are:
73 *
74 * builtins.c - jam's built-in rules
75 * command.c - maintain lists of commands
76 * compile.c - compile parsed jam statements
77 * exec*.c - execute a shell script on a specific OS
78 * file*.c - scan directories and archives on a specific OS
79 * hash.c - simple in-memory hashing routines
80 * hdrmacro.c - handle header file parsing for filename macro definitions
81 * headers.c - handle #includes in source files
7c673cae
FG
82 * jamgram.y - jam grammar
83 * lists.c - maintain lists of strings
84 * make.c - bring a target up to date, once rules are in place
85 * make1.c - execute command to bring targets up to date
86 * object.c - string manipulation routines
87 * option.c - command line option processing
88 * parse.c - make and destroy parse trees as driven by the parser
89 * path*.c - manipulate file names on a specific OS
90 * hash.c - simple in-memory hashing routines
91 * regexp.c - Henry Spencer's regexp
92 * rules.c - access to RULEs, TARGETs, and ACTIONs
93 * scan.c - the jam yacc scanner
94 * search.c - find a target along $(SEARCH) or $(LOCATE)
95 * timestamp.c - get the timestamp of a file or archive member
96 * variable.c - handle jam multi-element variables
97 */
98
99
100#include "jam.h"
92f5a8d4 101
7c673cae
FG
102#include "patchlevel.h"
103
92f5a8d4
TL
104/* Keep JAMVERSYM in sync with VERSION. */
105/* It can be accessed as $(JAMVERSION) in the Jamfile. */
106#define JAM_STRINGIZE(X) JAM_DO_STRINGIZE(X)
107#define JAM_DO_STRINGIZE(X) #X
108#define VERSION_MAJOR_SYM JAM_STRINGIZE(VERSION_MAJOR)
109#define VERSION_MINOR_SYM JAM_STRINGIZE(VERSION_MINOR)
110#define VERSION_PATCH_SYM JAM_STRINGIZE(VERSION_PATCH)
111#define VERSION VERSION_MAJOR_SYM "." VERSION_MINOR_SYM
112#define JAMVERSYM "JAMVERSION=" VERSION
113
7c673cae
FG
114#include "builtins.h"
115#include "class.h"
116#include "compile.h"
117#include "constants.h"
b32b8144 118#include "debugger.h"
7c673cae
FG
119#include "filesys.h"
120#include "function.h"
121#include "hcache.h"
122#include "lists.h"
123#include "make.h"
124#include "object.h"
125#include "option.h"
126#include "output.h"
127#include "parse.h"
128#include "cwd.h"
129#include "rules.h"
130#include "scan.h"
131#include "search.h"
20effc67 132#include "startup.h"
f67539c2 133#include "jam_strings.h"
7c673cae
FG
134#include "timestamp.h"
135#include "variable.h"
b32b8144 136#include "execcmd.h"
92f5a8d4 137#include "sysinfo.h"
7c673cae 138
20effc67
TL
139#include <errno.h>
140#include <string.h>
141
7c673cae
FG
142/* Macintosh is "special" */
143#ifdef OS_MAC
144# include <QuickDraw.h>
145#endif
146
147/* And UNIX for this. */
148#ifdef unix
149# include <sys/utsname.h>
150# include <signal.h>
151#endif
152
153struct globs globs =
154{
155 0, /* noexec */
156 1, /* jobs */
157 0, /* quitquick */
158 0, /* newestfirst */
159 0, /* pipes action stdout and stderr merged to action output */
160#ifdef OS_MAC
161 { 0, 0 }, /* debug - suppress tracing output */
162#else
163 { 0, 1 }, /* debug ... */
164#endif
165 0, /* output commands, not run them */
166 0, /* action timeout */
167 0 /* maximum buffer size zero is all output */
168};
169
170/* Symbols to be defined as true for use in Jambase. */
92f5a8d4 171static const char * othersyms[] = { OSMAJOR, OSMINOR, OSPLAT, JAMVERSYM, 0 };
7c673cae
FG
172
173
7c673cae
FG
174/* on Win32-LCC */
175#if defined( OS_NT ) && defined( __LCC__ )
176# define use_environ _environ
177#endif
178
179#if defined( __MWERKS__)
180# define use_environ _environ
181 extern char * * _environ;
182#endif
183
184#ifndef use_environ
185# define use_environ environ
186# if !defined( __WATCOM__ ) && !defined( OS_OS2 ) && !defined( OS_NT )
187 extern char **environ;
188# endif
189#endif
190
191#if YYDEBUG != 0
192 extern int yydebug;
193#endif
194
195#ifndef NDEBUG
196static void run_unit_tests()
197{
198# if defined( USE_EXECNT )
199 extern void execnt_unit_test();
200 execnt_unit_test();
201# endif
202 string_unit_test();
203}
204#endif
205
206int anyhow = 0;
207
208#ifdef HAVE_PYTHON
209 extern PyObject * bjam_call ( PyObject * self, PyObject * args );
210 extern PyObject * bjam_import_rule ( PyObject * self, PyObject * args );
211 extern PyObject * bjam_define_action( PyObject * self, PyObject * args );
212 extern PyObject * bjam_variable ( PyObject * self, PyObject * args );
213 extern PyObject * bjam_backtrace ( PyObject * self, PyObject * args );
214 extern PyObject * bjam_caller ( PyObject * self, PyObject * args );
215 int python_optimize = 1; /* Set Python optimzation on by default */
216#endif
217
218void regex_done();
219
220char const * saved_argv0;
221
b32b8144
FG
222static void usage( const char * progname )
223{
224 err_printf("\nusage: %s [ options ] targets...\n\n", progname);
225
226 err_printf("-a Build all targets, even if they are current.\n");
227 err_printf("-dx Set the debug level to x (0-13,console,mi).\n");
20effc67 228 err_printf("-fx Read x instead of bootstrap.\n");
b32b8144
FG
229 /* err_printf( "-g Build from newest sources first.\n" ); */
230 err_printf("-jx Run up to x shell commands concurrently.\n");
231 err_printf("-lx Limit actions to x number of seconds after which they are stopped.\n");
232 err_printf("-mx Maximum target output saved (kb), default is to save all output.\n");
233 err_printf("-n Don't actually execute the updating actions.\n");
234 err_printf("-ox Mirror all output to file x.\n");
235 err_printf("-px x=0, pipes action stdout and stderr merged into action output.\n");
236 err_printf("-q Quit quickly as soon as a target fails.\n");
237 err_printf("-sx=y Set variable x=y, overriding environment.\n");
238 err_printf("-tx Rebuild x, even if it is up-to-date.\n");
239 err_printf("-v Print the version of jam and exit.\n");
240#ifdef HAVE_PYTHON
241 err_printf("-z Disable Python Optimization and enable asserts\n");
242#endif
243 err_printf("--x Option is ignored.\n\n");
244
1e59de90 245 b2::clean_exit( EXITBAD );
b32b8144
FG
246}
247
1e59de90 248int guarded_main( int argc, char * * argv )
7c673cae
FG
249{
250 int n;
251 char * s;
252 struct bjam_option optv[ N_OPTS ];
20effc67 253 int status = 0;
7c673cae
FG
254 int arg_c = argc;
255 char * * arg_v = argv;
256 char const * progname = argv[ 0 ];
257 module_t * environ_module;
b32b8144 258 int is_debugger;
92f5a8d4 259 b2::system_info sys_info;
7c673cae
FG
260
261 saved_argv0 = argv[ 0 ];
f67539c2 262 last_update_now_status = 0;
7c673cae 263
b32b8144
FG
264#ifdef JAM_DEBUGGER
265
266 is_debugger = 0;
92f5a8d4 267
b32b8144
FG
268 if ( getoptions( argc - 1, argv + 1, "-:l:m:d:j:p:f:gs:t:ano:qv", optv ) < 0 )
269 usage( progname );
270
271 if ( ( s = getoptval( optv, 'd', 0 ) ) )
272 {
273 if ( strcmp( s, "mi" ) == 0 )
274 {
275 debug_interface = DEBUG_INTERFACE_MI;
276 is_debugger = 1;
277 }
278 else if ( strcmp( s, "console" ) == 0 )
279 {
280 debug_interface = DEBUG_INTERFACE_CONSOLE;
281 is_debugger = 1;
282 }
283 }
284
285#if NT
286
287 if ( argc >= 3 )
288 {
289 /* Check whether this instance is being run by the debugger. */
290 size_t opt_len = strlen( debugger_opt );
291 if ( strncmp( argv[ 1 ], debugger_opt, opt_len ) == 0 &&
292 strncmp( argv[ 2 ], debugger_opt, opt_len ) == 0 )
293 {
294 debug_init_handles( argv[ 1 ] + opt_len, argv[ 2 ] + opt_len );
295 /* Fix up argc/argv to hide the internal options */
296 arg_c = argc = (argc - 2);
297 argv[ 2 ] = argv[ 0 ];
298 arg_v = argv = (argv + 2);
299 debug_interface = DEBUG_INTERFACE_CHILD;
300 }
301 }
302
303 if ( is_debugger )
304 {
305 return debugger();
306 }
307
308#else
309
310 if ( is_debugger )
311 {
312 if ( setjmp( debug_child_data.jmp ) != 0 )
313 {
314 arg_c = argc = debug_child_data.argc;
315 arg_v = argv = (char * *)debug_child_data.argv;
316 debug_interface = DEBUG_INTERFACE_CHILD;
317 }
318 else
319 {
320 return debugger();
321 }
322 }
323
324#endif
325
7c673cae
FG
326#endif
327
328 --argc;
329 ++argv;
330
331 #ifdef HAVE_PYTHON
332 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qvz"
333 #else
334 #define OPTSTRING "-:l:m:d:j:p:f:gs:t:ano:qv"
335 #endif
336
337 if ( getoptions( argc, argv, OPTSTRING, optv ) < 0 )
338 {
b32b8144 339 usage( progname );
7c673cae
FG
340 }
341
92f5a8d4
TL
342 /* Set default parallel jobs to match cpu threads. This can be overridden
343 the usual way with -jX or PARALLELISM env var. */
344 globs.jobs = sys_info.cpu_thread_count();
345
7c673cae
FG
346 /* Version info. */
347 if ( ( s = getoptval( optv, 'v', 0 ) ) )
348 {
92f5a8d4
TL
349 out_printf( "B2 Version %s. %s.\n", VERSION, OSMINOR );
350 out_printf( " Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.\n" );
351 out_printf( " Copyright 2001 David Turner.\n" );
352 out_printf( " Copyright 2001-2004 David Abrahams.\n" );
353 out_printf( " Copyright 2002-2019 Rene Rivera.\n" );
354 out_printf( " Copyright 2003-2015 Vladimir Prus.\n" );
355 out_printf( "\n DEFAULTS: jobs = %i\n", globs.jobs);
7c673cae
FG
356 return EXITOK;
357 }
358
359 /* Pick up interesting options. */
360 if ( ( s = getoptval( optv, 'n', 0 ) ) )
361 {
362 ++globs.noexec;
363 globs.debug[ 2 ] = 1;
364 }
365
366 if ( ( s = getoptval( optv, 'p', 0 ) ) )
367 {
368 /* Undocumented -p3 (acts like both -p1 -p2) means separate pipe action
369 * stdout and stderr.
370 */
371 globs.pipe_action = atoi( s );
372 if ( globs.pipe_action < 0 || 3 < globs.pipe_action )
373 {
374 err_printf( "Invalid pipe descriptor '%d', valid values are -p[0..3]."
375 "\n", globs.pipe_action );
1e59de90 376 b2::clean_exit( EXITBAD );
7c673cae
FG
377 }
378 }
379
380 if ( ( s = getoptval( optv, 'q', 0 ) ) )
381 globs.quitquick = 1;
382
383 if ( ( s = getoptval( optv, 'a', 0 ) ) )
384 anyhow++;
385
386 if ( ( s = getoptval( optv, 'j', 0 ) ) )
387 {
388 globs.jobs = atoi( s );
b32b8144 389 if ( globs.jobs < 1 )
7c673cae 390 {
b32b8144 391 err_printf( "Invalid value for the '-j' option.\n" );
1e59de90 392 b2::clean_exit( EXITBAD );
7c673cae
FG
393 }
394 }
395
396 if ( ( s = getoptval( optv, 'g', 0 ) ) )
397 globs.newestfirst = 1;
398
399 if ( ( s = getoptval( optv, 'l', 0 ) ) )
400 globs.timeout = atoi( s );
401
402 if ( ( s = getoptval( optv, 'm', 0 ) ) )
403 globs.max_buf = atoi( s ) * 1024; /* convert to kb */
404
405 #ifdef HAVE_PYTHON
406 if ( ( s = getoptval( optv, 'z', 0 ) ) )
407 python_optimize = 0; /* disable python optimization */
408 #endif
409
410 /* Turn on/off debugging */
411 for ( n = 0; ( s = getoptval( optv, 'd', n ) ); ++n )
412 {
413 int i;
414
415 /* First -d, turn off defaults. */
416 if ( !n )
417 for ( i = 0; i < DEBUG_MAX; ++i )
418 globs.debug[i] = 0;
419
420 i = atoi( s );
421
422 if ( ( i < 0 ) || ( i >= DEBUG_MAX ) )
423 {
424 out_printf( "Invalid debug level '%s'.\n", s );
425 continue;
426 }
427
428 /* n turns on levels 1-n. */
429 /* +n turns on level n. */
430 if ( *s == '+' )
431 globs.debug[ i ] = 1;
432 else while ( i )
433 globs.debug[ i-- ] = 1;
434 }
435
436 /* If an output file is specified, set globs.out to that. */
437 if ( ( s = getoptval( optv, 'o', 0 ) ) )
438 {
439 if ( !( globs.out = fopen( s, "w" ) ) )
440 {
20effc67
TL
441 err_printf( "[errno %d] failed to write output file '%s': %s",
442 errno, s, strerror(errno) );
1e59de90 443 b2::clean_exit( EXITBAD );
7c673cae
FG
444 }
445 /* ++globs.noexec; */
446 }
447
7c673cae
FG
448 {
449 PROFILE_ENTER( MAIN );
450
451#ifdef HAVE_PYTHON
452 {
453 PROFILE_ENTER( MAIN_PYTHON );
454 Py_OptimizeFlag = python_optimize;
455 Py_Initialize();
456 {
457 static PyMethodDef BjamMethods[] = {
458 {"call", bjam_call, METH_VARARGS,
459 "Call the specified bjam rule."},
460 {"import_rule", bjam_import_rule, METH_VARARGS,
461 "Imports Python callable to bjam."},
462 {"define_action", bjam_define_action, METH_VARARGS,
463 "Defines a command line action."},
464 {"variable", bjam_variable, METH_VARARGS,
465 "Obtains a variable from bjam's global module."},
466 {"backtrace", bjam_backtrace, METH_VARARGS,
467 "Returns bjam backtrace from the last call into Python."},
468 {"caller", bjam_caller, METH_VARARGS,
469 "Returns the module from which the last call into Python is made."},
470 {NULL, NULL, 0, NULL}
471 };
472
473 Py_InitModule( "bjam", BjamMethods );
474 }
475 PROFILE_EXIT( MAIN_PYTHON );
476 }
477#endif
478
479#ifndef NDEBUG
480 run_unit_tests();
481#endif
482#if YYDEBUG != 0
483 if ( DEBUG_PARSE )
484 yydebug = 1;
485#endif
486
487 /* Set JAMDATE. */
488 {
489 timestamp current;
490 timestamp_current( &current );
491 var_set( root_module(), constant_JAMDATE, list_new( outf_time(
492 &current ) ), VAR_SET );
493 }
494
495 /* Set JAM_VERSION. */
496 var_set( root_module(), constant_JAM_VERSION,
497 list_push_back( list_push_back( list_new(
498 object_new( VERSION_MAJOR_SYM ) ),
499 object_new( VERSION_MINOR_SYM ) ),
500 object_new( VERSION_PATCH_SYM ) ),
501 VAR_SET );
502
503 /* Set JAMUNAME. */
504#ifdef unix
505 {
506 struct utsname u;
507
508 if ( uname( &u ) >= 0 )
509 {
510 var_set( root_module(), constant_JAMUNAME,
511 list_push_back(
512 list_push_back(
513 list_push_back(
514 list_push_back(
515 list_new(
516 object_new( u.sysname ) ),
517 object_new( u.nodename ) ),
518 object_new( u.release ) ),
519 object_new( u.version ) ),
520 object_new( u.machine ) ), VAR_SET );
521 }
522 }
523#endif /* unix */
524
525 /* Set JAM_TIMESTAMP_RESOLUTION. */
526 {
527 timestamp fmt_resolution[ 1 ];
528 file_supported_fmt_resolution( fmt_resolution );
529 var_set( root_module(), constant_JAM_TIMESTAMP_RESOLUTION, list_new(
530 object_new( timestamp_timestr( fmt_resolution ) ) ), VAR_SET );
531 }
532
533 /* Load up environment variables. */
534
535 /* First into the global module, with splitting, for backward
536 * compatibility.
537 */
538 var_defines( root_module(), use_environ, 1 );
539
540 environ_module = bindmodule( constant_ENVIRON );
541 /* Then into .ENVIRON, without splitting. */
542 var_defines( environ_module, use_environ, 0 );
543
544 /*
545 * Jam defined variables OS & OSPLAT. We load them after environment, so
546 * that setting OS in environment does not change Jam's notion of the
547 * current platform.
548 */
549 var_defines( root_module(), othersyms, 1 );
550
551 /* Load up variables set on command line. */
552 for ( n = 0; ( s = getoptval( optv, 's', n ) ); ++n )
553 {
554 char * symv[ 2 ];
555 symv[ 0 ] = s;
556 symv[ 1 ] = 0;
557 var_defines( root_module(), symv, 1 );
558 var_defines( environ_module, symv, 0 );
559 }
560
561 /* Set the ARGV to reflect the complete list of arguments of invocation.
562 */
563 for ( n = 0; n < arg_c; ++n )
564 var_set( root_module(), constant_ARGV, list_new( object_new(
565 arg_v[ n ] ) ), VAR_APPEND );
566
567 /* Initialize built-in rules. */
568 load_builtins();
20effc67 569 b2::startup::load_builtins();
7c673cae
FG
570
571 /* Add the targets in the command line to the update list. */
572 for ( n = 1; n < arg_c; ++n )
573 {
574 if ( arg_v[ n ][ 0 ] == '-' )
575 {
92f5a8d4 576 const char * f = "-:l:d:j:f:gs:t:ano:qv";
7c673cae 577 for ( ; *f; ++f ) if ( *f == arg_v[ n ][ 1 ] ) break;
92f5a8d4 578 if ( f[0] && f[1] && ( f[ 1 ] == ':' ) && ( arg_v[ n ][ 2 ] == '\0' ) ) ++n;
7c673cae
FG
579 }
580 else
581 {
582 OBJECT * const target = object_new( arg_v[ n ] );
583 mark_target_for_updating( target );
584 object_free( target );
585 }
586 }
587
92f5a8d4
TL
588 /* The build system may set the PARALLELISM variable to override -j
589 * options.
590 */
591 {
592 LIST * const p = var_get( root_module(), constant_PARALLELISM );
593 if ( !list_empty( p ) )
594 {
595 int const j = atoi( object_str( list_front( p ) ) );
596 if ( j < 1 )
597 out_printf( "Invalid value of PARALLELISM: %s.\n",
598 object_str( list_front( p ) ) );
599 else
600 globs.jobs = j;
601 }
602 }
603
604 /* KEEP_GOING overrides -q option. */
605 {
606 LIST * const p = var_get( root_module(), constant_KEEP_GOING );
607 if ( !list_empty( p ) )
608 globs.quitquick = atoi( object_str( list_front( p ) ) ) ? 0 : 1;
609 }
610
611
7c673cae
FG
612 if ( list_empty( targets_to_update() ) )
613 mark_target_for_updating( constant_all );
614
615 /* Parse ruleset. */
616 {
617 FRAME frame[ 1 ];
618 frame_init( frame );
619 for ( n = 0; ( s = getoptval( optv, 'f', n ) ); ++n )
620 {
621 OBJECT * const filename = object_new( s );
622 parse_file( filename, frame );
623 object_free( filename );
624 }
625
20effc67
TL
626 if ( !n )
627 status = b2::startup::bootstrap(frame) ? 0 : 13;
7c673cae
FG
628 }
629
f67539c2
TL
630 /* FIXME: What shall we do if builtin_update_now,
631 * the sole place setting last_update_now_status,
632 * failed earlier?
633 */
7c673cae 634
20effc67
TL
635 if ( status == 0 )
636 status = yyanyerrors();
637 if ( status == 0 )
7c673cae 638 {
f67539c2
TL
639 /* Manually touch -t targets. */
640 for ( n = 0; ( s = getoptval( optv, 't', n ) ); ++n )
641 {
642 OBJECT * const target = object_new( s );
643 touch_target( target );
644 object_free( target );
645 }
7c673cae 646
f67539c2
TL
647 /* Now make target. */
648 {
649 PROFILE_ENTER( MAIN_MAKE );
650 LIST * const targets = targets_to_update();
651 if ( !list_empty( targets ) )
652 status |= make( targets, anyhow );
653 else
654 status = last_update_now_status;
655 PROFILE_EXIT( MAIN_MAKE );
656 }
7c673cae
FG
657 }
658
659 PROFILE_EXIT( MAIN );
660 }
661
1e59de90
TL
662 return status ? EXITBAD : EXITOK;
663}
664
665int main( int argc, char * * argv )
666{
667 BJAM_MEM_INIT();
668
669#ifdef OS_MAC
670 InitGraf( &qd.thePort );
671#endif
672
673 cwd_init();
674 constants_init();
675
676 int result = EXIT_SUCCESS;
677 try
678 {
679 result = guarded_main( argc, argv );
680 }
681 catch ( b2::exit_result exit_code )
682 {
683 result = (int)exit_code;
684 }
685
7c673cae
FG
686 if ( DEBUG_PROFILE )
687 profile_dump();
688
7c673cae
FG
689#ifdef OPT_HEADER_CACHE_EXT
690 hcache_done();
691#endif
692
693 clear_targets_to_update();
694
695 /* Widely scattered cleanup. */
696 property_set_done();
b32b8144 697 exec_done();
7c673cae
FG
698 file_done();
699 rules_done();
700 timestamp_done();
701 search_done();
702 class_done();
703 modules_done();
704 regex_done();
705 cwd_done();
706 path_done();
707 function_done();
708 list_done();
709 constants_done();
710 object_done();
711
712 /* Close log out. */
713 if ( globs.out )
714 fclose( globs.out );
715
716#ifdef HAVE_PYTHON
717 Py_Finalize();
718#endif
719
720 BJAM_MEM_CLOSE();
721
1e59de90 722 return result;
7c673cae 723}