cfad47cfa3/t3compiler/tads3/tcmake.cpp

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
#ifdef RCSID
2
static char RCSid[] =
3
"$Header: d:/cvsroot/tads/tads3/TCMAKE.CPP,v 1.1 1999/07/11 00:46:53 MJRoberts Exp $";
4
#endif
5
6
/* 
7
 *   Copyright (c) 1999, 2002 Michael J. Roberts.  All Rights Reserved.
8
 *   
9
 *   Please see the accompanying license file, LICENSE.TXT, for information
10
 *   on using and copying this software.  
11
 */
12
/*
13
Name
14
  tcmake.cpp - TADS 3 Compiler "Make" Engine
15
Function
16
  The TADS 3 compiler provides automatic dependency maintenance of
17
  derived files through this "make" engine.  The TADS 3 compilation
18
  process, when a program is constructed from several source files
19
  that are compiled separately, is as follows:
20
21
   1.  For each source file, create a symbol export file.
22
   2.  For each source file, load all other symbol export files, then
23
       create an object file from the source file.
24
   3.  Load all object files, and create the image file.
25
   4.  If not compiling for debugging, load the image file, run
26
       preinitialization, and write the updated image file.
27
28
  The dependency tree is as follows:
29
30
   - the ultimate target is the image file
31
   - the image file depends upon all of the object files
32
   - each object file depends upon all of the symbol export files,
33
     plus the single corresponding source file
34
   - each symbol export file depends upon the single corresponding
35
     source file
36
37
Notes
38
  
39
Modified
40
  07/09/99 MJRoberts  - Creation
41
*/
42
43
#include <stdlib.h>
44
#include <string.h>
45
#include <stdio.h>
46
47
#include "os.h"
48
#include "t3std.h"
49
#include "tctok.h"
50
#include "resload.h"
51
#include "tcmain.h"
52
#include "tchost.h"
53
#include "tcglob.h"
54
#include "tcprs.h"
55
#include "tctarg.h"
56
#include "vmfile.h"
57
#include "tcmake.h"
58
#include "vmpreini.h"
59
#include "vmhostsi.h"
60
#include "tcvsn.h"
61
#include "vmmaincn.h"
62
#include "vmrunsym.h"
63
#include "tcunas.h"
64
#include "vmcrc.h"
65
#include "rcmain.h"
66
67
68
/* ------------------------------------------------------------------------ */
69
/*
70
 *   Host interface mapping from our tcmain host interface to the rcmain host
71
 *   interface.  
72
 */
73
class CRcHostIfcTcmake: public CRcHostIfc
74
{
75
public:
76
    CRcHostIfcTcmake(CTcHostIfc *ifc) { ifc_ = ifc; }
77
78
    /* 
79
     *   map the rcmain host interface methods to the equivalents in the
80
     *   tcmain host interface 
81
     */
82
    virtual void display_error(const char *msg)
83
        { ifc_->print_err("%s\n", msg); }
84
    virtual void display_status(const char *msg)
85
        { ifc_->print_step("%s\n", msg); }
86
87
private:
88
    /* our underlying tcmain host interface */
89
    CTcHostIfc *ifc_;
90
};
91
92
/* ------------------------------------------------------------------------ */
93
/*
94
 *   TADS 3 Compiler "Make" engine 
95
 */
96
97
/*
98
 *   initialize 
99
 */
100
CTcMake::CTcMake()
101
{
102
    /* no modules yet */
103
    mod_head_ = mod_tail_ = 0;
104
105
    /* no #include paths yet */
106
    inc_head_ = inc_tail_ = nonsys_inc_tail_ = 0;
107
108
    /* no source paths yet */
109
    src_head_ = src_tail_ = nonsys_src_tail_ = 0;
110
111
    /* no preprocessor symbols defined yet */
112
    def_head_ = def_tail_ = 0;
113
114
    /* assume non-verbose mode */
115
    verbose_ = FALSE;
116
117
    /* assume we won't show error numbers */
118
    show_err_numbers_ = FALSE;
119
120
    /* assume we'll show standard but not pedantic warnings */
121
    show_warnings_ = TRUE;
122
    pedantic_ = FALSE;
123
    warnings_as_errors_ = FALSE;
124
125
    /* we don't have a list of warnings to suppress yet */
126
    suppress_list_ = 0;
127
    suppress_cnt_ = 0;
128
129
    /* assume no debug information */
130
    debug_ = FALSE;
131
132
    /* 
133
     *   assume we're actually compiling, not just preprocessing, listing
134
     *   included files, or cleaning up derived files 
135
     */
136
    pp_only_ = FALSE;
137
    list_includes_mode_ = FALSE;
138
    clean_mode_ = FALSE;
139
140
    /* assume we're not in test reporting mode */
141
    test_report_mode_ = FALSE;
142
143
    /* assume we won't want quoted filenames */
144
    quoted_fname_mode_ = FALSE;
145
146
    /* assume we'll link the program after compiling */
147
    do_link_ = TRUE;
148
149
    /* assume we'll use default preinit mode based on debug mode */
150
    explicit_preinit_ = FALSE;
151
152
    /* set an arbitrary data pool XOR mask */
153
    data_xor_mask_ = 0xDF;
154
155
    /* no source character set has been specified yet */
156
    source_charset_ = 0;
157
158
    /* presume we won't be capturing strings */
159
    string_fp_ = 0;
160
161
    /* presume we won't be generating an assembly listing */
162
    assembly_listing_fp_ = 0;
163
164
    /* assume we won't generate sourceTextGroup properties */
165
    src_group_mode_ = FALSE;
166
}
167
168
/*
169
 *   delete 
170
 */
171
CTcMake::~CTcMake()
172
{
173
    /* delete the modules */
174
    while (mod_head_ != 0)
175
    {
176
        CTcMakeModule *nxt;
177
178
        /* remember the next module */
179
        nxt = mod_head_->get_next();
180
181
        /* delete this one */
182
        delete mod_head_;
183
184
        /* move on to the next one */
185
        mod_head_ = nxt;
186
    }
187
188
    /* delete the #include path list */
189
    while (inc_head_ != 0)
190
    {
191
        CTcMakePath *nxt;
192
193
        /* remember the next one */
194
        nxt = inc_head_->get_next();
195
196
        /* delete this one */
197
        delete inc_head_;
198
199
        /* move on to the next one */
200
        inc_head_ = nxt;
201
    }
202
203
    /* delete the source path list */
204
    while (src_head_ != 0)
205
    {
206
        CTcMakePath *nxt;
207
208
        /* remember the next one */
209
        nxt = src_head_->get_next();
210
211
        /* delete this one */
212
        delete src_head_;
213
214
        /* move on to the next one */
215
        src_head_ = nxt;
216
    }
217
218
    /* delete the preprocessor symbol list */
219
    while (def_head_ != 0)
220
    {
221
        CTcMakeDef *nxt;
222
223
        /* remember the next one */
224
        nxt = def_head_->get_next();
225
226
        /* delete this one */
227
        delete def_head_;
228
229
        /* move on to the next one */
230
        def_head_ = nxt;
231
    }
232
233
    /* delete the source character set name */
234
    lib_free_str(source_charset_);
235
}
236
237
/*
238
 *   Add a preprocessor symbol definition 
239
 */
240
void CTcMake::def_pp_sym(const char *sym, const char *expan)
241
{
242
    /* if there's no expansion, use a default value of "1" */
243
    if (expan == 0)
244
        expan = "1";
245
246
    /* add the symbol to our list */
247
    add_pp_def(sym, expan, TRUE);
248
}
249
250
/*
251
 *   Undefine a preprocessor symbol 
252
 */
253
void CTcMake::undef_pp_sym(const char *sym)
254
{
255
    /* add the symbol to our list */
256
    add_pp_def(sym, 0, FALSE);
257
}
258
259
/*
260
 *   Add a preprocessor symbol define/undefine to our list 
261
 */
262
void CTcMake::add_pp_def(const char *sym, const char *expan, int is_def)
263
{
264
    CTcMakeDef *def;
265
266
    /* create the new list entry */
267
    def = new CTcMakeDef(sym, expan, is_def);
268
269
    /* link it in at the end of our list */
270
    if (def_tail_ != 0)
271
        def_tail_->set_next(def);
272
    else
273
        def_head_ = def;
274
    def_tail_ = def;
275
}
276
277
/*
278
 *   look up a preprocess symbol definition 
279
 */
280
const char *CTcMake::look_up_pp_sym(const char *sym, size_t len)
281
{
282
    CTcMakeDef *def;
283
    const char *found_val;
284
285
    /* iterate over our symbols to find this definition */
286
    for (found_val = 0, def = def_head_ ; def != 0 ; def = def->get_next())
287
    {
288
        /* if this one matches, note it */
289
        if (strlen(def->get_sym()) == len
290
            && memcmp(def->get_sym(), sym, len) == 0)
291
        {
292
            /* 
293
             *   it's a match - if this is a definition, remember it as the
294
             *   latest definition; if it's an undefinition, forget any
295
             *   previous definition we've noted 
296
             */
297
            found_val = (def->is_def() ? def->get_expan() : 0);
298
        }
299
    }
300
301
    /* return the definition we found, if any */
302
    return found_val;
303
}
304
305
/*
306
 *   Add a module at the tail of the list
307
 */
308
void CTcMake::add_module(CTcMakeModule *mod)
309
{
310
    /* add it at the end of our list */
311
    if (mod_tail_ != 0)
312
        mod_tail_->set_next(mod);
313
    else
314
        mod_head_ = mod;
315
    mod_tail_ = mod;
316
    mod->set_next(0);
317
}
318
319
/*
320
 *   Add a module at the head of the list
321
 */
322
void CTcMake::add_module_first(CTcMakeModule *mod)
323
{
324
    /* add it at the end of our list */
325
    mod->set_next(mod_head_);
326
    mod_head_ = mod;
327
328
    /* if it's the first thing in the list, it's the tail as well */
329
    if (mod_tail_ == 0)
330
        mod_tail_ = mod;
331
}
332
333
/*
334
 *   Add a module by filename 
335
 */
336
CTcMakeModule *CTcMake::add_module(const char *src_name,
337
                                   const char *sym_name,
338
                                   const char *obj_name,
339
                                   int first)
