/* * Copyright (c) 1990-2004 by Wayne C. Gramlich. * All rights reserved. */ #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef STR_EXPORTS_H #include "str_exports.h" #endif #ifndef STRVEC_EXPORTS_H #include "strvec_exports.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef UNIX_STDIO_H #include "unix_stdio.h" #endif #ifndef UNIX_STDLIB_H #include "unix_stdlib.h" #endif #ifndef UNIX_SYS_STAT_H #include "unix_sys_stat.h" #endif #ifndef VECTOR_DEFS_H #include "vector_defs.h" #endif /* Lint is a lot happier if we don't #include "run_time_exports.h"! */ extern char *run__time__enums; extern char *run__time__type_defs; extern char *run__time__struct_defs; typedef struct Flags_struct *Flags; struct Flags_struct { int c_plus_plus; int cross_compile; Str compiler_name; int debug_c; Vec(Str) interface_files; Vec(Str) libraries; Vec(Str) object_files; Str out_dir; Str out_file_name; int profile; Str sub_dir; Vec(Str) use_files; int verbose; }; LOCAL Flags flags_parse(int, Str *, Heap); LOCAL Str init_file_create(Flags, Heap); extern char *realpath(const char *, char *); extern char *getcwd(char *, unsigned); /* * main(argc, argv) * This routine will link the "argc" options in "argv". */ int main( int argc, Str *argv) { char chr; Str cmd; Strvec command; Str compiler; Flags flags; Heap heap; unsigned index; Str init_file_name; Str libmath_name; Str library; Str library_path; Str libstipple_name; Str libutil_name; Str object_file; Vec(Str) object_files; Str path; Str path_list; unsigned path_size; Str program_name; unsigned size; Str strt0_name; Stat_rec status; char full_path_name[1024]; /* Should be MAXPATHLEN */ program_name = argv[0]; argc--; argv++; if (argc == 0) { (void)printf("Usage: stl -[options] object_files ...\n"); return 0; } heap = heap_standard_create(); flags = flags_parse(argc, argv, heap); (void)fflush(stdout); /* Figure out where stl came from: */ path_list = getenv("PATH"); assert(path_list != (Str)0); size = strlen(path_list); if (program_name[0] != '/') { path = (Str)heap_alloc(heap, size + strlen(program_name) + 1); path[0] = '\0'; path_size = 0; for (index = 0; index < size; index++) { chr = path_list[index]; if ((chr != ':') || (index + 1 == size)) { path[path_size] = chr; path_size += 1; path[path_size] = '\0'; } if ((chr == ':') || (index + 1 == size)) { strcat(path, "/"); strcat(path, program_name); if (stat(path, &status) == 0) { break; } path[0] = '\0'; path_size = 0; } } } else { path = strdup(program_name); } full_path_name[0] = '\0'; path = realpath(path, full_path_name); if (path == (Str)0) { (void)fprintf(stderr, "Could not convert `%s' into a real path\n", path); assert(0); } size = strlen(full_path_name); for (index = size - 1; index != 0; index--) { chr = full_path_name[index]; if (chr == '/') { full_path_name[index] = '\0'; break; } } /* (void)printf("Exec directory: %s\n", full_path_name); */ library_path = (Str)strdup(path); if (flags->cross_compile) { Str last_slash = rindex(library_path, '/'); assert (last_slash != (Str)0); (void)strcpy(last_slash, "/win-x86"); } strt0_name = strprintf(heap,"%s/strt0.o", library_path); libstipple_name = strprintf(heap, "%s/libstipple.a", library_path); libutil_name = strprintf(heap, "%s/libutil.a", library_path); libmath_name = "-lm"; /* Create and compile the initialization file: */ init_file_name = init_file_create(flags, heap); command = strvec_create(heap); compiler = ""; if (flags->cross_compile) { compiler = flags->compiler_name; } else { if (flags->c_plus_plus) { compiler = "g++"; } else { compiler = "gcc"; } } strvec_print(command, compiler); #ifdef SOLARIS strvec_print(command, " -Bstatic"); #endif /* SOLARIS */ if (flags->debug_c) { strvec_print(command, " -g"); } if (flags->out_file_name != (Str)0) { strvec_print(command, " -o %s", flags->out_file_name); } if (flags->profile) { strvec_print(command, " -xpg"); } strvec_print(command, " %s", strt0_name); strvec_print(command, " %s", init_file_name); object_files = flags->object_files; VEC_LOOP(Str, object_files, object_file) { strvec_print(command, " %s", object_file); } strvec_print(command, " %s", libstipple_name); strvec_print(command, " %s", libutil_name); strvec_print(command, " %s", libmath_name); #ifdef SOLARIS strvec_print(command, " -Bdynamic"); #endif /* SOLARIS */ #ifdef LINUX if (!flags->cross_compile) { strvec_print(command, " -export-dynamic"); } #endif /* LINUX */ VEC_LOOP(Str, flags->libraries, library) { strvec_print(command, " %s", library); } #ifdef SOLARIS strvec_print(command, " -ldl -Bstatic"); #endif /* SOLARIS */ #ifdef LINUX if (!flags->cross_compile) { strvec_print(command, " -ldl"); strvec_print(command, " -lc"); } #endif /* LINUX */ cmd = strvec_str_get(command, heap); if (flags->verbose) { (void)printf("link command: "); (void)printf("%s\n", cmd); } (void)fflush(stdout); if (system(cmd) != 0) { error_fatal("Program did not link"); } return 0; } /* * flags_parse(argc, argv, heap) * This routine will parse the "argc" options in "argv" into a flags * object allocated from "heap" and return it. */ LOCAL Flags flags_parse( int argc, Str *argv, Heap heap) { Str arg; int index; Flags flags; int length; /* Allocate and initialize the flags object: */ flags = heap_allocate(heap, Flags); flags->c_plus_plus = 0; flags->compiler_name = "cc"; flags->cross_compile = 0; flags->debug_c = 1; flags->interface_files = vec_create(Str, heap); flags->libraries = vec_create(Str, heap); flags->object_files = vec_create(Str, heap); flags->out_dir = (Str)0; flags->out_file_name = (Str)0; flags->profile = 0; flags->use_files = vec_create(Str, heap); flags->verbose = 0; for (index = 0; index < argc; index++) { arg = argv[index]; /* (void)printf("arg[%d]:'%s'\n", index, arg); */ length = strlen(arg); if (arg[0] == '-') { switch (arg[1]) { case 'C': flags->c_plus_plus = 1; break; case 'd': vec_append(Str, flags->libraries, "-shared"); break; case 'E': index++; if (index == argc) { error_fatal("No directory after -O"); } if (flags->out_dir != (Str)0) { error_fatal("Too many -E options"); } flags->out_dir = argv[index]; break; case 'l': case 'L': vec_append(Str, flags->libraries, arg); break; case 'o': index++; if (index == argc) { error_fatal("No directory after -o"); } if (flags->out_file_name != (Str)0) { error_fatal("Too many -o options"); } flags->out_file_name = argv[index]; break; case 'G': flags->debug_c = 1; break; case 's': vec_append(Str, flags->libraries, "-static"); break; case 'W': flags->cross_compile = 1; break; case 'w': index++; if (index == argc) { error_fatal("No file name after -w"); } flags->compiler_name = argv[index]; break; case 'v': flags->verbose = 1; break; case 'z': flags->profile = 1; break; default: error_fatal("Unknown option '%s'", arg); } } else if ((length >= 2) && (strncmp(arg + length - 2, ".o", 2) == 0)) { vec_append(Str, flags->object_files, arg); } else if ((length >= 4) && (strncmp(arg + length - 4, ".sti", 4) == 0)) { vec_append(Str, flags->interface_files, arg); } else if ((length >= 4) && (strncmp(arg + length - 4, ".stu", 4) == 0)) { vec_append(Str, flags->use_files, arg); } else { error_fatal("File with unrecongnized suffix '%s'\n", arg); } } return flags; } /* * init_file_create(flags, heap) * Will create an initialization file based on "flags". The * name of the resulting file is returned as a string allocated * from "heap". */ LOCAL Str init_file_create( Flags flags, Heap heap) { Str c_extern; Str base_name; Str out_dir; Stdio out_file; Strvec out_file_name; Str out_name; Str interface_file; Vec(Str) interface_files; Str module_name; Vec(Str) module_names; Str pointer; int size; /* Extract all of the module names: */ module_names = vec_create(Str, heap); interface_files = flags->interface_files; VEC_LOOP(Str, interface_files, interface_file) { pointer = strrchr(interface_file, '/'); if (pointer == (Str)0) { pointer = interface_file; } else { pointer++; } module_name = strdupl(pointer, heap); pointer = strrchr(module_name, '.'); assert(pointer != (Str)0); pointer[0] = '\0'; vec_append(Str, module_names, module_name); } out_dir = (flags->out_dir == (Str)0) ? "/tmp" : flags->out_dir; if (out_dir[0] != '/') { char cwd[2000]; assert(getcwd(cwd, sizeof(cwd)) != (Str)0); out_dir = strprintf(heap, "%s/%s", cwd, out_dir); /* Total kludge! */ if (strncmp(out_dir, "/tmp_mnt", 8) == 0) { out_dir += 8; } } out_file_name = strvec_create(heap); base_name = strrchr(flags->out_file_name, '/'); if (base_name == (char *)0) { base_name = flags->out_file_name; } else { base_name += 1; } if (flags->c_plus_plus) { strvec_print(out_file_name, "%s/%s__init.cpp", out_dir, base_name); } else { strvec_print(out_file_name, "%s/%s__init.c", out_dir, base_name); } out_name = strvec_str_get(out_file_name, heap); out_file = fopen(out_name, "w"); if (out_file == (Stdio)0) { error_fatal("Could not open %s for writing", out_name); } (void)fprintf(out_file, "%s", run__time__enums); (void)fprintf(out_file, "%s", run__time__type_defs); (void)fprintf(out_file, "typedef void *routine__info__type;\n"); (void)fprintf(out_file, "%s", run__time__struct_defs); c_extern = ""; (void)fflush(stdout); if (flags->c_plus_plus) { c_extern = " \"C\""; (void)fflush(stdout); } VEC_LOOP(Str, module_names, module_name) { (void)fprintf(out_file, "extern%s module___object %s__module__object;\n", c_extern, module_name); (void)fprintf(out_file, "extern%s void %s__module__initialize(void);\n", c_extern, module_name); } (void)fprintf(out_file, "extern%s void program__modules__initialize(void);\n", c_extern); (void)fprintf(out_file, "\n"); size = vec_size(Str, module_names); (void)fprintf(out_file, "int module__objects__count = %d;\n", size); (void)fprintf(out_file, "module___object *module___objects[%d] = {\n", size); VEC_LOOP(Str, module_names, module_name) { (void)fprintf(out_file, "\t&%s__module__object,\n", module_name); } (void)fprintf(out_file, "};\n"); (void)fprintf(out_file, "\n"); (void)fprintf(out_file, "char *module__coverage__file = \"%s: %s/%s.counts\";\n", "STIPPLE_COVERAGE_FILE", out_dir, flags->out_file_name); (void)fprintf(out_file, "\n"); (void)fprintf(out_file, "void program__modules__initialize(void)\n"); (void)fprintf(out_file, "{\n"); VEC_LOOP(Str, module_names, module_name) { (void)fprintf(out_file, "\t%s__module__initialize();\n", module_name); } (void)fprintf(out_file, "}\n"); (void)fclose(out_file); return out_name; }