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