340
{
341
    CTcMakeModule *mod;
342
343
    /* create a module object */
344
    mod = new CTcMakeModule();
345
346
    /* set the module name */
347
    mod->set_module_name(src_name);
348
349
    /* set the symbol file name if specified */
350
    if (sym_name != 0)
351
        mod->set_symbol_name(sym_name);
352
353
    /* set the object file name if specified */
354
    if (obj_name != 0)
355
        mod->set_object_name(obj_name);
356
357
    /* add it to the module list */
358
    if (first)
359
        add_module_first(mod);
360
    else
361
        add_module(mod);
362
363
    /* return the new module */
364
    return mod;
365
}
366
367
/*
368
 *   Add a #include path entry
369
 */
370
void CTcMake::add_include_path(const textchar_t *path)
371
{
372
    CTcMakePath *inc;
373
    
374
    /* create the entry */
375
    inc = new CTcMakePath(path);
376
    
377
    /* 
378
     *   add it at the end of our non-system list - note that system files
379
     *   might follow this point, so we need to insert the item into the
380
     *   list after the last existing non-system item 
381
     */
382
    if (nonsys_inc_tail_ == 0)
383
    {
384
        /* no non-system path yet - insert at the head of the list */
385
        inc->set_next(inc_head_);
386
        inc_head_ = inc;
387
    }
388
    else
389
    {
390
        /* insert after the last non-system item */
391
        inc->set_next(nonsys_inc_tail_->get_next());
392
        nonsys_inc_tail_->set_next(inc);
393
    }
394
395
    /* this is the last non-system item */
396
    nonsys_inc_tail_ = inc;
397
398
    /* if this is the last item overall, advance the list tail */
399
    if (inc->get_next() == 0)
400
        inc_tail_ = inc;
401
}
402
403
/*
404
 *   Add a #include path entry if it's not already in our list 
405
 */
406
void CTcMake::maybe_add_include_path(const textchar_t *path)
407
{
408
    CTcMakePath *inc;
409
410
    /* 
411
     *   scan our existing list of include paths for a match to this path -
412
     *   if the path is already in our list, we don't want to bother adding
413
     *   it again 
414
     */
415
    for (inc = inc_head_ ; inc != 0 ; inc = inc->get_next())
416
    {
417
        /* 
418
         *   If this existing path matches the new path, we don't need to
419
         *   bother adding the new path.  Note that we just do a
420
         *   simple-minded string comparison of the paths, which might not
421
         *   always detect equivalent paths (this strategy can be fooled by
422
         *   hard/soft links, differing case in a case-insensitive file
423
         *   system, and relative vs. absolute notation, among other
424
         *   things); this isn't too important, though, because the worst
425
         *   that will happen is that we'll lose a little efficiency by
426
         *   searching the same directory twice.  
427
         */
428
        if (strcmp(inc->get_path(), path) == 0)
429
            return;
430
    }
431
432
    /* didn't find an exact match for the path, so add it */
433
    add_include_path(path);
434
}
435
436
/*
437
 *   Add a system #include path entry 
438
 */
439
CTcMakePath *CTcMake::add_sys_include_path(const textchar_t *path)
440
{
441
    CTcMakePath *inc;
442
443
    /* create the entry */
444
    inc = new CTcMakePath(path);
445
446
    /* add it at the end of our list */
447
    if (inc_tail_ != 0)
448
        inc_tail_->set_next(inc);
449
    else
450
        inc_head_ = inc;
451
    inc_tail_ = inc;
452
    inc->set_next(0);
453
454
    /* return the new path object */
455
    return inc;
456
}
457
458
/*
459
 *   Add a source path entry
460
 */
461
void CTcMake::add_source_path(const textchar_t *path)
462
{
463
    CTcMakePath *src;
464
465
    /* create the entry */
466
    src = new CTcMakePath(path);
467
    
468
    /* 
469
     *   add it at the end of our non-system list - note that system files
470
     *   might follow this point, so we need to insert the item into the
471
     *   list after the last existing non-system item 
472
     */
473
    if (nonsys_src_tail_ == 0)
474
    {
475
        /* no non-system path yet - insert at the head of the list */
476
        src->set_next(src_head_);
477
        src_head_ = src;
478
    }
479
    else
480
    {
481
        /* insert after the last non-system item */
482
        src->set_next(nonsys_src_tail_->get_next());
483
        nonsys_src_tail_->set_next(src);
484
    }
485
486
    /* this is the last non-system item */
487
    nonsys_src_tail_ = src;
488
489
    /* if this is the last item overall, advance the list tail */
490
    if (src->get_next() == 0)
491
        src_tail_ = src;
492
}
493
494
/*
495
 *   Add a system source path entry 
496
 */
497
CTcMakePath *CTcMake::add_sys_source_path(const textchar_t *path)
498
{
499
    CTcMakePath *src;
500
501
    /* create the entry */
502
    src = new CTcMakePath(path);
503
504
    /* add it at the end of our list */
505
    if (src_tail_ != 0)
506
        src_tail_->set_next(src);
507
    else
508
        src_head_ = src;
509
    src_tail_ = src;
510
    src->set_next(0);
511
512
    /* return the object */
513
    return src;
514
}
515
516
/*
517
 *   Check a new module we're adding to make sure its name doesn't collide
518
 *   with an existing module.  Each module is required to have a unique root
519
 *   filename, so flag an error if the module name matches one that's already
520
 *   in the list.  
521
 */
522
void CTcMake::check_module_collision(CTcMakeModule *new_mod)
523
{
524
    const char *new_root;
525
    CTcMakeModule *cur_mod;
526
527
    /* get the root name of this module */
528
    new_root = os_get_root_name((char *)new_mod->get_source_name());
529
530
    /* 
531
     *   Scan the list of modules for a collision.  Stop when we get to this
532
     *   module, because we want to report the collision at the later module,
533
     *   so that we report basically in the order of adding modules to the
534
     *   build.  
535
     */
536
    for (cur_mod = mod_head_ ; cur_mod != 0 && cur_mod != new_mod ;
537
         cur_mod = cur_mod->get_next())
538
    {
539
        const char *cur_root;
540
541
        /* 
542
         *   Compare this module's root name.  Since some file systems are
543
         *   insensitive to case, ignore case ourselves; this is more
544
         *   restrictive than is actually necessary on some systems, but will
545
         *   flag the potential for problems in case the project is later
546
         *   moved to a different operating system.  
547
         */
548
        cur_root = os_get_root_name((char *)cur_mod->get_source_name());
549
        if (stricmp(cur_root, new_root) == 0)
550
        {
551
            char new_name_buf[OSFNMAX*2 + 10];
552
553
            /* if the new module is from a library, so note */
554
            if (new_mod->get_source_type() == TCMOD_SOURCE_NORMAL)
555
            {
556
                /* it's not from a library - just show the module name */
557
                sprintf(new_name_buf, "\"%s\"", new_mod->get_source_name());
558
            }
559
            else
560
            {
561
                /* it is from a library - show the library name as well */
562
                sprintf(new_name_buf,
563
                        tcerr_get_msg(TCERR_SOURCE_FROM_LIB, FALSE),
564
                        new_mod->get_source_name(), new_mod->get_from_lib());
565
            }
566
567
            /*
568
             *   Flag a warning.  If the older module is from a library, use
569
             *   a separate version of the message, so that we can mention
570
             *   the library it's from.  
571
             */
572
            if (cur_mod->get_source_type() == TCMOD_SOURCE_NORMAL)
573
            {
574
                /* the older module isn't from a library */
575
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
576
                                    TCERR_MODULE_NAME_COLLISION,
577
                                    new_name_buf);
578
            }
579
            else
580
            {
581
                /* the older module is in a library, so mention the source */
582
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
583
                                    TCERR_MODULE_NAME_COLLISION_WITH_LIB,
584
                                    new_name_buf, cur_mod->get_from_lib());
585
            }
586
587
            /* 
588
             *   there's no need to find yet another module with the same
589
             *   name - it's good enough to flag the error once 
590
             */
591
            break;
592
        }
593
    }
594
}
595
596
/*
597
 *   Check all modules for name collisions.
598
 */
599
void CTcMake::check_all_module_collisions(CTcHostIfc *hostifc,
600
                                          CResLoader *res_loader,
601
                                          int *err_cnt, int *warn_cnt)
602
{
603
    err_try
604
    {
605
        CTcMakeModule *cur;
606
        
607
        /* initialize the compiler */
608
        CTcMain::init(hostifc, res_loader, source_charset_);
609
610
        /* set options */
611
        set_compiler_options();
612
613
        /* scan all of the modules in our list */
614
        for (cur = mod_head_ ; cur != 0 ; cur = cur->get_next())
615
            check_module_collision(cur);
616
    }
617
    err_finally
618
    {
619
        /* update the caller's error and warning counters */
620
        *err_cnt += G_tcmain->get_error_count();
621
        *warn_cnt += G_tcmain->get_warning_count();
622
623
        /* terminate the compiler */
624
        CTcMain::terminate();
625
    }
626
    err_end;
627
}
628
629
/*
630
 *   Build the program 
631
 */
632
void CTcMake::build(CTcHostIfc *hostifc, int *errcnt, int *warncnt,
633
                    int force_build, int force_link,
634
                    CRcResList *res_list, const char *argv0)
