| | 1 | /* $Header$ */ |
| | 2 | |
| | 3 | /* |
| | 4 | * Copyright (c) 1999, 2002 Michael J. Roberts. All Rights Reserved. |
| | 5 | * |
| | 6 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 7 | * on using and copying this software. |
| | 8 | */ |
| | 9 | /* |
| | 10 | Name |
| | 11 | tcmake.h - TADS 3 Compiler "Make" Engine |
| | 12 | Function |
| | 13 | The "Make" engine doesn't have a main program entrypoint; instead, |
| | 14 | this class is meant to make it easy to write a main entrypoint. The |
| | 15 | program main function must parse command line arguments, read a config |
| | 16 | file, get the parameters from a dialog, or use whatever other OS-specific |
| | 17 | mechanism it desires to obtain the compilation parameters. Given the |
| | 18 | parameters, this class makes it easy to compile the program. |
| | 19 | |
| | 20 | To compile a TADS 3 program, create a CTcMake object, then perform |
| | 21 | the following steps: |
| | 22 | |
| | 23 | - set the build options (source/symbol/object paths, debug mode, |
| | 24 | error options, etc) |
| | 25 | |
| | 26 | - add a module object for each source file |
| | 27 | |
| | 28 | - set the image file name |
| | 29 | |
| | 30 | - invoke build() |
| | 31 | |
| | 32 | Notes |
| | 33 | |
| | 34 | Modified |
| | 35 | 07/11/99 MJRoberts - Creation |
| | 36 | */ |
| | 37 | |
| | 38 | #ifndef TCMAKE_H |
| | 39 | #define TCMAKE_H |
| | 40 | |
| | 41 | #include "t3std.h" |
| | 42 | |
| | 43 | /* ------------------------------------------------------------------------ */ |
| | 44 | /* |
| | 45 | * String buffer object |
| | 46 | */ |
| | 47 | class CTcMakeStr |
| | 48 | { |
| | 49 | public: |
| | 50 | CTcMakeStr() { buf_ = 0; } |
| | 51 | ~CTcMakeStr() { lib_free_str(buf_); } |
| | 52 | |
| | 53 | /* get the string */ |
| | 54 | const textchar_t *get() const { return (buf_ != 0 ? buf_ : ""); } |
| | 55 | |
| | 56 | /* set the string */ |
| | 57 | void set(const textchar_t *str) |
| | 58 | { set(str, str == 0 ? 0 : strlen(str)); } |
| | 59 | void set(const textchar_t *str, size_t len) |
| | 60 | { |
| | 61 | lib_free_str(buf_); |
| | 62 | buf_ = lib_copy_str(str, len); |
| | 63 | } |
| | 64 | |
| | 65 | /* check to see if the string has been set - returns true if so */ |
| | 66 | int is_set() const { return buf_ != 0; } |
| | 67 | |
| | 68 | private: |
| | 69 | /* our string buffer */ |
| | 70 | textchar_t *buf_; |
| | 71 | }; |
| | 72 | |
| | 73 | /* ------------------------------------------------------------------------ */ |
| | 74 | /* |
| | 75 | * Module source types. This tells us how we resolved the given name of |
| | 76 | * the module to a filename. |
| | 77 | */ |
| | 78 | enum tcmod_source_t |
| | 79 | { |
| | 80 | /* "normal" - the module is found on the ordinary search path */ |
| | 81 | TCMOD_SOURCE_NORMAL = 1, |
| | 82 | |
| | 83 | /* the module comes from the system library */ |
| | 84 | TCMOD_SOURCE_SYSLIB = 2, |
| | 85 | |
| | 86 | /* the module comes from a specific user library */ |
| | 87 | TCMOD_SOURCE_LIB = 3 |
| | 88 | }; |
| | 89 | |
| | 90 | |
| | 91 | /* |
| | 92 | * Module list entry. Each module is represented by one of these |
| | 93 | * entries. |
| | 94 | * |
| | 95 | * A module defines a source file and its directly derived files: a |
| | 96 | * symbol file, and an object file. |
| | 97 | */ |
| | 98 | class CTcMakeModule |
| | 99 | { |
| | 100 | public: |
| | 101 | CTcMakeModule() |
| | 102 | { |
| | 103 | /* not in a list yet */ |
| | 104 | nxt_ = 0; |
| | 105 | |
| | 106 | /* presume we won't need recompilation */ |
| | 107 | needs_sym_recompile_ = FALSE; |
| | 108 | needs_obj_recompile_ = FALSE; |
| | 109 | |
| | 110 | /* by default, include all modules in the compilation */ |
| | 111 | exclude_ = FALSE; |
| | 112 | |
| | 113 | /* presume the module is from the ordinary search path */ |
| | 114 | source_type_ = TCMOD_SOURCE_NORMAL; |
| | 115 | |
| | 116 | /* we don't have a sequence number yet */ |
| | 117 | seqno_ = 0; |
| | 118 | } |
| | 119 | ~CTcMakeModule() { } |
| | 120 | |
| | 121 | /* get/set the next list entry */ |
| | 122 | CTcMakeModule *get_next() const { return nxt_; } |
| | 123 | void set_next(CTcMakeModule *nxt) { nxt_ = nxt; } |
| | 124 | |
| | 125 | /* get/set the sequence number */ |
| | 126 | int get_seqno() const { return seqno_; } |
| | 127 | void set_seqno(int n) { seqno_ = n; } |
| | 128 | |
| | 129 | /* |
| | 130 | * Set the module name. This will fill in the source, symbol, and |
| | 131 | * object filenames with names derived from the source name if those |
| | 132 | * names are not already defined. If any of the names are already |
| | 133 | * explicitly defined, this won't affect them. |
| | 134 | */ |
| | 135 | void set_module_name(const textchar_t *modname); |
| | 136 | |
| | 137 | /* |
| | 138 | * Get/set the original module name. The original module name is the |
| | 139 | * name as it was given on the command line, in the library source, or |
| | 140 | * wherever else it was originally specified. This is the name before |
| | 141 | * conversion to local filename conventions and before resolving to a |
| | 142 | * specific directory; this is useful in debugging records because it |
| | 143 | * can be more portable than the resolved filename. |
| | 144 | */ |
| | 145 | const textchar_t *get_orig_name() const { return orig_name_.get(); } |
| | 146 | void set_orig_name(const textchar_t *name) { orig_name_.set(name); } |
| | 147 | |
| | 148 | /* get/set the source filename */ |
| | 149 | const textchar_t *get_source_name() const { return src_.get(); } |
| | 150 | void set_source_name(const textchar_t *fname) { src_.set(fname); } |
| | 151 | |
| | 152 | /* |
| | 153 | * Get/set the "search" source filename. This is the filename we use |
| | 154 | * when we're trying to find the file in a search path. In some cases, |
| | 155 | * this might not be identical to the given filename; for example, when |
| | 156 | * we assume a relative path for a file, we won't use the assumed |
| | 157 | * relative path in the search name, since we only assumed the relative |
| | 158 | * path because we thought that would tell us where the file is. |
| | 159 | */ |
| | 160 | const textchar_t *get_search_source_name() const |
| | 161 | { |
| | 162 | /* |
| | 163 | * if there's an explicit search name, use it; otherwise, simply |
| | 164 | * use the normal source name |
| | 165 | */ |
| | 166 | if (search_src_.get() != 0 && search_src_.get()[0] != '\0') |
| | 167 | return search_src_.get(); |
| | 168 | else |
| | 169 | return src_.get(); |
| | 170 | } |
| | 171 | void set_search_source_name(const textchar_t *fname) |
| | 172 | { search_src_.set(fname); } |
| | 173 | |
| | 174 | /* get/set the symbol filename */ |
| | 175 | const textchar_t *get_symbol_name() const { return sym_.get(); } |
| | 176 | void set_symbol_name(const textchar_t *fname) { sym_.set(fname); } |
| | 177 | |
| | 178 | /* get/set the object filename */ |
| | 179 | const textchar_t *get_object_name() const { return obj_.get(); } |
| | 180 | void set_object_name(const textchar_t *fname) { obj_.set(fname); } |
| | 181 | |
| | 182 | /* get/set the symbol file recompilation flag */ |
| | 183 | int get_needs_sym_recompile() const { return needs_sym_recompile_; } |
| | 184 | void set_needs_sym_recompile(int flag) { needs_sym_recompile_ = flag; } |
| | 185 | |
| | 186 | /* get/set the object file recompilation flag */ |
| | 187 | int get_needs_obj_recompile() const { return needs_obj_recompile_; } |
| | 188 | void set_needs_obj_recompile(int flag) { needs_obj_recompile_ = flag; } |
| | 189 | |
| | 190 | /* get/set the exclusion flag */ |
| | 191 | int is_excluded() const { return exclude_; } |
| | 192 | void set_excluded(int exc) { exclude_ = exc; } |
| | 193 | |
| | 194 | /* get/set the library member URL */ |
| | 195 | const char *get_url() const { return url_.get(); } |
| | 196 | void set_url(const char *url) { url_.set(url); } |
| | 197 | |
| | 198 | /* get the module's source type */ |
| | 199 | tcmod_source_t get_source_type() const { return source_type_; } |
| | 200 | |
| | 201 | /* set the module's source to the system library */ |
| | 202 | void set_from_syslib() { source_type_ = TCMOD_SOURCE_SYSLIB; } |
| | 203 | |
| | 204 | /* |
| | 205 | * set the module's source to the given library, specified via |
| | 206 | * URL-style library path (so a module in library 'bar' that was in |
| | 207 | * turn in library 'foo' will have library path 'foo/bar') |
| | 208 | */ |
| | 209 | void set_from_lib(const textchar_t *libname, const textchar_t *url) |
| | 210 | { |
| | 211 | /* save the library's name and URL */ |
| | 212 | lib_name_.set(libname); |
| | 213 | lib_url_.set(url); |
| | 214 | |
| | 215 | /* remember that we're from a library */ |
| | 216 | source_type_ = TCMOD_SOURCE_LIB; |
| | 217 | } |
| | 218 | |
| | 219 | /* get our library URL */ |
| | 220 | const textchar_t *get_from_lib() const { return lib_name_.get(); } |
| | 221 | |
| | 222 | protected: |
| | 223 | /* next entry in the list */ |
| | 224 | CTcMakeModule *nxt_; |
| | 225 | |
| | 226 | /* source filename */ |
| | 227 | CTcMakeStr src_; |
| | 228 | |
| | 229 | /* |
| | 230 | * sequence number - this is simply an ordinal giving our position in |
| | 231 | * the list of modules making up the build |
| | 232 | */ |
| | 233 | int seqno_; |
| | 234 | |
| | 235 | /* path-searching source filename */ |
| | 236 | CTcMakeStr search_src_; |
| | 237 | |
| | 238 | /* the original name, before local file path resolution */ |
| | 239 | CTcMakeStr orig_name_; |
| | 240 | |
| | 241 | /* symbol filename */ |
| | 242 | CTcMakeStr sym_; |
| | 243 | |
| | 244 | /* object filename */ |
| | 245 | CTcMakeStr obj_; |
| | 246 | |
| | 247 | /* flag: requires recompilation of symbol/object file */ |
| | 248 | int needs_sym_recompile_; |
| | 249 | int needs_obj_recompile_; |
| | 250 | |
| | 251 | /* |
| | 252 | * flag: module is excluded from compilation (this is set when a |
| | 253 | * module is included by a library and then explicitly excluded from |
| | 254 | * the build) |
| | 255 | */ |
| | 256 | int exclude_; |
| | 257 | |
| | 258 | /* |
| | 259 | * Library member URL - this is the URL-style string naming the module |
| | 260 | * if it is a member of a library. This is not used except for |
| | 261 | * library members. This value is formed by adding the library prefix |
| | 262 | * for each enclosing sublibrary (not including the top-level library, |
| | 263 | * included from the command line or equivalent) to the "source:" |
| | 264 | * variable value that included this module from its library. A |
| | 265 | * library prefix is formed by adding the library prefix for each |
| | 266 | * enclosing sublibrary to the "library:" variable name that included |
| | 267 | * the library, plus a terminating "/". |
| | 268 | */ |
| | 269 | CTcMakeStr url_; |
| | 270 | |
| | 271 | /* the name of the enclosing library */ |
| | 272 | CTcMakeStr lib_name_; |
| | 273 | |
| | 274 | /* |
| | 275 | * library URL - this is the URL to our enclosing library, not |
| | 276 | * including the module name itself |
| | 277 | */ |
| | 278 | CTcMakeStr lib_url_; |
| | 279 | |
| | 280 | /* the source of the module */ |
| | 281 | enum tcmod_source_t source_type_; |
| | 282 | }; |
| | 283 | |
| | 284 | /* ------------------------------------------------------------------------ */ |
| | 285 | /* |
| | 286 | * Search path list entry - each entry in this list is a directory that |
| | 287 | * we'll search for a certain type of file (#include files, source files) |
| | 288 | */ |
| | 289 | class CTcMakePath |
| | 290 | { |
| | 291 | public: |
| | 292 | CTcMakePath(const textchar_t *path) |
| | 293 | { |
| | 294 | /* remember the path */ |
| | 295 | path_.set(path); |
| | 296 | |
| | 297 | /* we're not in a list yet */ |
| | 298 | nxt_ = 0; |
| | 299 | } |
| | 300 | |
| | 301 | /* get/set the path */ |
| | 302 | const textchar_t *get_path() const { return path_.get(); } |
| | 303 | void set_path(const textchar_t *path) { path_.set(path); } |
| | 304 | |
| | 305 | /* get/set the next list entry */ |
| | 306 | CTcMakePath *get_next() const { return nxt_; } |
| | 307 | void set_next(CTcMakePath *nxt) { nxt_ = nxt; } |
| | 308 | |
| | 309 | protected: |
| | 310 | /* our path string */ |
| | 311 | CTcMakeStr path_; |
| | 312 | |
| | 313 | /* next include path in the list */ |
| | 314 | CTcMakePath *nxt_; |
| | 315 | }; |
| | 316 | |
| | 317 | |
| | 318 | /* ------------------------------------------------------------------------ */ |
| | 319 | /* |
| | 320 | * Preprocessor symbol definition or undefinition item |
| | 321 | */ |
| | 322 | class CTcMakeDef |
| | 323 | { |
| | 324 | public: |
| | 325 | CTcMakeDef(const textchar_t *sym, const textchar_t *expan, int is_def) |
| | 326 | { |
| | 327 | /* remember the symbol and its expansion */ |
| | 328 | sym_.set(sym); |
| | 329 | expan_.set(expan); |
| | 330 | |
| | 331 | /* remember whether it's a definition or un-definition */ |
| | 332 | is_def_ = (is_def != 0); |
| | 333 | |
| | 334 | /* not in a list yet */ |
| | 335 | nxt_ = 0; |
| | 336 | } |
| | 337 | |
| | 338 | /* get my symbol */ |
| | 339 | const textchar_t *get_sym() const { return sym_.get(); } |
| | 340 | |
| | 341 | /* get my expansion text */ |
| | 342 | const textchar_t *get_expan() const { return expan_.get(); } |
| | 343 | |
| | 344 | /* get my define/undefine flag */ |
| | 345 | int is_def() const { return is_def_ != 0; } |
| | 346 | |
| | 347 | /* get/set the next list entry */ |
| | 348 | CTcMakeDef *get_next() const { return nxt_; } |
| | 349 | void set_next(CTcMakeDef *nxt) { nxt_ = nxt; } |
| | 350 | |
| | 351 | protected: |
| | 352 | /* next in the list */ |
| | 353 | CTcMakeDef *nxt_; |
| | 354 | |
| | 355 | /* the symbol to define or undefine */ |
| | 356 | CTcMakeStr sym_; |
| | 357 | |
| | 358 | /* the expansion text */ |
| | 359 | CTcMakeStr expan_; |
| | 360 | |
| | 361 | /* flag: true -> define the symbol, false -> undefine it */ |
| | 362 | unsigned int is_def_ : 1; |
| | 363 | }; |
| | 364 | |
| | 365 | |
| | 366 | /* ------------------------------------------------------------------------ */ |
| | 367 | /* |
| | 368 | * The program maintenance facility class. The program main entrypoint |
| | 369 | * constructs one of these objects, sets its parameters, then calls the |
| | 370 | * "build()" entrypoint to carry out the build instructions. |
| | 371 | * |
| | 372 | * The caller should not initialize or use compiler globals. This |
| | 373 | * object owns the compiler globals, and will create and destroy |
| | 374 | * compiler globals in the course of its processing. |
| | 375 | */ |
| | 376 | class CTcMake |
| | 377 | { |
| | 378 | public: |
| | 379 | CTcMake(); |
| | 380 | ~CTcMake(); |
| | 381 | |
| | 382 | /* |
| | 383 | * Set the default source file character set. Source and header |
| | 384 | * files that don't specify a character set (using a #charset |
| | 385 | * directive at the very start of the file) will be read using this |
| | 386 | * character set. If this isn't specified, we'll use the default |
| | 387 | * character set obtained from the OS. |
| | 388 | */ |
| | 389 | void set_source_charset(const textchar_t *charset) |
| | 390 | { |
| | 391 | /* delete any previous character set string */ |
| | 392 | lib_free_str(source_charset_); |
| | 393 | |
| | 394 | /* store the new character set name */ |
| | 395 | source_charset_ = lib_copy_str(charset); |
| | 396 | } |
| | 397 | |
| | 398 | /* |
| | 399 | * turn on/off source-level debugging - we'll generate the extra |
| | 400 | * information necessary for debugging the program |
| | 401 | */ |
| | 402 | void set_debug(int debug) { debug_ = debug; } |
| | 403 | |
| | 404 | /* set preprocess-only mode */ |
| | 405 | void set_pp_only(int pp_only) { pp_only_ = pp_only; } |
| | 406 | |
| | 407 | /* set list-include-files mode */ |
| | 408 | void set_list_includes(int f) { list_includes_mode_ = f; } |
| | 409 | |
| | 410 | /* set "clean" mode */ |
| | 411 | void set_clean_mode(int f) { clean_mode_ = f; } |
| | 412 | |
| | 413 | /* |
| | 414 | * set test reporting mode - in this mode, we suppress path names in |
| | 415 | * filenames in progress reports, so that the output is independent of |
| | 416 | * local path conventions |
| | 417 | */ |
| | 418 | void set_test_report_mode(int flag) { test_report_mode_ = flag; } |
| | 419 | |
| | 420 | /* set quoted filenames mode for error messages */ |
| | 421 | void set_err_quoted_fnames(int flag) { quoted_fname_mode_ = flag; } |
| | 422 | |
| | 423 | /* |
| | 424 | * turn on/off linking - by default, we'll compile and link, but the |
| | 425 | * linking phase can be turned off so we just compile sources to |
| | 426 | * object files |
| | 427 | */ |
| | 428 | void set_do_link(int do_link) { do_link_ = do_link; } |
| | 429 | |
| | 430 | /* |
| | 431 | * turn on preinit mode - by default, we'll run preinit if and only |
| | 432 | * if we're not in debug mode |
| | 433 | */ |
| | 434 | void set_preinit(int preinit) |
| | 435 | { |
| | 436 | preinit_ = preinit; |
| | 437 | explicit_preinit_ = TRUE; |
| | 438 | } |
| | 439 | |
| | 440 | /* turn sourceTextGroup property generation on or off */ |
| | 441 | void set_source_text_group_mode(int f) { src_group_mode_ = f; } |
| | 442 | |
| | 443 | /* turn verbose error messages on or off */ |
| | 444 | void set_verbose(int verbose) { verbose_ = verbose; } |
| | 445 | |
| | 446 | /* turn error number display on or off */ |
| | 447 | void set_show_err_numbers(int show) { show_err_numbers_ = show; } |
| | 448 | |
| | 449 | /* turn all warning messages on or off */ |
| | 450 | void set_warnings(int show) { show_warnings_ = show; } |
| | 451 | |
| | 452 | /* treat warnings as errors mode */ |
| | 453 | void set_warnings_as_errors(int f) { warnings_as_errors_ = f; } |
| | 454 | |
| | 455 | /* turn pedantic messages on or off */ |
| | 456 | void set_pedantic(int show) { pedantic_ = show; } |
| | 457 | |
| | 458 | /* |
| | 459 | * Set the list of warning messages to suppress. The caller is |
| | 460 | * responsible for maintaining this memory, keeping it valid as long as |
| | 461 | * we have a reference to it and deleting the memory when it's no |
| | 462 | * longer needed. We merely keep a reference to the caller's memory. |
| | 463 | */ |
| | 464 | void set_suppress_list(const int *lst, size_t cnt) |
| | 465 | { |
| | 466 | /* remember the caller's suppress list */ |
| | 467 | suppress_list_ = lst; |
| | 468 | suppress_cnt_ = cnt; |
| | 469 | } |
| | 470 | |
| | 471 | /* set the constant pool data XOR mask */ |
| | 472 | void set_data_xor_mask(uchar mask) { data_xor_mask_ = mask; } |
| | 473 | |
| | 474 | /* add a #include path entry */ |
| | 475 | void add_include_path(const textchar_t *path); |
| | 476 | |
| | 477 | /* add a #include path entry, if it's not already in our list */ |
| | 478 | void maybe_add_include_path(const textchar_t *path); |
| | 479 | |
| | 480 | /* add a source file path */ |
| | 481 | void add_source_path(const textchar_t *dir); |
| | 482 | |
| | 483 | /* |
| | 484 | * add a system include/source file path - system paths are always |
| | 485 | * searched after all of the regular paths, so effectively the items |
| | 486 | * in these lists come after all items in the add_include_path and |
| | 487 | * add_source_path lists, respectively |
| | 488 | */ |
| | 489 | class CTcMakePath *add_sys_include_path(const textchar_t *dir); |
| | 490 | class CTcMakePath *add_sys_source_path(const textchar_t *dir); |
| | 491 | |
| | 492 | /* |
| | 493 | * Set the symbol file directory. Any symbol file that doesn't have |
| | 494 | * an absolute path will default to this directory. |
| | 495 | */ |
| | 496 | void set_symbol_dir(const textchar_t *dir) { symdir_.set(dir); } |
| | 497 | |
| | 498 | /* |
| | 499 | * Set the object file directory. Any object file that doesn't have |
| | 500 | * an absolute path will default to this directory. |
| | 501 | */ |
| | 502 | void set_object_dir(const textchar_t *dir) { objdir_.set(dir); } |
| | 503 | |
| | 504 | /* set the assembly listing file */ |
| | 505 | void set_assembly_listing(osfildef *fp) { assembly_listing_fp_ = fp; } |
| | 506 | |
| | 507 | /* |
| | 508 | * Set the image file name |
| | 509 | */ |
| | 510 | void set_image_file(const textchar_t *fname) { image_fname_.set(fname); } |
| | 511 | |
| | 512 | /* get the image filename */ |
| | 513 | const char *get_image_file() const { return image_fname_.get(); } |
| | 514 | |
| | 515 | /* |
| | 516 | * Add a module (a module defines a source file and its directly |
| | 517 | * derived files: a symbol file and an object file). |
| | 518 | * |
| | 519 | * Once a module has been added to our list, we own the module. |
| | 520 | * We'll delete the module object when we're deleted. |
| | 521 | */ |
| | 522 | void add_module(CTcMakeModule *mod); |
| | 523 | void add_module_first(CTcMakeModule *mod); |
| | 524 | |
| | 525 | /* get the head and tail of the module list */ |
| | 526 | CTcMakeModule *get_first_module() const { return mod_head_; } |
| | 527 | CTcMakeModule *get_last_module() const { return mod_tail_; } |
| | 528 | |
| | 529 | /* |
| | 530 | * Add a module by filename. src_name must be specified, but |
| | 531 | * sym_name and obj_name can be null, in which case we'll use the |
| | 532 | * standard algorithm to derive these names from the source file |
| | 533 | * name. |
| | 534 | */ |
| | 535 | CTcMakeModule *add_module(const char *src_name, |
| | 536 | const char *sym_name, |
| | 537 | const char *obj_name) |
| | 538 | { return add_module(src_name, sym_name, obj_name, FALSE); } |
| | 539 | |
| | 540 | /* add a module at the head of the module list */ |
| | 541 | CTcMakeModule *add_module_first(const char *src_name, |
| | 542 | const char *sym_name, |
| | 543 | const char *obj_name) |
| | 544 | { return add_module(src_name, sym_name, obj_name, TRUE); } |
| | 545 | |
| | 546 | |
| | 547 | /* add a module at either the start or end of the module list */ |
| | 548 | CTcMakeModule *add_module(const char *src_name, const char *sym_name, |
| | 549 | const char *obj_name, int first); |
| | 550 | |
| | 551 | /* |
| | 552 | * Add a preprocessor symbol definition. If the expansion text is |
| | 553 | * null, we'll set the expansion text to "1" by default. |
| | 554 | */ |
| | 555 | void def_pp_sym(const textchar_t *sym, const textchar_t *expan); |
| | 556 | |
| | 557 | /* |
| | 558 | * Un-define a preprocessor symbol. |
| | 559 | */ |
| | 560 | void undef_pp_sym(const textchar_t *sym); |
| | 561 | |
| | 562 | /* look up a preprocessor symbol definition */ |
| | 563 | const char *look_up_pp_sym(const textchar_t *sym, size_t sym_len); |
| | 564 | |
| | 565 | /* |
| | 566 | * Build the program. This can be invoked once the options are set |
| | 567 | * and all of the modules have been added. This routine checks |
| | 568 | * dependencies and performs the build: |
| | 569 | * |
| | 570 | * - for each source file, generates a symbol file if the symbol file |
| | 571 | * is not up to date |
| | 572 | * |
| | 573 | * - after creating all symbol files: for each source file, compiles |
| | 574 | * the source to an object file if the object file isn't up to date |
| | 575 | * |
| | 576 | * - after creating all object files: links the object files to create |
| | 577 | * an image file, if the image file isn't up to date |
| | 578 | * |
| | 579 | * If any errors occur, we'll stop after the step in which the errors |
| | 580 | * occur. For example, if errors occur compiling an object file, |
| | 581 | * we'll stop after finishing with the object file and will not |
| | 582 | * proceed to any additional object file compilations. |
| | 583 | * |
| | 584 | * The 'host_interface' object must be provided by the caller. This |
| | 585 | * tells the compiler how to report error messages and otherwise |
| | 586 | * interact with the host environment. |
| | 587 | * |
| | 588 | * Fills in '*error_count' and '*warning_count' with the number of |
| | 589 | * errors and warnings, respectively, that occur during the |
| | 590 | * compilation. |
| | 591 | * |
| | 592 | * If 'force_build' is set, we'll build all derived files (symbols, |
| | 593 | * objects, and image), regardless of whether it appears necessary |
| | 594 | * based on file times. |
| | 595 | * |
| | 596 | * 'argv0' is the main program's argv[0], if available; a null pointer |
| | 597 | * can be passed in if argv[0] is not available (for example, if we're |
| | 598 | * not running in a command-line environment and the program's |
| | 599 | * executable filename is not available) |
| | 600 | */ |
| | 601 | void build(class CTcHostIfc *host_interface, |
| | 602 | int *error_count, int *warning_count, |
| | 603 | int force_build, int force_link, |
| | 604 | class CRcResList *res_list, |
| | 605 | const textchar_t *argv0); |
| | 606 | |
| | 607 | /* |
| | 608 | * Write our build configuration information to a symbol file. The |
| | 609 | * symbol file builder calls this to give us a chance to insert our |
| | 610 | * build configuration information into the symbol file. We include |
| | 611 | * all of the information we will need when re-loading the symbol file |
| | 612 | * to determine if the symbol file is up-to-date, so that we can |
| | 613 | * determine if we must rebuild the symbol file from the source or can |
| | 614 | * use it without rebuilding. |
| | 615 | */ |
| | 616 | void write_build_config_to_sym_file(class CVmFile *fp); |
| | 617 | |
| | 618 | /* |
| | 619 | * Compare our build configuration to the information saved in an |
| | 620 | * symbol file. Returns true if the configuration in the symbol file |
| | 621 | * matches our current configuration, false if not. A false return |
| | 622 | * indicates that recompilation is necessary, because something in the |
| | 623 | * configuration has changed. |
| | 624 | */ |
| | 625 | int compare_build_config_from_sym_file(const char *sym_fname, |
| | 626 | class CVmFile *fp); |
| | 627 | |
| | 628 | /* |
| | 629 | * Set the string capture file. If this is set, we'll write each |
| | 630 | * string token in the compiled text to this file, one string per |
| | 631 | * line. |
| | 632 | */ |
| | 633 | void set_string_capture(osfildef *fp) { string_fp_ = fp; } |
| | 634 | |
| | 635 | /* |
| | 636 | * Derive the source/symbol/object filenames for a module. Fills in |
| | 637 | * the buffer with the derived name. If the filenames don't have |
| | 638 | * paths explicitly specified, we'll use our default path settings to |
| | 639 | * build the full filename. |
| | 640 | * |
| | 641 | * The buffers are assumed to be OSFNMAX characters long, which should |
| | 642 | * be large enough for any valid filename. |
| | 643 | */ |
| | 644 | void get_srcfile(textchar_t *dst, CTcMakeModule *mod); |
| | 645 | void get_symfile(textchar_t *dst, CTcMakeModule *mod); |
| | 646 | void get_objfile(textchar_t *dst, CTcMakeModule *mod); |
| | 647 | |
| | 648 | private: |
| | 649 | /* scan all modules for name collisions with other modules */ |
| | 650 | void check_all_module_collisions(class CTcHostIfc *hostifc, |
| | 651 | class CResLoader *res_loader, |
| | 652 | int *err_cnt, int *warn_cnt); |
| | 653 | |
| | 654 | /* check the given module for name collisions with other modules */ |
| | 655 | void check_module_collision(CTcMakeModule *mod); |
| | 656 | |
| | 657 | /* |
| | 658 | * read and compare a configuration string; returns true if the |
| | 659 | * string matches what's stored in the file, false if not |
| | 660 | */ |
| | 661 | int read_and_compare_config_str(CVmFile *fp, const textchar_t *str); |
| | 662 | |
| | 663 | /* preprocess a source file */ |
| | 664 | void preprocess_source(class CTcHostIfc *hostifc, |
| | 665 | class CResLoader *res_loader, |
| | 666 | const textchar_t *src_fname, |
| | 667 | CTcMakeModule *src_mod, |
| | 668 | int *error_count, int *warning_count); |
| | 669 | |
| | 670 | /* build a symbol file */ |
| | 671 | void build_symbol_file(class CTcHostIfc *hostifc, |
| | 672 | class CResLoader *res_loader, |
| | 673 | const textchar_t *src_fname, |
| | 674 | const textchar_t *sym_fname, |
| | 675 | CTcMakeModule *src_mod, |
| | 676 | int *error_count, int *warning_count); |
| | 677 | |
| | 678 | /* build an object file */ |
| | 679 | void build_object_file(class CTcHostIfc *hostifc, |
| | 680 | class CResLoader *res_loader, |
| | 681 | const textchar_t *src_fname, |
| | 682 | const textchar_t *obj_fname, |
| | 683 | CTcMakeModule *src_mod, |
| | 684 | int *error_count, int *warning_count); |
| | 685 | |
| | 686 | /* build the image file */ |
| | 687 | void build_image_file(class CTcHostIfc *hostifc, |
| | 688 | class CResLoader *res_loader, |
| | 689 | const textchar_t *image_fname, |
| | 690 | int *error_count, int *warning_count, |
| | 691 | class CVmRuntimeSymbols *runtime_symtab, |
| | 692 | const char tool_data[4]); |
| | 693 | |
| | 694 | /* symbol enumeration callback: build runtime symbol table */ |
| | 695 | static void build_runtime_symtab_cb(void *ctx, class CTcSymbol *sym); |
| | 696 | |
| | 697 | /* set compiler options in the G_tcmain object */ |
| | 698 | void set_compiler_options(); |
| | 699 | |
| | 700 | /* add a preprocessor symbol definition or undefinition */ |
| | 701 | void add_pp_def(const textchar_t *sym, const textchar_t *expan, |
| | 702 | int is_def); |
| | 703 | |
| | 704 | /* |
| | 705 | * Get the string to report for a filename in a progress report. If |
| | 706 | * we're in test reporting mode, we'll return the root name so that we |
| | 707 | * suppress all paths in progress reports; otherwise, we'll just return |
| | 708 | * the name as given. If we're quoting filenames in messages, we'll |
| | 709 | * quote the filename. |
| | 710 | */ |
| | 711 | const char *get_step_fname(char *buf, const char *fname); |
| | 712 | |
| | 713 | /* default source file character set */ |
| | 714 | char *source_charset_; |
| | 715 | |
| | 716 | /* symbol file directory */ |
| | 717 | CTcMakeStr symdir_; |
| | 718 | |
| | 719 | /* object file diretory */ |
| | 720 | CTcMakeStr objdir_; |
| | 721 | |
| | 722 | /* assembly listing file */ |
| | 723 | osfildef *assembly_listing_fp_; |
| | 724 | |
| | 725 | /* image file name */ |
| | 726 | CTcMakeStr image_fname_; |
| | 727 | |
| | 728 | /* head and tail of module list */ |
| | 729 | CTcMakeModule *mod_head_; |
| | 730 | CTcMakeModule *mod_tail_; |
| | 731 | |
| | 732 | /* head and tail of source path list */ |
| | 733 | CTcMakePath *src_head_; |
| | 734 | CTcMakePath *src_tail_; |
| | 735 | |
| | 736 | /* |
| | 737 | * tail of regular source path list - this is where we insert regular |
| | 738 | * source path entries, which come before all system path entries |
| | 739 | */ |
| | 740 | CTcMakePath *nonsys_src_tail_; |
| | 741 | |
| | 742 | /* head and tail of #include path list */ |
| | 743 | CTcMakePath *inc_head_; |
| | 744 | CTcMakePath *inc_tail_; |
| | 745 | |
| | 746 | /* tail of regular (non-system) include path list */ |
| | 747 | CTcMakePath *nonsys_inc_tail_; |
| | 748 | |
| | 749 | /* head and tail of preprocessor symbol list */ |
| | 750 | CTcMakeDef *def_head_; |
| | 751 | CTcMakeDef *def_tail_; |
| | 752 | |
| | 753 | /* string capture file */ |
| | 754 | osfildef *string_fp_; |
| | 755 | |
| | 756 | /* true -> generate sourceTextGroup properties */ |
| | 757 | int src_group_mode_; |
| | 758 | |
| | 759 | /* true -> show verbose error messages */ |
| | 760 | int verbose_; |
| | 761 | |
| | 762 | /* true -> show error numbers with error messages */ |
| | 763 | int show_err_numbers_; |
| | 764 | |
| | 765 | /* true -> show warnings, false -> suppress all warnings */ |
| | 766 | int show_warnings_; |
| | 767 | |
| | 768 | /* true -> treat warnings as errors */ |
| | 769 | int warnings_as_errors_; |
| | 770 | |
| | 771 | /* true -> show "pedantic" warning messages */ |
| | 772 | int pedantic_; |
| | 773 | |
| | 774 | /* list of warning numbers to suppress */ |
| | 775 | const int *suppress_list_; |
| | 776 | size_t suppress_cnt_; |
| | 777 | |
| | 778 | /* true -> debug mode */ |
| | 779 | int debug_; |
| | 780 | |
| | 781 | /* true -> preprocess only */ |
| | 782 | int pp_only_; |
| | 783 | |
| | 784 | /* true -> #include list mode */ |
| | 785 | int list_includes_mode_; |
| | 786 | |
| | 787 | /* true -> "clean" mode */ |
| | 788 | int clean_mode_; |
| | 789 | |
| | 790 | /* true -> do linking after compiling */ |
| | 791 | int do_link_; |
| | 792 | |
| | 793 | /* true -> preinit mode */ |
| | 794 | int preinit_; |
| | 795 | |
| | 796 | /* |
| | 797 | * true -> obey 'preinit_' setting; otherwise, use default based on |
| | 798 | * 'debug_' setting |
| | 799 | */ |
| | 800 | int explicit_preinit_; |
| | 801 | |
| | 802 | /* |
| | 803 | * data pool XOR mask - we'll mask each byte of each constant data |
| | 804 | * pool with this byte when writing the image file, to obscure any |
| | 805 | * text strings in the constant data |
| | 806 | */ |
| | 807 | uchar data_xor_mask_; |
| | 808 | |
| | 809 | /* |
| | 810 | * true -> test reporting mode: suppress all paths from filenames |
| | 811 | * displayed in progress reports, in order to make the output |
| | 812 | * independent of local path name conventions |
| | 813 | */ |
| | 814 | int test_report_mode_; |
| | 815 | |
| | 816 | /* true -> use quoted filenames in error messages */ |
| | 817 | int quoted_fname_mode_; |
| | 818 | }; |
| | 819 | |
| | 820 | #endif /* TCMAKE_H */ |
| | 821 | |