7
* Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved.
9
* Please see the accompanying license file, LICENSE.TXT, for information
10
* on using and copying this software.
14
tcmakecl.cpp - TADS Compiler "Make" command line tool
16
Command-line interface to "make" program build utility
20
07/11/99 MJRoberts - Creation
42
* Library parser. This is a specialized version of the library parser
43
* that we use to expand library arguments into their corresponding source
46
class CTcLibParserCmdline: public CTcLibParser
50
* Process a command-line argument that refers to a library. We'll
51
* read the library and add each file mentioned in the library to the
54
* Returns zero on success, non-zero if any errors occur. Fills in
55
* '*nodef' on return to indicate whether or not a "nodef" flag
56
* appeared in the library.
58
static int process_lib_arg(CTcHostIfc *hostifc, CTcMake *mk,
60
const char *lib_name, const char *lib_url,
64
char full_name[OSFNMAX];
66
/* add a default "tl" extension to the library name */
67
strcpy(full_name, lib_name);
68
os_defext(full_name, "tl");
70
/* extract the path name from the library's name */
71
os_get_path_name(path, sizeof(path), lib_name);
74
* add the directory containing the library to the include path,
75
* if it's not already there
77
mk->maybe_add_include_path(path);
79
/* set up our library parser object */
80
CTcLibParserCmdline parser(hostifc, mk, res_list, full_name, lib_url);
82
/* scan the library and add its files to the command line */
85
/* set the 'nodef' indication for the caller */
86
*nodef = parser.nodef_;
88
/* if there are any errors, return non-zero */
89
return parser.get_err_cnt();
94
CTcLibParserCmdline(CTcHostIfc *hostifc, CTcMake *mk,
96
const char *lib_name, const char *lib_url)
97
: CTcLibParser(lib_name)
99
/* remember our host interface */
102
/* remember our 'make' control object */
105
/* remember our resource list container */
106
res_list_ = res_list;
108
/* remember the URL to the library */
109
lib_name_ = lib_copy_str(lib_name);
110
lib_url_ = lib_copy_str(lib_url);
112
/* no "nodef" flag yet */
116
~CTcLibParserCmdline()
118
/* delete the library name and URL strings */
119
lib_free_str(lib_name_);
120
lib_free_str(lib_url_);
123
/* process a source file entry in the library */
124
void scan_full_source(const char *val, const char *fname)
126
char url[OSFNMAX*2 + 20];
129
/* add the source module to our module list */
130
mod = mk_->add_module(fname, 0, 0);
133
* build the full URL for the module - this is the library URL
134
* prefix plus the "source:" value (not the full filename - simply
135
* the original unretouched value of the "source:" variable)
137
sprintf(url, "%.*s%.*s", (int)OSFNMAX, lib_url_, (int)OSFNMAX, val);
139
/* set the module's URL */
142
/* set the module's original name and library name */
143
mod->set_orig_name(val);
144
mod->set_from_lib(lib_name_, lib_url_);
147
/* process a sub-library entry in the library */
148
void scan_full_library(const char *val, const char *fname)
150
char url[OSFNMAX*2 + 20];
154
* build the library URL prefix - this is the parent library URL
155
* prefix, plus our "library:" value (not the full filename -
156
* simply the original unretouched "library:" variable value),
159
sprintf(url, "%.*s%.*s/", (int)OSFNMAX, lib_url_, (int)OSFNMAX, val);
161
/* parse the sub-library */
162
if (process_lib_arg(hostifc_, mk_, res_list_, fname, url, &nodef))
165
* error parsing the sub-library - count it in our own error
166
* count, so we know the parsing failed
172
* if the sub-library had a 'nodef' flag, count it as a 'nodef'
173
* flag in this library
179
/* process a resource entry in the library */
180
void scan_full_resource(const char *val, const char *fname)
182
/* add the resource to the list */
183
res_list_->add_file(fname, val, TRUE);
186
/* display an error */
187
void err_msg(const char *msg, ...)
191
/* display the error */
193
hostifc_->v_print_err(msg, args);
194
hostifc_->print_err("\n");
198
/* look up a preprocessor symbol */
199
int get_pp_symbol(char *dst, size_t dst_len,
200
const char *sym_name, size_t sym_len)
205
/* ask the 'make' control object for the expansion */
206
val = mk_->look_up_pp_sym(sym_name, sym_len);
208
/* if we didn't find a value, return undefined */
212
/* if it fits in the caller's result buffer, copy it */
213
val_len = strlen(val);
214
if (val_len <= dst_len)
215
memcpy(dst, val, val_len);
217
/* return the value length */
221
/* scan a "nodef" flag */
222
void scan_nodef() { nodef_ = TRUE; }
224
/* our 'make' control object */
227
/* our resource list container */
228
CRcResList *res_list_;
230
/* host system interface */
231
CTcHostIfc *hostifc_;
233
/* the library name */
237
* the library URL - this is the common prefix for the URL of every
238
* member of the library
242
/* flag: we've seen a "nodef" flag */
247
/* ------------------------------------------------------------------------ */
249
* Helper object for CTcCommandUtil::parse_opt_file
251
class CMainOptHelper: public CTcOptFileHelper
254
/* allocate an option string */
255
char *alloc_opt_file_str(size_t len) { return lib_alloc_str(len); }
257
/* free an option string previously allocated */
258
void free_opt_file_str(char *str) { lib_free_str(str); }
260
/* process a comment (we ignore comments) */
261
void process_comment_line(const char *) { }
263
/* process a non-comment line (ignore it) */
264
void process_non_comment_line(const char *) { }
266
/* process a configuration section line (ignore it) */
267
void process_config_line(const char *, const char *, int) { }
270
/* ------------------------------------------------------------------------ */
272
* Make a file path relative to the option file path, if we indeed have an
273
* option file path. 'buf' is a buffer the caller provides where we can
274
* build the full path, if necessary. We'll return a pointer either to the
275
* buffer containing the combined path, or to the original filename if we
276
* decided not to use the relative path.
278
static char *make_opt_file_relative(char *buf, size_t buflen,
280
const char *opt_file_path,
286
* if we haven't read an option file, we don't have an option file path
287
* to use as the relative root, so use the original filename unchanged
292
/* convert the name to local conventions */
293
os_cvt_url_dir(buf, buflen < sizeof(lcl) ? buflen : sizeof(lcl),
296
/* if the filename is absolute, use it as given */
297
if (os_is_file_absolute(buf))
301
* we have a relative filename and an option file, so build the given
302
* name relative to the option file path, using the version that we
303
* converted to local conventions
306
os_build_full_path(buf, buflen, opt_file_path, lcl);
308
/* return the caller's buffer where we built the full path */
314
/* ------------------------------------------------------------------------ */
316
* Program main entrypoint
318
int main(int argc, char **argv)
320
CTcHostIfcStdio *hostifc = new CTcHostIfcStdio();
323
int force_build = FALSE;
324
int force_link = FALSE;
326
int err_cnt, warn_cnt;
327
int image_specified = FALSE;
328
char dirbuf[OSFNMAX + 4096];
330
const char *opt_file = 0;
331
char opt_file_path[OSFNMAX];
332
int read_opt_file = FALSE;
333
int usage_err = FALSE;
334
int add_def_mod = TRUE;
335
int compile_only = FALSE;
337
osfildef *string_fp = 0;
338
osfildef *assembly_fp = 0;
339
int sym_dir_set = FALSE;
340
int obj_dir_set = FALSE;
342
CMainOptHelper opt_helper;
343
int opt_file_path_warning = FALSE;
344
int need_opt_file_path_warning;
345
const size_t SUPPRESS_LIST_MAX = 100;
346
int suppress_list[SUPPRESS_LIST_MAX];
348
CTcMakePath *sys_inc_entry;
349
CTcMakePath *sys_lib_entry;
351
int pedantic = FALSE;
352
int res_recurse = TRUE;
353
CRcResList *res_list;
354
int warnings_as_errors = FALSE;
356
/* we don't have any warning codes to suppress yet */
359
/* no errors or warnings yet */
360
err_cnt = warn_cnt = 0;
362
/* create a resource list, in case we have resource options */
363
res_list = new CRcResList();
365
/* initialize the error subsystem */
367
CResLoader *res_loader;
370
/* create a resource loader */
371
os_get_special_path(buf, sizeof(buf), argv[0], OS_GSP_T3_RES);
372
res_loader = new CResLoader(buf);
374
/* tell the resource loader the executable filename, if possible */
375
if (os_get_exe_filename(buf, sizeof(buf), argv[0]))
376
res_loader->set_exe_filename(buf);
378
/* initialize the error subsystem */
379
CTcMain::tc_err_init(1024, res_loader);
381
/* done with the resource loader */
385
/* create the 'make' object */
388
/* presume we'll show the banner and progress messages */
392
* Add the default system header directory to the system include path.
393
* System include paths always follow any user-specified paths in the
396
os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_INC);
397
sys_inc_entry = mk->add_sys_include_path(dirbuf);
400
* Add the user library search path list to the source search path.
401
* This list comes from platform-specific global configuration data
402
* (such as a environment variable on Unix), so we want it to come
403
* after any search list specified in the command-line options; ensure
404
* that we search these locations last by making them "system" paths,
405
* since system paths follow all command-line paths.
407
os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_USER_LIBS);
408
for (p = dirbuf ; *p != '\0' ; )
413
/* remember where this list element starts */
416
/* find the next path separator character */
417
for ( ; *p != '\0' && *p != OSPATHSEP ; ++p) ;
419
/* if there's another path element, note its start */
421
if (*nxt == OSPATHSEP)
424
/* null-terminate the path at the separator */
428
mk->add_sys_source_path(start);
430
/* continue scanning at the next list element */
435
* Add the default system library directory to the source path.
436
* System source paths always follow user-specified paths in the
439
os_get_special_path(dirbuf, sizeof(dirbuf), argv[0], OS_GSP_T3_LIB);
440
sys_lib_entry = mk->add_sys_source_path(dirbuf);
443
/* read the options */
444
for (curarg = 1 ; curarg < argc && argv[curarg][0] == '-' ; ++curarg)
447
char relbuf[OSFNMAX];
450
* if we have a "-source" or "-lib" argument, we're done with
451
* options, and we're on to the module list
453
if (strcmp(argv[curarg], "-source") == 0
454
|| strcmp(argv[curarg], "-lib") == 0
455
|| strcmp(argv[curarg], "-res") == 0)
459
* figure out which option we have, starting with the first letter
462
switch(argv[curarg][1])
465
/* read an options file - make sure we don't have one already */
468
/* can't read a file from a file */
469
printf("error: only one option file (-f) is allowed\n");
475
* remember the options file name - we'll get around to the
476
* actual reading of the file after we finish with the
477
* command line options
479
opt_file = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
481
goto missing_option_arg;
490
/* add preprocessor symbol definition */
491
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
496
/* see if there's an '=' in the string */
497
for (eq = p ; *eq != '\0' && *eq != '=' ; ++eq) ;
499
/* if the '=' is present, replace it with a null byte */
505
/* skip to the start of the replacement text */
509
/* add the symbol definition */
510
mk->def_pp_sym(p, eq);
513
goto missing_option_arg;
517
/* check for longer option names */
518
if (strlen(argv[curarg]) >= 7
519
&& memcmp(argv[curarg], "-errnum", 7) == 0)
521
/* check for "+" or "-" suffixes */
522
if (strcmp(argv[curarg] + 7, "+") == 0
523
|| argv[curarg][7] == '\0')
525
/* turn on error number display */
526
mk->set_show_err_numbers(TRUE);
528
else if (strcmp(argv[curarg] + 7, "-") == 0)
530
/* turn off error number display */
531
mk->set_show_err_numbers(FALSE);
547
/* add preprocess symbol un-definition */
548
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
552
goto missing_option_arg;
556
/* see what follows */
557
switch (argv[curarg][2])
560
/* it's a character set specification */
561
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
563
mk->set_source_charset(p);
565
goto missing_option_arg;
569
/* check for "-clean" */
570
if (strcmp(argv[curarg], "-clean") == 0)
572
/* set "clean" mode */
573
mk->set_clean_mode(TRUE);
583
/* set compile-only (no link) mode */
584
mk->set_do_link(FALSE);
595
/* see what follows */
596
switch(argv[curarg][2])
599
/* force only the link phase */
614
/* set verbose mode */
615
mk->set_verbose(TRUE);
620
/* add a #include path */
621
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
624
/* make it relative to the option file path if appropriate */
625
p = make_opt_file_relative(relbuf, sizeof(relbuf),
626
read_opt_file, opt_file_path, p);
629
mk->add_include_path(p);
632
goto missing_option_arg;
636
/* set the image file name */
637
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 1);
640
/* make it relative to the option file path if appropriate */
641
p = make_opt_file_relative(relbuf, sizeof(relbuf),
642
read_opt_file, opt_file_path, p);
644
/* set the image file name */
645
mk->set_image_file(p);
647
/* note that we have an explicit image file name */
648
image_specified = TRUE;
651
goto missing_option_arg;
655
switch(argv[curarg][2])
659
* if we already have a string capture file, close the
668
/* set the string file */
669
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
671
goto missing_option_arg;
673
/* make it relative to the option file path if appropriate */
674
p = make_opt_file_relative(relbuf, sizeof(relbuf),
675
read_opt_file, opt_file_path, p);
677
/* open the string file */
678
string_fp = osfopwt(p, OSFTTEXT);
681
printf("error: unable to create string capture file "
686
/* set the string capture file in the build object */
687
mk->set_string_capture(string_fp);
693
/* invalid suboption */
699
/* presume we won't need an option file path warning */
700
need_opt_file_path_warning = FALSE;
702
/* note the sub-option letter */
703
subopt = argv[curarg][2];
705
/* get the filename/path argument */
706
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
708
goto missing_option_arg;
710
/* make it relative to the option file path */
711
p = make_opt_file_relative(relbuf, sizeof(relbuf),
712
read_opt_file, opt_file_path, p);
715
* if this is an absolute path, note it so we can warn about it
716
* if this is in an option file
718
need_opt_file_path_warning = os_is_file_absolute(p);
720
/* check the suboption */
724
/* override the system library path */
725
sys_lib_entry->set_path(p);
729
/* override the system include path */
730
sys_inc_entry->set_path(p);
734
/* add the source path */
735
mk->add_source_path(p);
739
/* set the symbol path */
740
mk->set_symbol_dir(p);
742
/* remember that we have a symbol directory */
747
/* set the object file directory */
748
mk->set_object_dir(p);
750
/* remember that we've set this path */
756
* Set the assembly listing file. Note that this is an
757
* undocumented option - at the moment, the assembly
758
* listing is a bit rough, and is meant for internal TADS 3
759
* development use, to facilitate analysis of the
760
* compiler's code generation.
763
/* close any previous assembly listing file */
764
if (assembly_fp != 0)
770
/* open the listing file */
771
assembly_fp = osfopwt(p, OSFTTEXT);
772
if (assembly_fp == 0)
774
printf("error: unable to create assembly listing file "
779
/* set the listing file */
780
mk->set_assembly_listing(assembly_fp);
791
* if we're reading from a command file, and we haven't already
792
* found reason to warn about absolute paths, note that we need
796
&& need_opt_file_path_warning)
797
opt_file_path_warning = TRUE;
803
/* code generation options */
804
if (strcmp(argv[curarg], "-Gstg") == 0)
806
/* turn on sourceTextGroup mode */
807
mk->set_source_text_group_mode(TRUE);
814
/* check what we have */
815
if (strcmp(argv[curarg], "-nopre") == 0)
817
/* explicitly turn off preinit mode */
818
mk->set_preinit(FALSE);
820
else if (strcmp(argv[curarg], "-nobanner") == 0)
822
/* turn off the banner */
825
else if (strcmp(argv[curarg], "-nodef") == 0)
827
/* don't add the default modules */
835
/* check what we have */
836
if (strcmp(argv[curarg], "-pre") == 0)
838
/* explicitly turn on preinit mode */
839
mk->set_preinit(TRUE);
847
* A preprocess-only mode. The plain -P generates
848
* preprocessed source to standard output; -Pi generates only
849
* a list of names of #included files to standard output.
851
if (strcmp(argv[curarg], "-P") == 0)
853
/* set preprocess-only mode */
854
mk->set_pp_only(TRUE);
857
else if (strcmp(argv[curarg], "-Pi") == 0)
859
/* set list-includes mode */
860
mk->set_list_includes(TRUE);
866
/* check the full option name */
867
if (strcmp(argv[curarg], "-quotefname") == 0)
869
/* they want quoted filenames in error messages */
870
mk->set_err_quoted_fnames(TRUE);
872
else if (strcmp(argv[curarg], "-q") == 0)
874
/* quiet mode - turn off banner and progress messages */
876
hostifc->set_show_progress(FALSE);
883
/* check the full option name */
884
if (strcmp(argv[curarg], "-statprefix") == 0)
886
/* get the argument */
887
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 10);
889
/* set the status message prefix text */
891
hostifc->set_status_prefix(p);
893
goto missing_option_arg;
897
/* unknown option - report usage error */
903
/* check the full option name */
904
if (strcmp(argv[curarg], "-test") == 0)
907
* it's the secret test-mode option - the test scripts use
908
* this to set the reporting mode so that we suppress path
909
* names in progress reports, so that the test logs can be
910
* insensitive to local path name conventions
912
mk->set_test_report_mode(TRUE);
914
/* perform any necessary test initialization */
919
/* unknown option - report usage error */
925
/* warning level/mode - see what level they're setting */
926
switch(argv[curarg][2])
933
mk->set_warnings(FALSE);
934
mk->set_pedantic(FALSE);
938
/* normal warnings, but not pedantic warnings */
939
mk->set_warnings(TRUE);
940
mk->set_pedantic(FALSE);
944
/* show all warnings, even pedantic ones */
945
mk->set_warnings(TRUE);
946
mk->set_pedantic(TRUE);
953
* Add/remove a warning to/from the list of warnings to
954
* suppress. First, note whether we're enabling or
955
* disabling the warning.
957
enable = (argv[curarg][2] == '+');
959
/* get the warning number */
960
p = CTcCommandUtil::get_opt_arg(argc, argv, &curarg, 2);
962
goto missing_option_arg;
964
/* convert it to a number */
968
* add it to the list if we're disabling it, otherwise
969
* remove it from the list (since every warning is enabled
974
/* if we don't have room, we can't add it */
975
if (suppress_cnt >= SUPPRESS_LIST_MAX)
977
/* tell them what's wrong */
978
printf("Too many -w-# options - maximum %d.\n",
979
(int)SUPPRESS_LIST_MAX);
985
/* add the new list entry */
986
suppress_list[suppress_cnt++] = num;
995
* scan the list for an existing instance of this
996
* number, and remove any we find
998
for (rem = suppress_cnt, src = dst = suppress_list ;
999
rem != 0 ; ++src, --rem)
1001
/* if this one isn't to be suppressed, keep it */
1006
/* calculate the new count */
1007
suppress_cnt = dst - suppress_list;
1010
/* remember the updated list */
1011
mk->set_suppress_list(suppress_list, suppress_cnt);
1017
/* turn "warnings as errors" mode on or off */
1018
switch (argv[curarg][3])
1022
warnings_as_errors = TRUE;
1023
mk->set_warnings_as_errors(TRUE);
1027
warnings_as_errors = FALSE;
1028
mk->set_warnings_as_errors(FALSE);
1037
/* invalid option */
1043
/* take '?' as an explicit request to show the usage message */
1047
/* check for "-help" */
1048
if (strcmp(argv[curarg], "-help") == 0)
1051
/* other '-h*' options are unrecognized */
1056
/* invalid - describe the problem */
1057
printf("Error: Invalid option: \"%s\"\n"
1058
"(Type \"t3make -help\" for a summary of the "
1059
"command syntax)\n", argv[curarg]);
1065
/* missing option argument */
1066
printf("Error: Missing argument for option \"%s\"\n"
1067
"(Type \"t3make -help\" for a summary of the "
1068
"command syntax)\n", argv[curarg]);
1076
* if there are no module arguments, and no project file was
1077
* specified, look for a default project file
1079
if (curarg >= argc && !usage_err && opt_file == 0)
1082
* if the default project file exists, try reading it; otherwise,
1083
* show a usage error
1085
if (!osfacc(T3_DEFAULT_PROJ_FILE))
1086
opt_file = T3_DEFAULT_PROJ_FILE;
1090
* if there are no arguments at all, just show the usage
1091
* message; otherwise, explain that we need some source files
1095
/* just fall through to the usage message */
1100
/* explain that we need source files */
1101
printf("Error: No source file(s) specified.\n"
1102
"(Type \"t3make -help\" for help with the "
1103
"command syntax.\n");
1110
* Show the banner, unless they explicitly asked us not to (and even
1111
* then, show it anyway if we're going to show the "usage" message).
1113
if ((show_banner || usage_err) && (opt_file == 0 || read_opt_file))
1118
* Generate the patch number or development build iteration number,
1119
* if appropriate. If there's a patch number, give it precedence,
1120
* appending it as an extra dot-number suffix; if there's a build
1121
* number, show it as an alphabetic suffix. If neither is defined,
1122
* add nothing, so we'll just have a three-part dotted version
1125
if (TC_VSN_PATCH != 0)
1126
sprintf(patch_id, ".%d", TC_VSN_PATCH);
1127
else if (TC_VSN_DEVBUILD != 0)
1128
sprintf(patch_id, "%c", TC_VSN_DEVBUILD + 'a' - 1);
1132
/* show the banner */
1133
/* copyright-date-string */
1134
printf("TADS Compiler %d.%d.%d%s "
1135
"Copyright 1999, 2007 Michael J. Roberts\n",
1136
TC_VSN_MAJOR, TC_VSN_MINOR, TC_VSN_REV, patch_id);
1140
* warn about absolute paths in the options file, if necessary; do this
1141
* only in pedantic mode, though, since it's only a usage suggestion
1143
if (opt_file_path_warning && pedantic)
1145
/* show the warning */
1146
printf("Warning: absolute path found in -Fs/-Fo/-Fy option "
1147
"in options (-f) file.\n");
1149
/* add more explanation if in verbose mode */
1151
printf("It's better not to use absolute paths in the "
1152
"options file, because this\n"
1153
"ties the options file to the particular "
1154
"directory layout of your machine. \n"
1155
"If possible, refer only to subfolders of the "
1156
"folder containing the options\n"
1157
"file, and refer to the subfolders using "
1158
"relative path notation.\n");
1161
/* if a usage error occurred, display the usage message */
1165
printf("usage: t3make [options] module ... [-res resources]\n"
1167
" -a - rebuild all files, "
1168
"even if up to date\n"
1169
" -al - relink, even if image file is up to date\n"
1170
" -c - compile only (do not create image file)\n"
1171
" -clean - delete all derived (symbol, object, image) "
1173
" -cs xxx - source file character set is 'xxx'\n"
1174
" -d - compile for debugging (include symbols)\n"
1175
" -D x=y - define preprocessor symbol 'x' with value 'y'\n"
1176
" -errnum - show numeric error codes with error messages\n"
1177
" -f file - read command line options from 'file'\n"
1178
" -I dir - add 'dir' to #include search path\n"
1179
" -Fs dir - add 'dir' to source file search path\n"
1180
" -Fy dir - put symbol files in directory 'dir'\n"
1181
" -Fo dir - put object files in directory 'dir'\n"
1182
" -FI dir - override the standard system include path\n"
1183
" -FL dir - override the standard system library path\n"
1184
" -Gstg - generate sourceTextGroup properties\n"
1185
" -nobanner - suppress version/copyright banner\n"
1186
" -nodef - do not include default library modules in build\n"
1187
" -nopre - do not run pre-initialization, regardless of "
1189
" -o img - set image file name to 'img'\n"
1190
" -Os str - write all strings found in compiled files to "
1192
" -P - preprocess only; write preprocessed source "
1194
" -Pi - preprocess only; write only list of #include "
1195
"files to console\n"
1196
" -pre - run pre-initialization, regardless of "
1198
" -q - quiet mode: suppress banner and "
1199
"progress reports\n"
1200
" -quotefname - quote filenames in error messages\n"
1201
" -statprefix txt - set status-message prefix text\n"
1202
" -U x - un-define preprocessor symbol 'x'\n"
1203
" -v - display verbose error messages\n"
1204
" -w# - warning level: 0=none, 1=standard "
1205
"(default), 2=pedantic\n"
1206
" -w-# - suppress the given warning number\n"
1207
" -w+# - enable the given warning number\n"
1208
" -we - treat warnings as errors (-we- to disable)\n"
1210
"Modules: Each entry in the module list can have one "
1213
" filename - specify the name of a source or "
1214
"library file; the\n"
1215
" file's type is inferred from its "
1217
" -source filename - specify the name of a source file\n"
1218
" -lib filename - specify the name of a library\n"
1220
"The default filename suffix for a source file is \".t\", "
1221
"and the default for a\n"
1222
"library is \".tl\". You can omit the \"-source\" or "
1223
"\"-lib\" specifier for any\n"
1224
"file if its name includes the correct default suffix for "
1225
"its type, and its\n"
1226
"name doesn't begin with a \"-\".\n"
1227
"Immediately following each library, you can add one or more "
1229
"options to exclude library members. Each \"-x\" excludes "
1230
"one library member.\n"
1231
"The filename specified in a \"-x\" option must exactly "
1232
"match the filename as it\n"
1233
"appears in the library \"source:\" line.\n"
1235
"If no modules are specified, the compiler will attempt to "
1236
"find '" T3_DEFAULT_PROJ_FILE "'\n"
1237
"in the current directory, and will read it to obtain build "
1240
"Resources: Multi-media resources can be bundled into the "
1241
"image file using the\n"
1242
"-res option. After the -res option, specify any desired "
1243
"resource options:\n"
1245
" -recurse - recurse into subdirectories for subsequent "
1247
" -norecurse - do not recurse into subdirectories for "
1248
"subsequent items\n"
1249
" file - add 'file' as a multimedia resource\n"
1250
" file=alias - add 'file', using 'alias' as the resource "
1252
" dir - add all files within directory 'dir' (and all "
1254
" subdirectories of 'dir', if -recurse option "
1257
"When a file is specified without an '=alias' name, the "
1258
"stored resource name is\n"
1259
"the original filename converted to URL-style notation. If "
1260
"an '=alias' name is\n"
1261
"specified, then the stored resource will be named with the "
1264
"Note that resource options are ignored when compiling "
1265
"for debugging.\n");
1271
/* add the modules */
1272
for ( ; curarg < argc ; ++curarg)
1276
char relbuf[OSFNMAX];
1278
/* we don't know the file type yet */
1282
/* check to see if we have a module type option */
1283
if (argv[curarg][0] == '-')
1285
if (strcmp(argv[curarg], "-source") == 0)
1287
/* note that we have a source file, and skip the option */
1291
else if (strcmp(argv[curarg], "-lib") == 0)
1293
/* note that we have a library, and skip the option */
1297
else if (strcmp(argv[curarg], "-res") == 0)
1300
* Resource arguments follow - we're done with modules.
1301
* Skip the "-res" argument and exit the module loop.
1308
/* invalid option in the module list */
1313
* if we have no filename argument following the type
1314
* specifier, it's an error
1319
goto missing_option_arg;
1324
* if we didn't find an explicit type specifier, infer the type
1325
* from the filename suffix
1327
if (!is_source && !is_lib)
1332
* if we have a ".tl" suffix, assume it's a library file;
1333
* otherwise, assume it's a source file
1335
if ((len = strlen(argv[curarg])) > 3
1336
&& stricmp(argv[curarg] + len - 3, ".tl") == 0)
1338
/* ".tl" - it's a library file */
1343
/* something else - assume it's a source file */
1348
/* make the filename relative to the option file path */
1349
p = make_opt_file_relative(relbuf, sizeof(relbuf),
1350
read_opt_file, opt_file_path,
1353
/* process the file according to its type */
1358
/* add this file to the module list */
1359
mod = mk->add_module(p, 0, 0);
1361
/* set the module's original name to the name as given */
1362
mod->set_orig_name(argv[curarg]);
1365
* if no image has been specified yet already, use this
1366
* module's name as the image name, with the suffix ".t3"
1368
if (!image_specified)
1373
* build the default image filename by changing the
1374
* module's extension to "t3" (or adding the "t3"
1375
* extension if the module didn't have one to begin with)
1379
os_addext(buf, "t3");
1381
/* set the filename */
1382
mk->set_image_file(buf);
1384
/* note that we know the image file's name now */
1385
image_specified = TRUE;
1390
CTcMakeModule lib_mod;
1391
CTcMakeModule *last_pre_lib_mod;
1392
char fname[OSFNMAX];
1393
char orig_fname[OSFNMAX];
1396
/* add a default "tl" extension */
1398
os_defext(fname, "tl");
1400
/* likewise, add a default "tl" extension to the original name */
1401
strcpy(orig_fname, argv[curarg]);
1402
os_defext(orig_fname, "tl");
1405
* set up a module for the library, so we can easily search
1406
* the source path for the module
1408
lib_mod.set_module_name(fname);
1409
lib_mod.set_search_source_name(orig_fname);
1411
/* get the module name by searching the path if necessary */
1412
mk->get_srcfile(fname, &lib_mod);
1414
/* remember the last module before this library's modules */
1415
last_pre_lib_mod = mk->get_last_module();
1418
* Process the library. Since this is a top-level library
1419
* (rather than a sub-library included from within another
1420
* library), there is no prefix to the URL's of the member
1423
if (CTcLibParserCmdline::process_lib_arg(
1424
hostifc, mk, res_list, fname, "", &nodef))
1427
/* if there was a 'nodef' flag, note it */
1429
add_def_mod = FALSE;
1431
/* process any exclusion options */
1432
while (curarg + 1 < argc && strcmp(argv[curarg+1], "-x") == 0)
1437
/* skip to the "-x" */
1440
/* if the filename is missing, report a usage error */
1441
if (curarg + 1 >= argc)
1442
goto missing_option_arg;
1444
/* skip to the -x's argument and retrieve it */
1445
url = argv[++curarg];
1448
* Start with the next module after the last module before
1449
* this library. If there was nothing before this library,
1450
* then this library's first module is the first module in
1451
* the entire program,.
1453
if ((mod = last_pre_lib_mod) != 0)
1454
mod = mod->get_next();
1456
mod = mk->get_first_module();
1458
/* scan the list of library modules for a match */
1459
for ( ; mod != 0 ; mod = mod->get_next())
1461
/* if this module has the excluded URL, exclude it */
1462
if (stricmp(mod->get_url(), argv[curarg]) == 0)
1464
/* mark this module as excluded */
1465
mod->set_excluded(TRUE);
1468
* no need to look any further - assume each URL
1478
/* if we have any more arguments, they're for resource files */
1479
for ( ; curarg < argc ; ++curarg)
1481
char relbuf[OSFNMAX];
1483
/* check for a resource bundler option */
1484
if (argv[curarg][0] == '-')
1486
/* check the argument */
1487
switch(argv[curarg][1])
1490
/* check for '-norecurse' */
1491
if (strcmp(argv[curarg], "-norecurse") == 0)
1492
res_recurse = FALSE;
1498
/* check for '-recurse' */
1499
if (strcmp(argv[curarg], "-recurse") == 0)
1506
/* unknown option */
1517
* It's not an option, so it must be a file. Scan for an
1518
* alias, which is introduced with an '=' character.
1520
for (p = fname = argv[curarg] ; *p != '\0' && *p != '=' ; ++p) ;
1524
* overwrite the '=' with a null byte, so that the filename
1529
/* the alias starts after the '=' */
1534
/* there's no alias */
1538
/* make the filename relative to the option file path */
1539
fname = make_opt_file_relative(relbuf, sizeof(relbuf),
1540
read_opt_file, opt_file_path,
1543
/* add this file to the resource list*/
1544
res_list->add_file(fname, alias, res_recurse);
1549
* If an option file was specified or implied, and we haven't read
1550
* it yet, read it now.
1552
if (opt_file != 0 && !read_opt_file)
1557
char new_opt_file[OSFNMAX];
1559
/* if the options file doesn't exist, try adding the suffix 't3m' */
1560
if (osfacc(opt_file))
1562
strcpy(new_opt_file, opt_file);
1563
os_defext(new_opt_file, "t3m");
1564
opt_file = new_opt_file;
1567
/* open the options file */
1568
fp = osfoprt(opt_file, OSFTTEXT);
1571
printf("error: unable to read option file \"%s\"\n", opt_file);
1577
* First, parse the file simply to count the arguments. Add in one
1578
* extra argument to make room for making a copy of argv[0].
1580
new_argc = CTcCommandUtil::parse_opt_file(fp, 0, &opt_helper) + 1;
1582
/* rewind the file to parse it again */
1583
osfseek(fp, 0, OSFSK_SET);
1585
/* allocate a new argument list */
1586
new_argv = (char **)t3malloc(new_argc * sizeof(new_argv[0]));
1588
/* copy the program name from argv[0] */
1589
new_argv[0] = argv[0];
1592
* Re-read the file, saving the arguments. Note that we want to
1593
* start saving the arguments from the file at index 1 in the new
1594
* argv array, because we reserve argv[0] to hold the original
1595
* program name argument.
1597
CTcCommandUtil::parse_opt_file(fp, new_argv + 1, &opt_helper);
1599
/* done with the file - close it */
1602
/* start over with the new argument vector */
1607
* note that we've read the options file - we can only do this
1610
read_opt_file = TRUE;
1613
* Note the option file's path prefix. We'll assume that any
1614
* relative filename paths mentioned in the option file are meant
1615
* to be relative to the folder containing the option file itself.
1617
os_get_path_name(opt_file_path, sizeof(opt_file_path), opt_file);
1619
/* go add the new command options */
1624
* Add the default object modules, if appropriate. Do not add the
1625
* default modules unless we're linking.
1627
if (add_def_mod && !compile_only && !pp_only)
1629
char srcname[OSFNMAX];
1632
/* build the full path to the "_main" library module */
1633
os_build_full_path(srcname, sizeof(srcname),
1634
sys_lib_entry->get_path(), "_main");
1636
/* add this as the first module of our compilation */
1637
mod = mk->add_module_first(srcname, 0, 0);
1639
/* set its original name, and note it's from the system library */
1640
mod->set_orig_name("_main");
1641
mod->set_from_syslib();
1645
* If the symbol file and object file directory paths weren't
1646
* explicitly set, set these to the same path used by the image file.
1647
* This will put all of the output files in the same place, if they
1648
* didn't explicitly tell us where to put the different kinds of
1651
os_get_path_name(dirbuf, sizeof(dirbuf), mk->get_image_file());
1653
mk->set_symbol_dir(dirbuf);
1655
mk->set_object_dir(dirbuf);
1657
/* if we encountered any errors parsing a library, we can't proceed */
1661
/* build the program */
1662
mk->build(hostifc, &err_cnt, &warn_cnt,
1663
force_build, force_link, res_list, argv[0]);
1666
/* terminate the error subsystem */
1667
CTcMain::tc_err_term();
1669
/* delete our 'make' object */
1672
/* show the error and warning counts if non-zero */
1673
if (err_cnt != 0 || warn_cnt != 0)
1674
printf("Errors: %d\n"
1675
"Warnings: %d\n", err_cnt, warn_cnt);
1677
/* if we read an options file, delete the memory used for the options */
1683
* delete the argv strings (except for argv[0], which came from
1686
for (i = 1 ; i < argc ; ++i)
1687
opt_helper.free_opt_file_str(argv[i]);
1689
/* delete the argv vector itself */
1693
/* if we have a string capture file, close it */
1697
/* if we have an aassembly listing file, close it */
1698
if (assembly_fp != 0)
1699
osfcls(assembly_fp);
1701
/* delete the host interface */
1704
/* delete the resource list */
1707
/* show any unfreed memory (if we're in a debug build) */
1708
t3_list_memory_blocks(0);
1711
* exit with an appropriate exit code, depending on whether we had
1714
return (err_cnt != 0 || (warnings_as_errors && warn_cnt != 0)
1715
? OSEXFAIL : OSEXSUCC);