635
{
636
    CResLoader *res_loader;
637
    int fatal_error_count = 0;
638
    CTcMakeModule *mod;
639
    os_file_time_t imgmod;
640
    int build_image;
641
    int run_preinit;
642
    char exe_path[OSFNMAX];
643
    CVmRuntimeSymbols *volatile runtime_symtab = 0;
644
    int seqno;
645
    
646
    /* no warnings or errors so far */
647
    *errcnt = 0;
648
    *warncnt = 0;
649
650
    /* create a resource loader */
651
    os_get_special_path(exe_path, sizeof(exe_path), argv0, OS_GSP_T3_RES);
652
    res_loader = new CResLoader(exe_path);
653
654
    /* set the exectuable filename in the loader, if available */
655
    if (os_get_exe_filename(exe_path, sizeof(exe_path), argv0))
656
        res_loader->set_exe_filename(exe_path);
657
658
    /* 
659
     *   if we don't have an explicit preinit setting, turn preinit on if
660
     *   and only if we're not debugging 
661
     */
662
    if (!explicit_preinit_)
663
        run_preinit = !debug_;
664
    else
665
        run_preinit = preinit_;
666
667
    err_try
668
    {
669
        textchar_t qu_buf[OSFNMAX*2 + 2], qu_buf_out[OSFNMAX*2 + 2];
670
        int step_cnt;
671
        char img_tool_data[4];
672
        CVmCRC32 mod_crc;
673
674
        /* check for module name collisions - give up if we find an error */
675
        check_all_module_collisions(hostifc, res_loader, errcnt, warncnt);
676
        if (*errcnt != 0 || (warnings_as_errors_ && *warncnt != 0))
677
            goto done;
678
679
        /*
680
         *   If we're merely running the preprocessor to generate the
681
         *   preprocessed source or to generate a list of #include files, go
682
         *   through each non-excluded module and preprocess it.  
683
         */
684
        if (pp_only_ || list_includes_mode_)
685
        {
686
            /* preprocess each module */
687
            for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
688
            {
689
                textchar_t srcfile[OSFNMAX];
690
691
                /* if it's an excluded module, skip it */
692
                if (mod->is_excluded())
693
                    continue;
694
695
                /* derive the source file name */
696
                get_srcfile(srcfile, mod);
697
698
                /* preprocess it */
699
                preprocess_source(hostifc, res_loader, srcfile, mod,
700
                                  errcnt, warncnt);
701
            }
702
703
            /* that's all we want to do */
704
            goto done;
705
        }
706
707
        /*
708
         *   If we're in "clean" mode, do nothing except deleting the
709
         *   derived files implied by the command line.  
710
         */
711
        if (clean_mode_)
712
        {
713
            /* clean up each module's derived files */
714
            for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
715
            {
716
                textchar_t fname[OSFNMAX];
717
718
                /* skip any excluded modules */
719
                if (mod->is_excluded())
720
                    continue;
721
722
                /* delete the module's derived symbol file */
723
                get_symfile(fname, mod);
724
                if (!osfacc(fname))
725
                {
726
                    /* report our progress */
727
                    hostifc->print_step("deleting symbol file %s\n",
728
                                        get_step_fname(qu_buf, fname));
729
730
                    /* delete the file */
731
                    if (osfdel(fname))
732
                        hostifc->print_err(
733
                            "error: cannot delete %s\n", fname);
734
                }
735
736
                /* delete the module's derived object file */
737
                get_objfile(fname, mod);
738
                if (!osfacc(fname))
739
                {
740
                    /* report our progress */
741
                    hostifc->print_step("deleting object file %s\n",
742
                                        get_step_fname(qu_buf, fname));
743
744
                    /* delete the file */
745
                    if (osfdel(fname))
746
                        hostifc->print_err(
747
                            "error: cannot delete %s\n", fname);
748
                }
749
            }
750
751
            /* delete the image file */
752
            if (!osfacc(image_fname_.get()))
753
            {
754
                /* report our progress */
755
                hostifc->print_step(
756
                    "deleting image file %s\n",
757
                    get_step_fname(qu_buf, image_fname_.get()));
758
759
                /* delete the file */
760
                if (osfdel(image_fname_.get()))
761
                    hostifc->print_err("error: cannot delete %s\n",
762
                                       image_fname_.get());
763
            }
764
765
            /* that's all we want to do */
766
            goto done;
767
        }
768
769
        /*
770
         *   First, run through the files and determine what work we'll need
771
         *   to do. 
772
         */
773
        for (mod = mod_head_, step_cnt = 0 ; mod != 0 ; mod = mod->get_next())
774
        {
775
            textchar_t srcfile[OSFNMAX];
776
            textchar_t symfile[OSFNMAX];
777
            textchar_t objfile[OSFNMAX];
778
            os_file_time_t srcmod;
779
            os_file_time_t symmod;
780
            os_file_time_t objmod;
781
            int sym_recomp;
782
            int obj_recomp;
783
784
            /* if this module is excluded, skip it */
785
            if (mod->is_excluded())
786
                continue;
787
788
            /* derive the source, symbol, and object file names */
789
            get_srcfile(srcfile, mod);
790
            get_symfile(symfile, mod);
791
            get_objfile(objfile, mod);
792
793
            /* 
794
             *   add this module's source file name into the module-list
795
             *   checksum - we use this to determine if there have been any
796
             *   changes to the module list since the last time we linked the
797
             *   image file, so we can tell if we need to re-link 
798
             */
799
            mod_crc.scan_bytes(srcfile, get_strlen(srcfile));
800
801
            /* presume we will not need to recompile this file */
802
            sym_recomp = FALSE;
803
            obj_recomp = FALSE;
804
805
            /*
806
             *   Check to see if we need to rebuild this symbol file.
807
             *   
808
             *   Get the file times for the source and symbol files.  If
809
             *   either file doesn't exist, or the source modification time
810
             *   is later than the symbol file's modification time, then
811
             *   we'll need to build the symbol file.  
812
             */
813
            if (force_build
814
                || os_get_file_mod_time(&srcmod, srcfile)
815
                || os_get_file_mod_time(&symmod, symfile)
816
                || os_cmp_file_times(&srcmod, &symmod) > 0)
817
            {
818
                /* this symbol file requires recompilation */
819
                sym_recomp = TRUE;
820
            }
821
            else
822
            {
823
                osfildef *fp;
824
                textchar_t sym_fname[OSFNMAX];
825
826
                /*
827
                 *   On the basis of the file system timestamps alone, the
828
                 *   symbol file doesn't require rebuilding.  Check to see if
829
                 *   the configuration data stored in the symbol file is
830
                 *   different from our current configuration - if so, we'll
831
                 *   need to rebuild the symbol file.  
832
                 */
833
                get_symfile(sym_fname, mod);
834
                fp = osfoprb(sym_fname, OSFTT3SYM);
835
                if (fp == 0)
836
                {
837
                    /* there's no symbol file - definitely recompile */
838
                    sym_recomp = TRUE;
839
                }
840
                else
841
                {
842
                    CVmFile *sym_file;
843
                    ulong siz;
844
                    int same_config;
845
846
                    /* set up the symbol file descriptor */
847
                    sym_file = new CVmFile();
848
                    sym_file->set_file(fp, 0);
849
850
                    /* seek to the start of our config data */
851
                    siz = CTcParser::
852
                          seek_sym_file_build_config_info(sym_file);
853
854
                    /* compare the configuration */
855
                    err_try
856
                    {
857
                        /* compare the configuration */
858
                        same_config = compare_build_config_from_sym_file(
859
                            sym_fname, sym_file);
860
                    }
861
                    err_catch(exc)
862
                    {
863
                        /* 
864
                         *   the configuration information is invalid -
865
                         *   assume that recompilation is required 
866
                         */
867
                        same_config = FALSE;
868
                    }
869
                    err_end;
870
871
                    /* 
872
                     *   if we don't have the same configuration, we must
873
                     *   recompile this source file 
874
                     */
875
                    if (!same_config)
876
                    {
877
                        /* note that recompilation is necessary */
878
                        sym_recomp = TRUE;
879
                    }
880
881
                    /* delete the CVmFile object and close the file */
882
                    delete sym_file;
883
                }
884
            }
885
886
            /* note whether or not we have to build the symbol file */
887
            mod->set_needs_sym_recompile(sym_recomp);
888
889
            /* check to see if we need to rebuild it */
890
            if (sym_recomp)
891
            {
892
                /* we do - count the step */
893
                ++step_cnt;
894
895
                /* 
896
                 *   delete the current symbol file - if our build attempt
897
                 *   fails before we get here, this will ensure that we'll
898
                 *   pick up this dependency again on subsequent builds 
899
                 */
900
                osfdel(symfile);
901
            }
902
903
            /*
904
             *   Check to see if we need to rebuild this object file.
905
             *   
906
             *   Check the file times - if the object file doesn't exist, or
907
             *   the source modification time is later than the object file's
908
             *   modification time, we need to build the object file.
909
             *   
910
             *   In addition, if we had to compile the symbol file, it
911
             *   doesn't matter whether the object file is up-to-date with
912
             *   the source file - always rebuild the object file if we had
913
             *   to rebuild the symbol file.
914
             *   
915
             *   Finally, we need to recompile the object file if the symbol
916
             *   file has a more recent timestamp than the object file.  This
917
             *   can happen when a previous build got as far as our symbol
918
             *   file before encountering an error, in which case the object
919
             *   file could appear up-to-date.  
920
             */
921
            if (force_build
922
                || sym_recomp
923
                || os_get_file_mod_time(&srcmod, srcfile)
924
                || os_get_file_mod_time(&objmod, objfile)
925
                || os_get_file_mod_time(&symmod, symfile)
926
                || os_cmp_file_times(&srcmod, &objmod) > 0
927
                || os_cmp_file_times(&symmod, &objmod) > 0)
928
            {
929
                /* we do have to rebuild the object file */
930
                obj_recomp = TRUE;
931
            }
932
933
            /* note whether or not we have to build the object file */
934
            mod->set_needs_obj_recompile(obj_recomp);
935
936
            /* check to see if we need to rebuild the object file */
937
            if (obj_recomp)
938
            {
939
                /* we do - count the step */
940
                ++step_cnt;
941
942
                /* 
943
                 *   delete the object file, to ensure we eventually compile
944
                 *   it even if this attempt fails 
945
                 */
946
                osfdel(objfile);
947
            }
948
        }
949
950
        /* 
951
         *   We've scanned all of the modules now, so we have the checksum
952
         *   value for the source file list.  Store this in our special
953
         *   reserved tool-data field in the image file signature, so that we
954
         *   can check on the next build to see if the module list has
955
         *   changed. 
956
         */
957
        oswp4(img_tool_data, mod_crc.get_crc_val());
958
959
        /*
960
         *   Determine if we need to build the image file.  If any of the
961
         *   existing object files are newer than the image file, we need to
962
         *   build the image.  If we're going to build any object files,
963
         *   they'll definitely be newer, because they don't even exist yet.
964
         *   Build the image regardless of dates if we're forcing a full
965
         *   build or forcing a link.
966
         *   
967
         *   First, check to see if the user even wants us to perform linking
968
         *   - if not, don't build the image file.  Next, check to see if we
969
         *   even need to look at at object file; if the image file doesn't
970
         *   exist, or we're forcing a full build, we don't need to bother
971
         *   checking timestamps.  
972
         */
973
        if (!do_link_)
974
        {
975
            /* the user specifically wants to skip linking the image file */
976
            build_image = FALSE;
977
        }
978
        else if (force_build || force_link
979
                 || os_get_file_mod_time(&imgmod, image_fname_.get()))
980
        {
981
            /* we definitely need to build the image file */
982
            build_image = TRUE;
983
        }
984
        else
985
        {
986
            char sig_buf[45];
987
            osfildef *img_fp;
988
989
            /* presume we won't need to rebuild the image file */
990
            build_image = FALSE;
991
            
992
            /* 
993
             *   Read the "tool data" bytes stored in the image file.  We
994
             *   store a CRC-32 checksum of the names of all of the source
995
             *   files in this field in the image file, so that we can tell
996
             *   if the module list has changed since the last time we
997
             *   linked.  If the module list has changed, we need to rebuild
998
             *   the image file. 
999
             */
1000
            if ((img_fp = osfoprb(image_fname_.get(), OSFTT3IMG)) == 0
1001
                || osfrb(img_fp, sig_buf, 45))
1002
            {
1003
                /* couldn't open/read the file - definitely rebuild */
1004
                build_image = TRUE;
1005
            }
1006
            else
1007
            {
1008
                unsigned long old_crc;
1009
                
1010
                /* read the CRC value from the image file */
1011
                old_crc = t3rp4u(sig_buf + 41);
1012
1013
                /* rebuild if it doesn't match the current signature */
1014
                if (old_crc != mod_crc.get_crc_val())
1015
                    build_image = TRUE;
1016
            }
1017
1018
            /* close the file if we opened it */
1019
            if (img_fp != 0)
1020
                osfcls(img_fp);
1021
1022
            /* if we didn't just decide to rebuild, check module dates */
1023
            if (!build_image)
1024
            {
1025
                /* scan each object module to see if any are more recent */
1026
                for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
1027
                {
1028
                    textchar_t objfile[OSFNMAX];
1029
                    os_file_time_t objmod;
1030
                    
1031
                    /* if this module is excluded, skip it */
1032
                    if (mod->is_excluded())
1033
                        continue;
1034
                    
1035
                    /* 
1036
                     *   if this module is being recompiled, it'll definitely
1037
                     *   be newer than the image file, since we haven't even
1038
                     *   started building the new object file yet 
1039
                     */
1040
                    if (mod->get_needs_obj_recompile())
1041
                    {
1042
                        /* we need to build the image */
1043
                        build_image = TRUE;
1044
                        
1045
                        /* no need to look any further */
1046
                        break;
1047
                    }
1048
                    
1049
                    /* derive the object file name */
1050
                    get_objfile(objfile, mod);
1051
                    
1052
                    /* if it's more recent, we need to build the image */
1053
                    if (os_get_file_mod_time(&objmod, objfile)
1054
                        || os_cmp_file_times(&objmod, &imgmod) > 0)
1055
                    {
1056
                        /* we need to build the image */
1057
                        build_image = TRUE;
1058
1059
                        /* no need to continue scanning object files */
1060
                        break;
1061
                    }
1062
                }
1063
            }
1064
        }
1065
1066
        /* if we have to link the image file, count the step */
1067
        if (build_image)
1068
        {
1069
            /* count the link step */
1070
            ++step_cnt;
1071
1072
            /* count the preinit step if necessary */
1073
            if (run_preinit)
1074
                ++step_cnt;
1075
        }
1076
        
1077
        /* display the initial estimate of the number of build steps */
1078
        if (step_cnt != 0)
1079
            hostifc->print_step("Files to build: %d\n", step_cnt);
1080
1081
        /* assign sequence numbers to the modules */
1082
        for (mod = mod_head_, seqno = 1 ; mod != 0 ; mod = mod->get_next())
1083
            mod->set_seqno(seqno++);
1084
1085
        /*
1086
         *   Build the symbol files.  Go through our list of source files.
1087
         *   For each source file that is more recent than its symbol file,
1088
         *   or for which no symbol file exists, build the symbol file.  
1089
         */
1090
        for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
1091
        {
1092
            /* recompile if necessary */
1093
            if (!mod->is_excluded() && mod->get_needs_sym_recompile())
1094
            {
1095
                textchar_t srcfile[OSFNMAX];
1096
                textchar_t symfile[OSFNMAX];
1097
1098
                /* derive the source and symbol file names */
1099
                get_srcfile(srcfile, mod);
1100
                get_symfile(symfile, mod);
1101
1102
                /* display what we're doing */
1103
                hostifc->print_step("symbol_export %s -> %s\n",
1104
                                    get_step_fname(qu_buf, srcfile),
1105
                                    get_step_fname(qu_buf_out, symfile));
1106
                
1107
                /* we need to build the symbol file */
1108
                build_symbol_file(hostifc, res_loader, srcfile, symfile,
1109
                                  mod, errcnt, warncnt);
1110
1111
                /* if any errors occurred, stop now */
1112
                if (*errcnt != 0 || (warnings_as_errors_ && *warncnt != 0))
1113
                    goto done;
1114
            }
1115
        }
1116
        
1117
        /*
1118
         *   Build object files.  Go through our list of source files.
1119
         *   For each source file that is more recent than its object
1120
         *   file, or for which no object file exists, build the object
1121
         *   file.  
1122
         */
1123
        for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
1124
        {
1125
            /* if this module is excluded, skip it */
1126
            if (!mod->is_excluded() && mod->get_needs_obj_recompile())
1127
            {
1128
                textchar_t srcfile[OSFNMAX];
1129
                textchar_t objfile[OSFNMAX];
1130
1131
                /* derive the source and object file names */
1132
                get_srcfile(srcfile, mod);
1133
                get_objfile(objfile, mod);
1134
            
1135
                /* display what we're doing */
1136
                hostifc->print_step("compile %s -> %s\n",
1137
                                    get_step_fname(qu_buf, srcfile),
1138
                                    get_step_fname(qu_buf_out, objfile));
1139
                
1140
                /* we need to build the object file */
1141
                build_object_file(hostifc, res_loader, srcfile, objfile,
1142
                                  mod, errcnt, warncnt);
1143
                
1144
                /* if any errors occurred, stop now */
1145
                if (*errcnt != 0 || (warnings_as_errors_ && *warncnt != 0))
1146
                    goto done;
1147
            }
1148
        }
1149
        
1150
        /* if we're building the image file, do so now */
1151
        if (build_image)
1152
        {
1153
            const char *link_output;
1154
            char inter_file[OSFNMAX + 10];
1155
1156
            /* 
1157
             *   if we're running preinit, link to an intermediate file,
1158
             *   so that we can wait to store the final preinitialized
1159
             *   version in the actual image file; otherwise, link
1160
             *   directly to the final image filename 
1161
             */
1162
            if (run_preinit)
1163
            {
1164
                /* we'll run preinit - link to an intermediate file */
1165
                lib_strcpy(inter_file, OSFNMAX, image_fname_.get());
1166
                os_remext(inter_file);
1167
                os_addext(inter_file, "t3p");
1168
1169
                /* use the intermediate file as the linker output */
1170
                link_output = inter_file;
1171
1172
                /* 
1173
                 *   we're running preinit, so we need to build a symbol
1174
                 *   table to send it 
1175
                 */
1176
                runtime_symtab = new CVmRuntimeSymbols();
1177
            }
1178
            else
1179
            {
1180
                /* no preinit - link directly to the image filename */
1181
                link_output = image_fname_.get();
1182
            }
1183
            
1184
            /* display what we're doing */
1185
            hostifc->print_step("link -> %s\n",
1186
                                get_step_fname(qu_buf, link_output));
1187
1188
            /* build it */
1189
            build_image_file(hostifc, res_loader, link_output,
1190
                             errcnt, warncnt, runtime_symtab, img_tool_data);
1191
1192
            /* if an error occurred, don't bother with preinit */
1193
            if (*errcnt != 0 || (warnings_as_errors_ && *warncnt != 0))
1194
                goto done;
1195
1196
            /* run preinit if desired */
1197
            if (run_preinit)
1198
            {
1199
                CVmFile *file_in;
1200
                CVmFile *file_out;
1201
                osfildef *fp_in;
1202
                osfildef *fp_out;
1203
                CVmHostIfc *vmhostifc;
1204
                CVmMainClientConsole clientifc;
1205
                
1206
                /* note what we're doing */
1207
                hostifc->print_step(
1208
                    "preinit -> %s\n",
1209
                    get_step_fname(qu_buf, image_fname_.get()));
1210
1211
                /* open the linker output file for reading */
1212
                if ((fp_in = osfoprb(link_output, OSFTT3IMG)) == 0)
1213
                {
1214
                    /* can't open the input file - throw an error */
1215
                    err_throw_a(TCERR_MAKE_CANNOT_OPEN_IMG, 1,
1216
                                ERR_TYPE_CHAR, link_output);
1217
                }
1218
1219
                /* open the final image file for writing */
1220
                if ((fp_out = osfopwb(image_fname_.get(), OSFTT3IMG)) == 0)
1221
                {
1222
                    /* close the input file */
1223
                    osfcls(fp_in);
1224
1225
                    /* throw an error */
1226
                    err_throw_a(TCERR_MAKE_CANNOT_CREATE_IMG, 1,
1227
                                ERR_TYPE_CHAR, image_fname_.get());
1228
                }
1229
1230
                /* set up the input file object */
1231
                file_in = new CVmFile();
1232
                file_in->set_file(fp_in, 0);
1233
1234
                /* set up the output file object */
1235
                file_out = new CVmFile();
1236
                file_out->set_file(fp_out, 0);
1237
1238
                /* create a stdio host interface */
1239
                vmhostifc = new CVmHostIfcStdio(argv0);
1240
1241
                /* catch errors that occur during preinit */
1242
                err_try
1243
                {
1244
                    /* run preinit to build the image file */
1245
                    vm_run_preinit(file_in, link_output,
1246
                                   file_out, vmhostifc, &clientifc, 0, 0,
1247
                                   runtime_symtab);
1248
                }
1249
                err_finally
1250
                {
1251
                    /* delete our VM host interface */
1252
                    delete vmhostifc;
1253
1254
                    /* close and delete our files */
1255
                    delete file_in;
1256
                    delete file_out;
1257
                }
1258
                err_end;
1259
1260
                /* delete the intermediate file */
1261
                osfdel(link_output);
1262
            }
1263
1264
            /* 
1265
             *   if we have any resources to add, and we're not compiling for
1266
             *   debugging, add the resources 
1267
             */
1268
            if (res_list != 0 && res_list->get_count() != 0)
1269
            {
1270
                CRcHostIfcTcmake rc_hostifc(hostifc);
1271
1272
                /* mention what we're doing */
1273
                hostifc->print_step(
1274
                    "add_resource%ss -> %s\n",
1275
                    debug_ ? " link" : "",
1276
                    get_step_fname(qu_buf, image_fname_.get()));
1277
1278
                /* 
1279
                 *   Add the resources.  If we're in debug mode, add them in
1280
                 *   "link mode," meaning that we merely add links from the
1281
                 *   resources to the equivalent local filenames. 
1282
                 */
1283
                if (CResCompMain::add_resources(
1284
                    image_fname_.get(), res_list, &rc_hostifc,
1285
                    FALSE, OSFTT3IMG, debug_))
1286
                {
1287
                    /* failed - delete the image file */
1288
                    osfdel(image_fname_.get());
1289
                }
1290
            }
1291
        }
1292
1293
    done: ;
1294
    }
1295
    err_catch(exc)
1296
    {
1297
        /* 
1298
         *   if it's not a general internal or fatal error, log it; don't
1299
         *   log general errors, since these will have been logged as
1300
         *   specific internal errors before being thrown 
1301
         */
1302
        if (exc->get_error_code() != TCERR_INTERNAL_ERROR
1303
            && exc->get_error_code() != TCERR_FATAL_ERROR)
1304
        {
1305
            /* make sure the host interface is set up */
1306
            G_hostifc = hostifc;
1307
1308
            /* show the error */
1309
            CTcMain::S_log_error(
1310
                0, 0, errcnt, warncnt,
1311
                (verbose_ ? TCMAIN_ERR_VERBOSE : 0)
1312
                | (show_err_numbers_ ? TCMAIN_ERR_NUMBERS : 0)
1313
                | (show_warnings_ ? TCMAIN_ERR_WARNINGS : 0)
1314
                | (pedantic_ ? TCMAIN_ERR_PEDANTIC : 0)
1315
                | (test_report_mode_ ? TCMAIN_ERR_TESTMODE : 0)
1316
                | (quoted_fname_mode_ ? TCMAIN_ERR_FNAME_QU : 0),
1317
                suppress_list_, suppress_cnt_, TC_SEV_FATAL, exc);
1318
        }
1319
1320
        /* count the fatal error */
1321
        ++fatal_error_count;
1322
    }
1323
    err_end;
1324
1325
    /* if we created a runtime symbol table, delete it */
1326
    if (runtime_symtab != 0)
1327
        delete runtime_symtab;
1328
1329
    /* done with the resource loader */
1330
    delete res_loader;
1331
1332
    /* if any fatal errors occurred, include them in the error count */
1333
    *errcnt += fatal_error_count;
1334
}
1335
1336
/*
1337
 *   Build the version of a filename to show in a progress report. 
1338
 */
1339
const char *CTcMake::get_step_fname(char *buf, const char *fname)
1340
{
1341
    /* 
1342
     *   If we're in test-report mode, show only the root name.  We don't
1343
     *   want to show any paths in this mode, because we want our test output
1344
     *   to be independent of the local directory structure; this ensures
1345
     *   that tests can be run on any machine and then diff'ed against
1346
     *   portable reference logs.  
1347
     */
1348
    if (test_report_mode_)
1349
        fname = os_get_root_name((char *)fname);
1350
1351
    /* if we want quoted filenames, quote the filename */
1352
    if (quoted_fname_mode_)
1353
    {
1354
        const char *src;
1355
        char *dst;
1356
1357
        /* add quotes around the filename, and stutter any quotes within */
1358
        for (src = fname, dst = buf + 1, buf[0] = '"' ; *src != '\0' ; )
1359
        {
1360
            /* if this is a quote, stutter it */
1361
            if (*src == '"')
1362
                *dst++ = '"';
1363
1364
            /* add this character */
1365
            *dst++ = *src++;
1366
        }
1367
1368
        /* add the close quote and null terminator */
1369
        *dst++ = '"';
1370
        *dst = '\0';
1371
1372
        /* use the copy in the buffer */
1373
        fname = buf;
1374
    }
1375
1376
    /* return the final filename */
1377
    return fname;
1378
}
1379
1380
/* 
1381
 *   preprocess a source file to standard output
1382
 */
1383
void CTcMake::preprocess_source(CTcHostIfc *hostifc,
1384
                                CResLoader *res_loader,
1385
                                const textchar_t *src_fname,
1386
                                CTcMakeModule *src_mod,
1387
                                int *error_count, int *warning_count)
1388
{
1389
    CTcTokFileDesc *desc;
1390
    long linenum;
1391
1392
    err_try
1393
    {
1394
        int err;
1395
1396
        /* initialize the compiler */
1397
        CTcMain::init(hostifc, res_loader, source_charset_);
1398
1399
        /* set options */
1400
        set_compiler_options();
1401
1402
        /* set up the tokenizer with the main input file */
1403
        err = G_tok->set_source(src_fname, src_mod->get_orig_name());
1404
        if (err != 0)
1405
        {
1406
            G_tcmain->log_error(0, 0, TC_SEV_ERROR, err,
1407
                                (int)strlen(src_fname), src_fname);
1408
            goto done;
1409
        }
1410
1411
        /* 
1412
         *   Put the tokenizer into the appropriate preprocessing mode -
1413
         *   this makes changes to the way it expands certain directives to
1414
         *   make the output suitable for external consumption rather than
1415
         *   internal use.  
1416
         */
1417
        G_tok->set_mode_pp_only(pp_only_);
1418
        G_tok->set_list_includes_mode(list_includes_mode_);
1419
1420
        /* we haven't read anything yet, so we have no previous line info */
1421
        desc = 0;
1422
        linenum = 0;
1423
1424
        /* 
1425
         *   if we're writing out the preprocessed source, write a #charset
1426
         *   directive to indicate that our output is in utf8 format 
1427
         */
1428
        if (pp_only_)
1429
            printf("#charset \"utf8\"\n");
1430
1431
        /* read the file */
1432
        for (;;)
1433
        {
1434
            /* read the next line, and stop if we've reached end of file */
1435
            if (G_tok->read_line_pp())
1436
                break;
1437
1438
            /* 
1439
             *   If we're generating the preprocessed source, and we're in a
1440
             *   different stream than for the last line, or the new line
1441
             *   number is more than the last line number plus 1, add a
1442
             *   #line directive to the output stream 
1443
             */
1444
            if (pp_only_
1445
                && (G_tok->get_last_desc() != desc
1446
                    || G_tok->get_last_linenum() != linenum + 1))
1447
            {
1448
                /* we've jumped to a new line - add a #line directive */
1449
                printf("#line %ld %s\n", G_tok->get_last_linenum(),
1450
                       (test_report_mode_
1451
                        ? G_tok->get_last_desc()->get_dquoted_rootname()
1452
                        : G_tok->get_last_desc()->get_dquoted_fname()));
1453
            }
1454
1455
            /* remember the last line we read */
1456
            desc = G_tok->get_last_desc();
1457
            linenum = G_tok->get_last_linenum();
1458
            
1459
            /* show this line if we're generating preprocessed output */
1460
            if (pp_only_)
1461
                printf("%s\n", G_tok->get_cur_line());
1462
        }
1463
1464
    done: ;
1465
    }
1466
    err_finally
1467
    {
1468
        /* update the caller's error and warning counters */
1469
        *error_count += G_tcmain->get_error_count();
1470
        *warning_count += G_tcmain->get_warning_count();
1471
1472
        /* terminate the compiler */
1473
        CTcMain::terminate();
1474
    }
1475
    err_end;
1476
}
1477
1478
/* 
1479
 *   build a symbol file 
1480
 */
1481
void CTcMake::build_symbol_file(CTcHostIfc *hostifc,
1482
                                CResLoader *res_loader,
1483
                                const textchar_t *src_fname,
1484
                                const textchar_t *sym_fname,
1485
                                CTcMakeModule *src_mod,
1486
                                int *error_count, int *warning_count)
1487
{
1488
    osfildef *fpout;
1489
    CVmFile *volatile fp = 0;
1490
1491
    err_try
1492
    {
1493
        int err;
1494
        
1495
        /* initialize the compiler */
1496
        CTcMain::init(hostifc, res_loader, source_charset_);
1497
1498
        /* set options */
1499
        set_compiler_options();
1500
        
1501
        /* set up the tokenizer with the main input file */
1502
        err = G_tok->set_source(src_fname, src_mod->get_orig_name());
1503
        if (err != 0)
1504
        {
1505
            G_tcmain->log_error(0, 0, TC_SEV_ERROR, err,
1506
                                (int)strlen(src_fname), src_fname);
1507
            goto done;
1508
        }
1509
        
1510
        /* parse in syntax-only mode */
1511
        G_prs->set_syntax_only(TRUE);
1512
1513
        /* read the first token */
1514
        G_tok->next();
1515
1516
        /* give the parser the module information */
1517
        G_prs->set_module_info(
1518
            src_mod->get_orig_name(), src_mod->get_seqno());
1519
1520
        /* set the sourceTextGroup mode */
1521
        G_prs->set_source_text_group_mode(src_group_mode_);
1522
1523
        /* parse at the top level */
1524
        G_prs->parse_top();
1525
1526
        /* if no errors occurred, write the symbol file */
1527
        if (G_tcmain->get_error_count() == 0)
1528
        {
1529
            /* set up the output file */
1530
            fpout = osfopwb(sym_fname, OSFTT3SYM);
1531
            if (fpout == 0)
1532
            {
1533
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1534
                                    TCERR_MAKE_CANNOT_CREATE_SYM, sym_fname);
1535
                goto done;
1536
            }
1537
            fp = new CVmFile();
1538
            fp->set_file(fpout, 0);
1539
1540
            /* write the symbol file */
1541
            G_prs->write_symbol_file(fp, this);
1542
        }
1543
1544
    done: ;
1545
    }
1546
    err_finally
1547
    {
1548
        /* set the caller's error and warning counters */
1549
        *error_count += G_tcmain->get_error_count();
1550
        *warning_count += G_tcmain->get_warning_count();
1551
1552
        /* close our symbol file */
1553
        if (fp != 0)
1554
        {
1555
            delete fp;
1556
            fp = 0;
1557
        }
1558
1559
        /* 
1560
         *   if we weren't successful, delete the symbol file, so that we
1561
         *   don't leave around a partially-built file 
1562
         */
1563
        if (*error_count != 0 || (warnings_as_errors_ && *warning_count != 0))
1564
            osfdel(sym_fname);
1565
        
1566
        /* terminate the compiler */
1567
        CTcMain::terminate();
1568
    }
1569
    err_end;
1570
}
1571
1572
/* 
1573
 *   build an object file
1574
 */
1575
void CTcMake::build_object_file(CTcHostIfc *hostifc,
1576
                                CResLoader *res_loader,
1577
                                const textchar_t *src_fname,
1578
                                const textchar_t *obj_fname,
1579
                                CTcMakeModule *src_mod,
1580
                                int *error_count, int *warning_count)
1581
{
1582
    osfildef *fpout;
1583
    CVmFile *volatile fp = 0;
1584
    CVmFile *volatile symfile = 0;
1585
    int err;
1586
1587
    err_try
1588
    {
1589
        CTPNStmProg *node;
1590
        CTcMakeModule *mod;
1591
        
1592
        /* initialize the compiler */
1593
        CTcMain::init(hostifc, res_loader, source_charset_);
1594
1595
        /* 
1596
         *   keep object and property fixups, so that we can link the
1597
         *   object file with other object files - each object file will
1598
         *   use its own object and property numbering system, and we must
1599
         *   reconcile the systems when we link 
1600
         */
1601
        G_keep_objfixups = TRUE;
1602
        G_keep_propfixups = TRUE;
1603
        G_keep_enumfixups = TRUE;
1604
1605
        /* set options */
1606
        set_compiler_options();
1607
1608
        /* tell the tokenizer to capture strings to the string file */
1609
        if (string_fp_ != 0)
1610
            G_tok->set_string_capture(string_fp_);
1611
1612
        /* tell the code generator to write an assembly listing */
1613
        if (assembly_listing_fp_ != 0)
1614
        {
1615
            /* set up the disassembly output stream */
1616
            G_disasm_out = new CTcUnasOutFile(assembly_listing_fp_);
1617
1618
            /* introduce the file */
1619
            G_disasm_out->print("[%s]\n\n", src_fname);
1620
        }
1621
1622
        /* 
1623
         *   load each module's symbols (including our own - this provides
1624
         *   us with forward definitions of any symbols defined in our own
1625
         *   source module but referenced prior to the definitions) 
1626
         */
1627
        for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
1628
        {
1629
            osfildef *symfp;
1630
            char sym_fname[OSFNMAX];
1631
1632
            /* if this module is excluded, skip it */
1633
            if (mod->is_excluded())
1634
                continue;
1635
            
1636
            /* derive the symbol filename */
1637
            get_symfile(sym_fname, mod);
1638
1639
            /* open the file */
1640
            symfp = osfoprb(sym_fname, OSFTT3SYM);
1641
            if (symfp == 0)
1642
            {
1643
                /* log the error */
1644
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1645
                                    TCERR_MAKE_CANNOT_OPEN_SYM, sym_fname);
1646
            }
1647
            else
1648
            {
1649
                /* set up the file object */
1650
                symfile = new CVmFile();
1651
                symfile->set_file(symfp, 0);
1652
1653
                /* load it */
1654
                G_prs->read_symbol_file(symfile);
1655
1656
                /* done with the symbol file - close it */
1657
                delete symfile;
1658
                symfile = 0;
1659
            }
1660
        }
1661
1662
        /* if we encountered errors reading symbol files, give up now */
1663
        if (G_tcmain->get_error_count() != 0)
1664
            goto done;
1665
1666
        /* set up the tokenizer with the main input file */
1667
        err = G_tok->set_source(src_fname, src_mod->get_orig_name());
1668
        if (err != 0)
1669
        {
1670
            G_tcmain->log_error(0, 0, TC_SEV_ERROR, err,
1671
                                (int)strlen(src_fname), src_fname);
1672
            goto done;
1673
        }
1674
1675
        /* read the first token */
1676
        G_tok->next();
1677
1678
        /* give the parser the module information */
1679
        G_prs->set_module_info(
1680
            src_mod->get_orig_name(), src_mod->get_seqno());
1681
1682
        /* set the sourceTextGroup mode */
1683
        G_prs->set_source_text_group_mode(src_group_mode_);
1684
1685
        /* parse at the top level */
1686
        node = G_prs->parse_top();
1687
        if (G_tcmain->get_error_count() != 0)
1688
            goto done;
1689
1690
        /* fold symbolic constants for all nodes */
1691
        node->fold_constants(G_prs->get_global_symtab());
1692
        if (G_tcmain->get_error_count() != 0)
1693
            goto done;
1694
1695
        /* set up the output file */
1696
        fpout = osfopwb(obj_fname, OSFTT3OBJ);
1697
        if (fpout == 0)
1698
        {
1699
            G_tcmain->log_error(0, 0, TC_SEV_ERROR,
1700
                                TCERR_MAKE_CANNOT_CREATE_OBJ, obj_fname);
1701
            goto done;
1702
        }
1703
        fp = new CVmFile();
1704
        fp->set_file(fpout, 0);
1705
1706
        /* generate code and write the object file */
1707
        node->build_object_file(fp, this);
1708
1709
        /* add an extra blank line in the assembly listing file */
1710
        if (G_disasm_out != 0)
1711
            G_disasm_out->print("\n");
1712
1713
    done: ;
1714
    }
1715
    err_finally
1716
    {
1717
        /* set the caller's error and warning counters */
1718
        *error_count += G_tcmain->get_error_count();
1719
        *warning_count += G_tcmain->get_warning_count();
1720
1721
        /* close our output file */
1722
        if (fp != 0)
1723
        {
1724
            delete fp;
1725
            fp = 0;
1726
        }
1727
1728
        /* if we still have a symbol file open, close it */
1729
        if (symfile != 0)
1730
        {
1731
            delete symfile;
1732
            symfile = 0;
1733
        }
1734
1735
        /* 
1736
         *   if any errors occurred, delete the object file in the
1737
         *   external file system - this prevents us from leaving around
1738
         *   an incomplete or corrupted object file when compilation
1739
         *   fails, and helps 'make'-type tools realize that they must
1740
         *   generate the object file target again on the next build, even
1741
         *   if source file didn't change 
1742
         */
1743
        if (*error_count != 0 || (warnings_as_errors_ && *warning_count != 0))
1744
            osfdel(obj_fname);
1745
1746
        /* terminate the compiler */
1747
        CTcMain::terminate();
1748
    }
1749
    err_end;
1750
}
1751
1752
/*
1753
 *   Read our build configuration information from a symbol file and compare
1754
 *   it to the current configuration.  Returns true if the configurations are
1755
 *   identical, false if not.
1756
 *   
1757
 *   If we find any differences, we won't bother reading further in the file,
1758
 *   so the file's seek offset might be left in the middle of the
1759
 *   configuration data block on return.  
1760
 */
1761
int CTcMake::compare_build_config_from_sym_file(const char *sym_fname,
1762
                                                CVmFile *fp)
1763
{
1764
    CTcMakeDef *def;
1765
    CTcMakePath *path;
1766
    size_t cnt;
1767
    char buf[OSFNMAX + 1];
1768
    os_file_time_t sym_time;
1769
1770
    /* check the compiler version */
1771
    fp->read_bytes(buf, 5);
1772
    if (buf[0] != TC_VSN_MAJOR
1773
        || buf[1] != TC_VSN_MINOR
1774
        || buf[2] != TC_VSN_REV
1775
        || buf[3] != TC_VSN_PATCH
1776
        || buf[4] != TC_VSN_DEVBUILD)
1777
    {
1778
        /* 
1779
         *   the compiler has been updated since this file was compiled;
1780
         *   force a recompilation in case anything has changed in the
1781
         *   compiler 
1782
         */
1783
        return FALSE;
1784
    }
1785
1786
    /* 
1787
     *   read the debug mode - if the debug mode has changed, the
1788
     *   configuration has changed 
1789
     */
1790
    fp->read_bytes(buf, 1);
1791
    if ((buf[0] != 0) != (debug_ != 0))
1792
        return FALSE;
1793
1794
    /* read the -U/-D options */
1795
    for (def = def_head_, cnt = fp->read_int2() ; cnt != 0 ;
1796
         --cnt, def = def->get_next())
1797
    {
1798
        /* 
1799
         *   if we're out of symbols in our list, we seem to have left out
1800
         *   some symbols this time, so the configuration has changed 
1801
         */
1802
        if (def == 0)
1803
            return FALSE;
1804
1805
        /* read and compare the symbol */
1806
        if (!read_and_compare_config_str(fp, def->get_sym()))
1807
            return FALSE;
1808
1809
        /* read and compare the expansion */
1810
        if (!read_and_compare_config_str(fp, def->get_expan()))
1811
            return FALSE;
1812
1813
        /* read and compare the define/undefine flag */
1814
        fp->read_bytes(buf, 1);
1815
        if ((buf[0] != 0) != (def->is_def() != 0))
1816
            return FALSE;
1817
    }
1818
1819
    /* read the #include search path list */
1820
    for (path = inc_head_, cnt = fp->read_int2() ; cnt != 0 ;
1821
         --cnt, path = path->get_next())
1822
    {
1823
        /* if we're out of items in our list, the config has changed */
1824
        if (path == 0)
1825
            return FALSE;
1826
1827
        /* compare this entry */
1828
        if (!read_and_compare_config_str(fp, path->get_path()))
1829
            return FALSE;
1830
    }
1831
1832
    /* 
1833
     *   note the timestamp of the symbol file - if that fails, return a
1834
     *   mismatch, because we won't be able to compare the include file
1835
     *   timestamps to the symbol file timestamp 
1836
     */
1837
    if (os_get_file_mod_time(&sym_time, sym_fname))
1838
        return FALSE;
1839
1840
    /* read the #include file list */
1841
    for (cnt = fp->read_int2() ; cnt != 0 ; --cnt)
1842
    {
1843
        size_t len;
1844
        os_file_time_t inc_time;
1845
        
1846
        /* 
1847
         *   read the next name's length - if it's longer than our buffer,
1848
         *   ignore it and return a mismatch 
1849
         */
1850
        len = fp->read_int2();
1851
        if (len > sizeof(buf) - 1)
1852
            return FALSE;
1853
1854
        /* read the name */
1855
        fp->read_bytes(buf, len);
1856
        buf[len] = '\0';
1857
1858
        /* 
1859
         *   get this file's timestamp - if that fails, the original
1860
         *   include file doesn't even seem to be accessible to us any
1861
         *   more, so we have to try a recompile 
1862
         */
1863
        if (os_get_file_mod_time(&inc_time, buf))
1864
            return FALSE;
1865
1866
        /* 
1867
         *   if the include file has been modified more recently than the
1868
         *   symbol file, we must recompile the source 
1869
         */
1870
        if (os_cmp_file_times(&inc_time, &sym_time) > 0)
1871
            return FALSE;
1872
    }
1873
1874
    /* 
1875
     *   we didn't find any differences in the configuration - indicate
1876
     *   that the configuration is matches 
1877
     */
1878
    return TRUE;
1879
}
1880
1881
/*
1882
 *   Read and compare a single configuration string 
1883
 */
1884
int CTcMake::read_and_compare_config_str(CVmFile *fp, const textchar_t *str)
1885
{
1886
    size_t len;
1887
1888
    /* read the length */
1889
    len = (size_t)fp->read_int2();
1890
1891
    /* if the source string is null, the length must be zero to match */
1892
    if (str == 0 && len != 0)
1893
        return FALSE;
1894
1895
    /* if the lengths don't match, the strings can't match */
1896
    if (len != get_strlen(str))
1897
        return FALSE;
1898
1899
    /* keep going until we exhaust the string */
1900
    while (len != 0)
1901
    {
1902
        char buf[256];
1903
        size_t cur;
1904
1905
        /* read up to a buffer-full, or whatever remains if less */
1906
        cur = sizeof(buf);
1907
        if (len < cur)
1908
            cur = len;
1909
1910
        /* read the data */
1911
        fp->read_bytes(buf, cur);
1912
1913
        /* compare these bytes - if they differ, we don't have a match */
1914
        if (memcmp(str, buf, len) != 0)
1915
            return FALSE;
1916
1917
        /* skip past these bytes of the comparison string */
1918
        str += len;
1919
1920
        /* deduct this amount from the remaining total length */
1921
        len -= cur;
1922
    }
1923
1924
    /* we didn't find any differences - they match */
1925
    return TRUE;
1926
}
1927
1928
/*
1929
 *   Write our build configuration information to a symbol file 
1930
 */
1931
void CTcMake::write_build_config_to_sym_file(CVmFile *fp)
1932
{
1933
    CTcMakeDef *def;
1934
    CTcMakePath *inc;
1935
    CTcTokFileDesc *desc;
1936
    size_t cnt;
1937
    char buf[32];
1938
1939
    /* write the compiler version */
1940
    buf[0] = TC_VSN_MAJOR;
1941
    buf[1] = TC_VSN_MINOR;
1942
    buf[2] = TC_VSN_REV;
1943
    buf[3] = TC_VSN_PATCH;
1944
    buf[4] = TC_VSN_DEVBUILD;
1945
    fp->write_bytes(buf, 5);
1946
1947
    /* write the debug mode */
1948
    buf[0] = (char)debug_;
1949
    fp->write_bytes(buf, 1);
1950
1951
    /* 
1952
     *   Write our list of pre-defined and pre-undefined symbols (-D and
1953
     *   -U options).  If any changes are made to the -D/-U list, we'll
1954
     *   have to rebuild, since these options can change the meaning of
1955
     *   the source code.  
1956
     */
1957
1958
    /* count the symbols in our list */
1959
    for (cnt = 0, def = def_head_ ; def != 0 ;
1960
         def = def->get_next(), ++cnt) ;
1961
1962
    /* write the count */
1963
    fp->write_int2(cnt);
1964
1965
    /* write each option */
1966
    for (def = def_head_ ; def != 0 ; def = def->get_next())
1967
    {
1968
        /* write the symbol */
1969
        fp->write_int2(get_strlen(def->get_sym()));
1970
        fp->write_bytes(def->get_sym(), get_strlen(def->get_sym()));
1971
1972
        /* write the expansion */
1973
        if (def->get_expan() != 0)
1974
        {
1975
            fp->write_int2(get_strlen(def->get_expan()));
1976
            fp->write_bytes(def->get_expan(), get_strlen(def->get_expan()));
1977
        }
1978
        else
1979
            fp->write_int2(0);
1980
1981
        /* write the define/undefine flag */
1982
        buf[0] = (char)def->is_def();
1983
        fp->write_bytes(buf, 1);
1984
    }
1985
    
1986
    /* 
1987
     *   Write the #include search list.  If the search list changes, the
1988
     *   location in which we find a particular header file could change,
1989
     *   hence the text inserted by a #include directive could change,
1990
     *   hence we'd have to rebuild.  
1991
     */
1992
1993
    /* count the list */
1994
    for (cnt = 0, inc = inc_head_ ; inc != 0 ;
1995
         inc = inc->get_next(), ++cnt) ;
1996
1997
    /* write the count */
1998
    fp->write_int2(cnt);
1999
2000
    /* write the list */
2001
    for (inc = inc_head_ ; inc != 0 ; inc = inc->get_next())
2002
    {
2003
        /* write the entry */
2004
        fp->write_int2(get_strlen(inc->get_path()));
2005
        fp->write_bytes(inc->get_path(), get_strlen(inc->get_path()));
2006
    }
2007
2008
    /*
2009
     *   Write the actual list of #include files that were included in the
2010
     *   program.  We'll have to check each of these to see if any of them
2011
     *   have been modified more recently than the symbol file.
2012
     */
2013
2014
    /* get the count */
2015
    cnt = G_tok->get_filedesc_count();
2016
2017
    /* 
2018
     *   start with the second descriptor, because the first is the source
2019
     *   file itself, which isn't part of the include list 
2020
     */
2021
    desc = G_tok->get_first_filedesc();
2022
    if (desc != 0)
2023
    {
2024
        /* skip the first descriptor */
2025
        desc = desc->get_next();
2026
2027
        /* we're not writing it, so don't count it */
2028
        --cnt;
2029
    }
2030
2031
    /* write the count, excluding the actual source file */
2032
    fp->write_int2(cnt);
2033
2034
    /* write the descriptors */
2035
    for ( ; desc != 0 ; desc = desc->get_next())
2036
    {
2037
        /* 
2038
         *   Write the filename string.  Store the fully resolved local
2039
         *   filename, not the original unresolved name, because we want to
2040
         *   be able to detect a change in the configuration that points us
2041
         *   to a different resolved local file.  
2042
         */
2043
        fp->write_int2(get_strlen(desc->get_fname()));
2044
        fp->write_bytes(desc->get_fname(), get_strlen(desc->get_fname()));
2045
    }
2046
}
2047
2048
/*
2049
 *   build an image file 
2050
 */
2051
void CTcMake::build_image_file(CTcHostIfc *hostifc,
2052
                               CResLoader *res_loader,
2053
                               const char *image_fname,
2054
                               int *error_count, int *warning_count,
2055
                               CVmRuntimeSymbols *runtime_symtab,
2056
                               const char tool_data[4])
2057
{
2058
    osfildef *fpout;
2059
    CVmFile *volatile fp = 0;
2060
    CVmFile *volatile objfile = 0;
2061
2062
    err_try
2063
    {
2064
        CTcMakeModule *mod;
2065
2066
        /* initialize the compiler */
2067
        CTcMain::init(hostifc, res_loader, source_charset_);
2068
2069
        /* set options */
2070
        set_compiler_options();
2071
2072
        /* load each object module */
2073
        for (mod = mod_head_ ; mod != 0 ; mod = mod->get_next())
2074
        {
2075
            osfildef *objfp;
2076
            char obj_fname[OSFNMAX];
2077
2078
            /* if this module is excluded, skip it */
2079
            if (mod->is_excluded())
2080
                continue;
2081
2082
            /* derive the object filename */
2083
            get_objfile(obj_fname, mod);
2084
2085
            /* open the file */
2086
            objfp = osfoprb(obj_fname, OSFTT3OBJ);
2087
            if (objfp == 0)
2088
            {
2089
                /* log the error */
2090
                G_tcmain->log_error(0, 0, TC_SEV_ERROR,
2091
                                    TCERR_MAKE_CANNOT_OPEN_OBJ, obj_fname);
2092
            }
2093
            else
2094
            {
2095
                const char *report_fname;
2096
2097
                /* 
2098
                 *   if we're in test reporting mode, use the root name only
2099
                 *   in error reports 
2100
                 */
2101
                if (test_report_mode_)
2102
                    report_fname = os_get_root_name((char *)obj_fname);
2103
                else
2104
                    report_fname = obj_fname;
2105
                
2106
                /* set up the file object */
2107
                objfile = new CVmFile();
2108
                objfile->set_file(objfp, 0);
2109
2110
                /* load it */
2111
                G_cg->load_object_file(objfile, report_fname);
2112
2113
                /* done with the file - close it */
2114
                delete objfile;
2115
                objfile = 0;
2116
            }
2117
        }
2118
2119
        /* if we encountered errors loading object files, give up */
2120
        if (G_tcmain->get_error_count() != 0)
2121
            goto done;
2122
2123
        /* check for unresolved externals */
2124
        if (G_prs->check_unresolved_externs())
2125
            goto done;
2126
2127
        /* set up the output file */
2128
        fpout = osfopwb(image_fname, OSFTT3IMG);
2129
        if (fpout == 0)
2130
        {
2131
            G_tcmain->log_error(0, 0, TC_SEV_ERROR,
2132
                                TCERR_MAKE_CANNOT_CREATE_IMG, image_fname);
2133
            goto done;
2134
        }
2135
        fp = new CVmFile();
2136
        fp->set_file(fpout, 0);
2137
2138
        /* write the image file */
2139
        G_cg->write_to_image(fp, data_xor_mask_, tool_data);
2140
2141
    done: ;
2142
    }
2143
    err_finally
2144
    {
2145
        /* set the caller's error and warning counters */
2146
        *error_count += G_tcmain->get_error_count();
2147
        *warning_count += G_tcmain->get_warning_count();
2148
2149
        /*
2150
         *   If the build succeeded, build the global symbol table to pass
2151
         *   to the pre-initializer, if the caller wants us to.  (We must
2152
         *   build a table separate from the compiler global symbols, since
2153
         *   terminating the compiler will delete the compiler global symbol
2154
         *   table, and because we need the symbols in a different format
2155
         *   for the interpreter anyway.)
2156
         *   
2157
         *   There's no need to build this table if we got any errors during
2158
         *   the build, since we're not producing a valid image file in this
2159
         *   case anyway.  
2160
         */
2161
        if (runtime_symtab != 0 && *error_count == 0)
2162
        {
2163
            /* enumerate the global symbols into our builder callback */
2164
            G_prs->get_global_symtab()
2165
                ->enum_entries(&build_runtime_symtab_cb, runtime_symtab);
2166
        }
2167
2168
        /* close our output file */
2169
        if (fp != 0)
2170
        {
2171
            delete fp;
2172
            fp = 0;
2173
        }
2174
2175
        /* if we still have an object file open, close it */
2176
        if (objfile != 0)
2177
        {
2178
            delete objfile;
2179
            objfile = 0;
2180
        }
2181
2182
        /* 
2183
         *   if any errors occurred, delete the image file in the external
2184
         *   file system - this prevents us from leaving around an
2185
         *   incomplete or corrupted output file when compilation fails,
2186
         *   and helps 'make'-type tools realize that they must generate
2187
         *   the image file target again on the next build, even if source
2188
         *   files didn't change 
2189
         */
2190
        if (*error_count != 0 || (warnings_as_errors_ && *warning_count != 0))
2191
            osfdel(image_fname);
2192
2193
        /* terminate the compiler */
2194
        CTcMain::terminate();
2195
    }
2196
    err_end;
2197
}
2198
2199
/*
2200
 *   Enumeration callback for building the runtime symbol table from the
2201
 *   compiler global symbol table 
2202
 */
2203
void CTcMake::build_runtime_symtab_cb(void *ctx, class CTcSymbol *sym)
2204
{
2205
    CVmRuntimeSymbols *symtab;
2206
    
2207
    /* get our runtime symbol table object (it's the context) */
2208
    symtab = (CVmRuntimeSymbols *)ctx;
2209
2210
    /* build the value for this symbol according to its type */
2211
    sym->add_runtime_symbol(symtab);
2212
}
2213
2214
/*
2215
 *   Set the compiler options
2216
 */
2217
void CTcMake::set_compiler_options()
2218
{
2219
    CTcMakePath *inc;
2220
    CTcMakeDef *def;
2221
    char buf[256];
2222
    
2223
    /* set the error verbosity and warning level modes */
2224
    G_tcmain->set_verbosity(verbose_);
2225
    G_tcmain->set_show_err_numbers(show_err_numbers_);
2226
    G_tcmain->set_pedantic(pedantic_);
2227
    G_tcmain->set_suppress_list(suppress_list_, suppress_cnt_);
2228
    G_tcmain->set_warnings(show_warnings_);
2229
    G_tcmain->set_test_report_mode(test_report_mode_);
2230
    G_tcmain->set_quote_filenames(quoted_fname_mode_);
2231
2232
    /* set debug mode */
2233
    G_debug = debug_;
2234
2235
    /* add the #include path entries */
2236
    for (inc = inc_head_ ; inc != 0 ; inc = inc->get_next())
2237
        G_tok->add_inc_path(inc->get_path());
2238
2239
    /* if we're in debug mode, add the __DEBUG pre-defined macro */
2240
    if (debug_)
2241
        G_tok->add_define("__DEBUG", "1");
2242
2243
    /* 
2244
     *   if we're in test report mode, generate __FILE__ expansions with
2245
     *   root names only 
2246
     */
2247
    if (test_report_mode_)
2248
        G_tok->set_test_report_mode(TRUE);
2249
2250
    /* add the system-name pre-defined macro */
2251
    sprintf(buf, "__TADS_SYS_%s", OS_SYSTEM_NAME);
2252
    G_tok->add_define(buf, "1");
2253
2254
    /* add the pre-defined macro expanding to the system name */
2255
    sprintf(buf, "'%s'", OS_SYSTEM_NAME);
2256
    G_tok->add_define("__TADS_SYSTEM_NAME", buf);
2257
2258
    /* add the major and minor version number macros */
2259
    sprintf(buf, "%d", TC_VSN_MAJOR);
2260
    G_tok->add_define("__TADS_VERSION_MAJOR", buf);
2261
    sprintf(buf, "%d", TC_VSN_MINOR);
2262
    G_tok->add_define("__TADS_VERSION_MINOR", buf);
2263
2264
    /* add a symbol for __TADS3 */
2265
    G_tok->add_define("__TADS3", "1");
2266
2267
    /* add the preprocessor symbol definitions */
2268
    for (def = def_head_ ; def != 0 ; def = def->get_next())
2269
    {
2270
        /* define or undefine the symbol as appropriate */
2271
        if (def->is_def())
2272
            G_tok->add_define(def->get_sym(), def->get_expan());
2273
        else
2274
            G_tok->undefine(def->get_sym());
2275
    }
2276
}
2277
2278
/*
2279
 *   Get the source filename for a module 
2280
 */
2281
void CTcMake::get_srcfile(textchar_t *dst, CTcMakeModule *mod)
2282
{
2283
    CTcMakePath *path;
2284
    
2285
    /* 
2286
     *   if the file has an absolute path already, use the name without
2287
     *   further modification; otherwise, apply our default path 
2288
     */
2289
    if (os_is_file_absolute(mod->get_search_source_name()))
2290
    {
2291
        /* it's absolute - ignore the search path */
2292
        lib_strcpy(dst, OSFNMAX, mod->get_source_name());
2293
        return;
2294
    }
2295
2296
    /*
2297
     *   If the file exists with the name as given (in other words, relative
2298
     *   to the current working directory), use the name as given. 
2299
     */
2300
    if (!osfacc(mod->get_source_name()))
2301
    {
2302
        /* the file exists in the current directory - use the name as given */
2303
        lib_strcpy(dst, OSFNMAX, mod->get_source_name());
2304
        return;
2305
    }
2306
2307
    /* search the source path for the file */
2308
    for (path = src_head_ ; path != 0 ; path = path->get_next())
2309
    {
2310
        /* build the full path for this source path */
2311
        os_build_full_path(dst, OSFNMAX, path->get_path(),
2312
                           mod->get_search_source_name());
2313
2314
        /* if the resulting file exists, return it */
2315
        if (!osfacc(dst))
2316
            return;
2317
    }
2318
2319
    /* 
2320
     *   we failed to find the file anywhere - return the name as given,
2321
     *   which will let the caller fail when it can't open the file 
2322
     */
2323
    lib_strcpy(dst, OSFNMAX, mod->get_source_name());
2324
}
2325
2326
/*
2327
 *   Get the symbol filename for a module 
2328
 */
2329
void CTcMake::get_symfile(textchar_t *dst, CTcMakeModule *mod)
2330
{
2331
    /* 
2332
     *   If a symbol path is specified, remove the path part of the module
2333
     *   name and add the root filename to the symbol path, since the symbol
2334
     *   path overrides any path specified for the source file itself.
2335
     *   Otherwise, use the name as given.  
2336
     */
2337
    if (symdir_.is_set())
2338
        os_build_full_path(dst, OSFNMAX, symdir_.get(),
2339
                           os_get_root_name((char *)mod->get_symbol_name()));
2340
    else
2341
        lib_strcpy(dst, OSFNMAX, mod->get_symbol_name());
2342
}
2343
2344
/*
2345
 *   Get the object filename for a module 
2346
 */
2347
void CTcMake::get_objfile(textchar_t *dst, CTcMakeModule *mod)
2348
{
2349
    /*
2350
     *   If an object path is specified, remove the path part of the module
2351
     *   name and add the root filename to the object path, since the object
2352
     *   path overrides the source file path.  Otherwise, use the name as
2353
     *   given.  
2354
     */
2355
    if (objdir_.is_set())
2356
        os_build_full_path(dst, OSFNMAX, objdir_.get(),
2357
                           os_get_root_name((char *)mod->get_object_name()));
2358
    else
2359
        lib_strcpy(dst, OSFNMAX, mod->get_object_name());
2360
}
2361
2362
2363
/* ------------------------------------------------------------------------ */
2364
/*
2365
 *   Module Object
2366
 */
2367
2368
/*
2369
 *   Set the module name.  Sets the source, symbol, and object filenames
2370
 *   if these are not already set. 
2371
 */
2372
void CTcMakeModule::set_module_name(const textchar_t *modname)
2373
{
2374
    textchar_t buf[OSFNMAX];
2375
2376
    /* set the source name, if it's not already set */
2377
    if (!src_.is_set())
2378
    {
2379
        /* add a default extension of ".t" to make the source name */
2380
        lib_strcpy(buf, sizeof(buf), modname);
2381
        os_defext(buf, "t");
2382
        src_.set(buf);
2383
    }
2384
2385
    /* set the symbol file name, if it's not already set */
2386
    if (!sym_.is_set())
2387
    {
2388
        /* add a default extension of ".t3s" to make the symbol file name */
2389
        lib_strcpy(buf, sizeof(buf), modname);
2390
        os_remext(buf);
2391
        os_addext(buf, "t3s");
2392
        sym_.set(buf);
2393
    }
2394
2395
    /* set the object file name, if it's not already set */
2396
    if (!obj_.is_set())
2397
    {
2398
        /* add a default extension of ".t3o" to make the object name */
2399
        lib_strcpy(buf, sizeof(buf), modname);
2400
        os_remext(buf);
2401
        os_addext(buf, "t3o");
2402
        obj_.set(buf);
2403
    }
2404
}
2405