tomas@989: // Pulled out of dmd/mars.c tomas@989: tomas@989: // some things are taken from llvm's llc tool tomas@989: // which uses the llvm license tomas@989: tomas@989: #include "gen/llvm.h" kamm@1518: #include "gen/llvm-version.h" tomas@1149: #include "llvm/LinkAllVMCore.h" kamm@1052: #include "llvm/Linker.h" benny@1535: #include "llvm/LLVMContext.h" tomas@1149: #include "llvm/System/Signals.h" tomas@989: #include "llvm/Target/SubtargetFeature.h" tomas@989: #include "llvm/Target/TargetMachine.h" kamm@1199: #include "llvm/Target/TargetOptions.h" benny@1544: #include "llvm/Target/TargetRegistry.h" kamm@1518: #include "llvm/Target/TargetSelect.h" tomas@989: tomas@989: #include tomas@989: #include tomas@989: #include tomas@989: #include tomas@989: tomas@989: #if POSIX tomas@989: #include tomas@989: #elif _WIN32 tomas@989: #include tomas@989: #endif tomas@989: tomas@1103: #include "rmem.h" tomas@989: #include "root.h" tomas@989: tomas@989: #include "mars.h" tomas@989: #include "module.h" tomas@989: #include "mtype.h" tomas@989: #include "id.h" tomas@989: #include "cond.h" tomas@989: tomas@989: #include "gen/logger.h" tomas@989: #include "gen/linker.h" tomas@989: #include "gen/irstate.h" fvbommel@1482: #include "gen/optimizer.h" kamm@1052: #include "gen/toobj.h" fvbommel@1390: #include "gen/metadata.h" kamm@1324: #include "gen/passes/Passes.h" tomas@989: tomas@989: #include "gen/cl_options.h" tomas@989: #include "gen/cl_helpers.h" tomas@989: using namespace opts; tomas@989: tomas@1103: #include "gen/configfile.h" tomas@1103: tomas@989: extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); tomas@989: extern void backend_init(); tomas@989: extern void backend_term(); tomas@989: tomas@989: static cl::opt noDefaultLib("nodefaultlib", tomas@989: cl::desc("Don't add a default library for linking implicitly"), tomas@989: cl::ZeroOrMore); tomas@989: tomas@989: static ArrayAdapter impPathsStore("I", global.params.imppath); tomas@989: static cl::list importPaths("I", tomas@989: cl::desc("Where to look for imports"), tomas@989: cl::value_desc("path"), tomas@989: cl::location(impPathsStore), tomas@989: cl::Prefix); tomas@989: tomas@989: static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); tomas@989: static cl::list defaultlibs("defaultlib", tomas@989: cl::desc("Set default libraries for non-debug build"), tomas@989: cl::value_desc("lib,..."), tomas@989: cl::location(defaultLibStore), tomas@989: cl::CommaSeparated); tomas@989: tomas@989: static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); tomas@989: static cl::list debuglibs("debuglib", tomas@989: cl::desc("Set default libraries for debug build"), tomas@989: cl::value_desc("lib,..."), tomas@989: cl::location(debugLibStore), tomas@989: cl::CommaSeparated); tomas@989: tomas@989: void printVersion() { tomas@989: printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", tomas@989: global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); tomas@989: printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" tomas@989: "LDC Homepage: http://www.dsource.org/projects/ldc\n"); tomas@989: } tomas@989: tomas@989: // Helper function to handle -d-debug=* and -d-version=* tomas@989: static void processVersions(std::vector& list, char* type, tomas@989: void (*setLevel)(unsigned), void (*addIdent)(const char*)) { tomas@989: typedef std::vector::iterator It; tomas@989: tomas@989: for(It I = list.begin(), E = list.end(); I != E; ++I) { tomas@989: const char* value = I->c_str(); tomas@989: if (isdigit(value[0])) { tomas@989: errno = 0; tomas@989: char* end; tomas@989: long level = strtol(value, &end, 10); tomas@989: if (*end || errno || level > INT_MAX) { tomas@989: error("Invalid %s level: %s", type, I->c_str()); tomas@989: } else { tomas@989: setLevel((unsigned)level); tomas@989: } tomas@989: } else { tomas@989: char* cstr = mem.strdup(value); tomas@989: if (Lexer::isValidIdentifier(cstr)) { tomas@989: addIdent(cstr); tomas@989: continue; tomas@989: } else { tomas@989: error("Invalid %s identifier or level: '%s'", type, I->c_str()); tomas@989: } tomas@989: } tomas@989: } tomas@989: } tomas@989: tomas@989: // Helper function to handle -of, -od, etc. tomas@989: static void initFromString(char*& dest, const cl::opt& src) { tomas@989: dest = 0; tomas@989: if (src.getNumOccurrences() != 0) { tomas@989: if (src.empty()) tomas@989: error("Expected argument to '-%s'", src.ArgStr); tomas@989: dest = mem.strdup(src.c_str()); tomas@989: } tomas@989: } tomas@989: tomas@989: int main(int argc, char** argv) tomas@989: { tomas@1149: // stack trace on signals tomas@1149: llvm::sys::PrintStackTraceOnErrorSignal(); tomas@1149: tomas@989: Array files; tomas@989: char *p, *ext; tomas@989: Module *m; tomas@989: int status = EXIT_SUCCESS; tomas@989: tomas@989: // Set some default values tomas@989: #if _WIN32 tomas@989: char buf[MAX_PATH]; tomas@989: GetModuleFileName(NULL, buf, MAX_PATH); tomas@989: global.params.argv0 = buf; tomas@989: #else tomas@989: global.params.argv0 = argv[0]; tomas@989: #endif tomas@989: global.params.useSwitchError = 1; tomas@989: tomas@989: global.params.linkswitches = new Array(); tomas@989: global.params.libfiles = new Array(); tomas@989: global.params.objfiles = new Array(); tomas@989: global.params.ddocfiles = new Array(); kamm@1402: kamm@1402: global.params.moduleDeps = NULL; kamm@1402: global.params.moduleDepsFile = NULL; tomas@999: tomas@989: // Set predefined version identifiers tomas@989: VersionCondition::addPredefinedGlobalIdent("LLVM"); tomas@989: VersionCondition::addPredefinedGlobalIdent("LDC"); tomas@989: VersionCondition::addPredefinedGlobalIdent("all"); tomas@999: #if DMDV2 tomas@999: VersionCondition::addPredefinedGlobalIdent("D_Version2"); tomas@999: #endif tomas@999: tomas@1103: // merge DFLAGS environment variable into argc/argv tomas@989: getenv_setargv("DFLAGS", &argc, &argv); tomas@989: #if 0 tomas@989: for (int i = 0; i < argc; i++) tomas@989: { tomas@989: printf("argv[%d] = '%s'\n", i, argv[i]); tomas@989: } tomas@989: #endif tomas@989: tomas@1103: // build complete fixed up list of command line arguments tomas@1103: std::vector final_args; tomas@1103: final_args.reserve(argc); tomas@1103: kamm@1197: // insert command line args until -run is reached kamm@1197: int run_argnum = 1; kamm@1197: while (run_argnum < argc && strncmp(argv[run_argnum], "-run", 4) != 0) kamm@1197: ++run_argnum; kamm@1197: final_args.insert(final_args.end(), &argv[0], &argv[run_argnum]); tomas@1103: tomas@1103: // read the configuration file tomas@1103: ConfigFile cfg_file; tomas@1103: tomas@1103: // just ignore errors for now, they are still printed tomas@1103: #if DMDV2 tomas@1103: #define CFG_FILENAME "ldc2.conf" tomas@1103: #else tomas@1103: #define CFG_FILENAME "ldc.conf" tomas@1103: #endif tomas@1103: cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME); tomas@1103: #undef CFG_FILENAME tomas@1103: tomas@1103: // insert config file additions to the argument list tomas@1103: final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end()); tomas@1103: kamm@1197: // insert -run and everything beyond kamm@1197: final_args.insert(final_args.end(), &argv[run_argnum], &argv[argc]); kamm@1197: tomas@1103: #if 0 tomas@1103: for (size_t i = 0; i < final_args.size(); ++i) tomas@1103: { tomas@1103: printf("final_args[%zu] = %s\n", i, final_args[i]); tomas@1103: } tomas@1103: #endif tomas@1103: tomas@989: // Handle fixed-up arguments! tomas@989: cl::SetVersionPrinter(&printVersion); tomas@1103: cl::ParseCommandLineOptions(final_args.size(), (char**)&final_args[0], "LLVM-based D Compiler\n", true); tomas@989: fvbommel@1484: // Print config file path if -v was passed fvbommel@1484: if (global.params.verbose) { fvbommel@1484: const std::string& path = cfg_file.path(); fvbommel@1484: if (!path.empty()) fvbommel@1484: printf("config %s\n", path.c_str()); fvbommel@1484: } fvbommel@1484: tomas@989: // Negated options tomas@989: global.params.link = !compileOnly; tomas@989: global.params.obj = !dontWriteObj; tomas@989: global.params.useInlineAsm = !noAsm; tomas@989: tomas@989: // String options: std::string --> char* tomas@989: initFromString(global.params.objname, objectFile); tomas@989: initFromString(global.params.objdir, objectDir); tomas@989: tomas@989: initFromString(global.params.docdir, ddocDir); tomas@989: initFromString(global.params.docname, ddocFile); tomas@989: global.params.doDocComments |= tomas@989: global.params.docdir || global.params.docname; tomas@989: tomas@989: #ifdef _DH tomas@989: initFromString(global.params.hdrdir, hdrDir); tomas@989: initFromString(global.params.hdrname, hdrFile); tomas@989: global.params.doHdrGeneration |= tomas@989: global.params.hdrdir || global.params.hdrname; tomas@989: #endif tomas@989: kamm@1402: initFromString(global.params.moduleDepsFile, moduleDepsFile); kamm@1402: if (global.params.moduleDepsFile != NULL) kamm@1402: { kamm@1402: global.params.moduleDeps = new OutBuffer; kamm@1402: } kamm@1402: tomas@989: processVersions(debugArgs, "debug", tomas@989: DebugCondition::setGlobalLevel, tomas@989: DebugCondition::addGlobalIdent); tomas@989: processVersions(versions, "version", tomas@989: VersionCondition::setGlobalLevel, tomas@989: VersionCondition::addGlobalIdent); tomas@989: tomas@989: global.params.output_o = fvbommel@1415: (opts::output_o == cl::BOU_UNSET fvbommel@1415: && !(opts::output_bc || opts::output_ll || opts::output_s)) tomas@989: ? OUTPUTFLAGdefault tomas@989: : opts::output_o == cl::BOU_TRUE tomas@989: ? OUTPUTFLAGset tomas@989: : OUTPUTFLAGno; tomas@989: global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; tomas@989: global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; tomas@989: global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; tomas@989: tomas@989: if (global.params.run || !runargs.empty()) { tomas@989: // FIXME: how to properly detect the presence of a PositionalEatsArgs tomas@989: // option without parameters? We want to emit an error in that case... tomas@989: // You'd think getNumOccurrences would do it, but it just returns the tomas@989: // number of parameters) tomas@989: // NOTE: Hacked around it by detecting -run in getenv_setargv(), where tomas@989: // we're looking for it anyway, and pre-setting the flag... tomas@989: global.params.run = true; tomas@989: if (!runargs.empty()) { tomas@989: files.push(mem.strdup(runargs[0].c_str())); tomas@989: } else { tomas@989: global.params.run = false; tomas@989: error("Expected at least one argument to '-run'\n"); tomas@989: } tomas@989: } tomas@989: tomas@989: tomas@989: files.reserve(fileList.size()); tomas@989: typedef std::vector::iterator It; tomas@989: for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) tomas@989: if (!I->empty()) tomas@989: files.push(mem.strdup(I->c_str())); tomas@989: tomas@989: if (global.errors) tomas@989: { kamm@1007: fatal(); tomas@989: } tomas@989: if (files.dim == 0) tomas@989: { tomas@989: cl::PrintHelpMessage(); kamm@1007: return EXIT_FAILURE; tomas@989: } tomas@989: tomas@989: Array* libs; tomas@989: if (global.params.symdebug) kamm@1199: { kamm@1007: libs = global.params.debuglibnames; kamm@1199: llvm::NoFramePointerElim = true; kamm@1199: } tomas@989: else kamm@1007: libs = global.params.defaultlibnames; tomas@989: matti@1635: if (!noDefaultLib) tomas@989: { matti@1635: if (libs) kamm@1007: { matti@1635: for (int i = 0; i < libs->dim; i++) matti@1635: { matti@1635: char* lib = (char *)libs->data[i]; matti@1635: char *arg = (char *)mem.malloc(strlen(lib) + 3); matti@1635: strcpy(arg, "-l"); matti@1635: strcpy(arg+2, lib); matti@1635: global.params.linkswitches->push(arg); matti@1635: } kamm@1007: } matti@1635: else matti@1635: { robert@1527: #if DMDV2 matti@1635: global.params.linkswitches->push(mem.strdup("-ldruntime-ldc")); robert@1527: #else matti@1635: global.params.linkswitches->push(mem.strdup("-lldc-runtime")); matti@1635: global.params.linkswitches->push(mem.strdup("-ltango-cc-tango")); matti@1635: global.params.linkswitches->push(mem.strdup("-ltango-gc-basic")); matti@1635: // pass the runtime again to resolve issues matti@1635: // with linking order matti@1635: global.params.linkswitches->push(mem.strdup("-lldc-runtime")); robert@1523: #endif matti@1635: } tomas@989: } tomas@989: tomas@989: if (global.params.run) tomas@989: quiet = 1; tomas@989: tomas@989: if (global.params.useUnitTests) kamm@1007: global.params.useAssert = 1; tomas@989: tomas@989: // LDC output determination tomas@989: tomas@989: // if we don't link, autodetect target from extension tomas@989: if(!global.params.link && global.params.objname) { kamm@1007: ext = FileName::ext(global.params.objname); kamm@1007: bool autofound = false; kamm@1007: if (!ext) { kamm@1007: // keep things as they are kamm@1007: } else if (strcmp(ext, global.ll_ext) == 0) { kamm@1007: global.params.output_ll = OUTPUTFLAGset; kamm@1007: autofound = true; kamm@1007: } else if (strcmp(ext, global.bc_ext) == 0) { kamm@1007: global.params.output_bc = OUTPUTFLAGset; kamm@1007: autofound = true; kamm@1007: } else if (strcmp(ext, global.s_ext) == 0) { kamm@1007: global.params.output_s = OUTPUTFLAGset; kamm@1007: autofound = true; kamm@1007: } else if (strcmp(ext, global.obj_ext) == 0) { kamm@1007: global.params.output_o = OUTPUTFLAGset; kamm@1007: autofound = true; kamm@1007: } else { kamm@1007: // append dot, so forceExt won't change existing name even if it contains dots kamm@1007: size_t len = strlen(global.params.objname); kamm@1007: size_t extlen = strlen("."); kamm@1007: char* s = (char *)mem.malloc(len + 1 + extlen + 1); kamm@1007: memcpy(s, global.params.objname, len); kamm@1007: s[len] = '.'; kamm@1007: s[len+1+extlen] = 0; kamm@1007: global.params.objname = s; tomas@989: kamm@1007: } kamm@1007: if(autofound && global.params.output_o == OUTPUTFLAGdefault) kamm@1007: global.params.output_o = OUTPUTFLAGno; tomas@989: } tomas@989: tomas@989: // only link if possible tomas@989: if (!global.params.obj || !global.params.output_o) kamm@1007: global.params.link = 0; tomas@989: tomas@989: if (global.params.link) tomas@989: { kamm@1007: global.params.exefile = global.params.objname; kamm@1007: if (files.dim > 1) kamm@1007: global.params.objname = NULL; tomas@989: } tomas@989: else if (global.params.run) tomas@989: { kamm@1007: error("flags conflict with -run"); kamm@1007: fatal(); tomas@989: } tomas@989: else tomas@989: { kamm@1433: if (global.params.objname && files.dim > 1 && !singleObj) kamm@1007: { kamm@1007: error("multiple source files, but only one .obj name"); kamm@1007: fatal(); kamm@1007: } tomas@989: } tomas@989: tomas@989: // create a proper target tomas@1147: Ir ir; tomas@1021: tomas@1021: // check -m32/64 sanity tomas@1021: if (m32bits && m64bits) tomas@1021: error("cannot use both -m32 and -m64 options"); benny@1544: else if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty())) tomas@1021: error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches"); tomas@1021: if (global.errors) tomas@1021: fatal(); tomas@1021: tomas@1021: // override triple if needed tomas@1021: const char* defaultTriple = DEFAULT_TARGET_TRIPLE; tomas@1021: if ((sizeof(void*) == 4 && m64bits) || (sizeof(void*) == 8 && m32bits)) tomas@1021: { tomas@1021: defaultTriple = DEFAULT_ALT_TARGET_TRIPLE; tomas@1021: } tomas@1021: tomas@989: // did the user override the target triple? tomas@989: if (mTargetTriple.empty()) tomas@989: { benny@1544: if (!mArch.empty()) tomas@989: { tomas@989: error("you must specify a target triple as well with -mtriple when using the -march option"); tomas@989: fatal(); tomas@989: } tomas@1021: global.params.targetTriple = defaultTriple; tomas@989: } tomas@989: else tomas@989: { tomas@989: global.params.targetTriple = mTargetTriple.c_str(); tomas@989: } tomas@989: benny@1570: std::string triple = global.params.targetTriple; tomas@989: kamm@1518: // Allocate target machine. kamm@1518: kamm@1518: // first initialize llvm benny@1543: #define LLVM_TARGET(A) LLVMInitialize##A##TargetInfo(); LLVMInitialize##A##Target(); LLVMInitialize##A##AsmPrinter(); kamm@1518: // this is defined to be LLVM_TARGET(target name 1) LLVM_TARGET(target name 2) ... kamm@1518: LDC_TARGETS kamm@1518: #undef LLVM_TARGET kamm@1518: benny@1544: const llvm::Target *theTarget = NULL; kamm@1518: // Check whether the user has explicitly specified an architecture to compile for. benny@1544: if (mArch.empty()) tomas@989: { tomas@989: std::string Err; benny@1570: theTarget = llvm::TargetRegistry::lookupTarget(triple, Err); benny@1543: if (theTarget == 0) tomas@989: { tomas@997: error("failed to auto-select target: %s, please use the -march option", Err.c_str()); tomas@989: fatal(); tomas@989: } tomas@989: } benny@1543: else benny@1543: { benny@1544: for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(), benny@1544: ie = llvm::TargetRegistry::end(); it != ie; ++it) benny@1544: { benny@1544: if (mArch == it->getName()) benny@1544: { benny@1544: theTarget = &*it; benny@1544: break; benny@1544: } benny@1544: } benny@1544: benny@1544: if (!theTarget) benny@1544: { benny@1544: error("invalid target '%s'", mArch.c_str()); benny@1544: fatal(); benny@1544: } benny@1543: } tomas@989: tomas@989: // Package up features to be passed to target/subtarget tomas@989: std::string FeaturesStr; tomas@989: if (mCPU.size() || mAttrs.size()) tomas@989: { tomas@989: llvm::SubtargetFeatures Features; tomas@989: Features.setCPU(mCPU); tomas@989: for (unsigned i = 0; i != mAttrs.size(); ++i) tomas@989: Features.AddFeature(mAttrs[i]); tomas@989: FeaturesStr = Features.getString(); tomas@989: } tomas@989: benny@1570: std::auto_ptr target(theTarget->createTargetMachine(triple, FeaturesStr)); tomas@989: assert(target.get() && "Could not allocate target machine!"); tomas@989: gTargetMachine = target.get(); tomas@989: gTargetData = gTargetMachine->getTargetData(); tomas@989: tomas@989: // get final data layout tomas@989: std::string datalayout = gTargetData->getStringRepresentation(); tomas@989: global.params.dataLayout = datalayout.c_str(); tomas@989: benny@1543: global.params.llvmArch = theTarget->getName(); tomas@989: tomas@989: if (strcmp(global.params.llvmArch,"x86")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("X86"); tomas@989: global.params.isLE = true; tomas@989: global.params.is64bit = false; tomas@989: global.params.cpu = ARCHx86; tomas@989: if (global.params.useInlineAsm) { kamm@1033: VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); tomas@989: } tomas@989: } tomas@989: else if (strcmp(global.params.llvmArch,"x86-64")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("X86_64"); tomas@989: global.params.isLE = true; tomas@989: global.params.is64bit = true; tomas@989: global.params.cpu = ARCHx86_64; tomas@989: if (global.params.useInlineAsm) { kamm@1033: VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); tomas@989: } tomas@989: } tomas@989: else if (strcmp(global.params.llvmArch,"ppc32")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("PPC"); tomas@989: global.params.isLE = false; tomas@989: global.params.is64bit = false; tomas@989: global.params.cpu = ARCHppc; tomas@989: } tomas@989: else if (strcmp(global.params.llvmArch,"ppc64")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("PPC64"); tomas@989: global.params.isLE = false; tomas@989: global.params.is64bit = true; tomas@989: global.params.cpu = ARCHppc_64; tomas@989: } tomas@989: else if (strcmp(global.params.llvmArch,"arm")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("ARM"); tomas@989: global.params.isLE = true; tomas@989: global.params.is64bit = false; tomas@989: global.params.cpu = ARCHarm; tomas@989: } tomas@989: else if (strcmp(global.params.llvmArch,"thumb")==0) { tomas@989: VersionCondition::addPredefinedGlobalIdent("Thumb"); tomas@989: global.params.isLE = true; tomas@989: global.params.is64bit = false; tomas@989: global.params.cpu = ARCHthumb; tomas@989: } tomas@989: else { tomas@989: error("invalid cpu architecture specified: %s", global.params.llvmArch); tomas@989: fatal(); tomas@989: } tomas@989: tomas@989: // endianness tomas@989: if (global.params.isLE) { tomas@989: VersionCondition::addPredefinedGlobalIdent("LittleEndian"); tomas@989: } tomas@989: else { tomas@989: VersionCondition::addPredefinedGlobalIdent("BigEndian"); tomas@989: } tomas@989: tomas@989: // a generic 64bit version tomas@989: if (global.params.is64bit) { tomas@989: VersionCondition::addPredefinedGlobalIdent("LLVM64"); tomas@999: // FIXME: is this always correct? tomas@999: VersionCondition::addPredefinedGlobalIdent("D_LP64"); tomas@989: } tomas@989: tomas@989: // parse the OS out of the target triple tomas@989: // see http://gcc.gnu.org/install/specific.html for details tomas@989: // also llvm's different SubTargets have useful information tomas@989: size_t npos = std::string::npos; tomas@989: tomas@989: // windows tomas@989: // FIXME: win64 tomas@989: if (triple.find("windows") != npos || triple.find("win32") != npos || triple.find("mingw") != npos) tomas@989: { tomas@989: global.params.os = OSWindows; tomas@989: VersionCondition::addPredefinedGlobalIdent("Windows"); tomas@989: VersionCondition::addPredefinedGlobalIdent("Win32"); tomas@989: VersionCondition::addPredefinedGlobalIdent("mingw32"); tomas@989: } tomas@989: // FIXME: cygwin tomas@989: else if (triple.find("cygwin") != npos) tomas@989: { tomas@989: error("CygWin is not yet supported"); tomas@989: fatal(); tomas@989: } tomas@989: // linux tomas@989: else if (triple.find("linux") != npos) tomas@989: { tomas@989: global.params.os = OSLinux; tomas@989: VersionCondition::addPredefinedGlobalIdent("linux"); tomas@989: VersionCondition::addPredefinedGlobalIdent("Posix"); tomas@989: } tomas@989: // darwin tomas@989: else if (triple.find("-darwin") != npos) tomas@989: { tomas@989: global.params.os = OSMacOSX; tomas@989: VersionCondition::addPredefinedGlobalIdent("OSX"); tomas@989: VersionCondition::addPredefinedGlobalIdent("darwin"); tomas@989: VersionCondition::addPredefinedGlobalIdent("Posix"); tomas@989: } tomas@989: // freebsd tomas@989: else if (triple.find("-freebsd") != npos) tomas@989: { tomas@989: global.params.os = OSFreeBSD; tomas@989: VersionCondition::addPredefinedGlobalIdent("freebsd"); tomas@1387: VersionCondition::addPredefinedGlobalIdent("FreeBSD"); tomas@989: VersionCondition::addPredefinedGlobalIdent("Posix"); tomas@989: } tomas@989: // solaris tomas@989: else if (triple.find("-solaris") != npos) tomas@989: { tomas@989: global.params.os = OSSolaris; tomas@989: VersionCondition::addPredefinedGlobalIdent("solaris"); tomas@1387: VersionCondition::addPredefinedGlobalIdent("Solaris"); tomas@989: VersionCondition::addPredefinedGlobalIdent("Posix"); tomas@989: } tomas@989: // unsupported tomas@989: else tomas@989: { tomas@1463: error("target '%s' is not yet supported", global.params.targetTriple); tomas@989: fatal(); tomas@989: } tomas@989: tomas@989: // added in 1.039 tomas@989: if (global.params.doDocComments) tomas@989: VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); tomas@989: tomas@999: #if DMDV2 tomas@999: // unittests? tomas@999: if (global.params.useUnitTests) tomas@999: VersionCondition::addPredefinedGlobalIdent("unittest"); tomas@999: #endif tomas@999: tomas@989: // Initialization tomas@1147: Type::init(&ir); tomas@989: Id::initialize(); tomas@989: Module::init(); tomas@989: initPrecedence(); tomas@989: tomas@989: backend_init(); tomas@989: tomas@989: //printf("%d source files\n",files.dim); tomas@989: tomas@989: // Build import search path tomas@989: if (global.params.imppath) tomas@989: { kamm@1007: for (int i = 0; i < global.params.imppath->dim; i++) kamm@1007: { kamm@1007: char *path = (char *)global.params.imppath->data[i]; kamm@1007: Array *a = FileName::splitPath(path); tomas@989: kamm@1007: if (a) kamm@1007: { kamm@1007: if (!global.path) kamm@1007: global.path = new Array(); kamm@1007: global.path->append(a); kamm@1007: } tomas@989: } tomas@989: } tomas@989: tomas@989: // Build string import search path tomas@989: if (global.params.fileImppath) tomas@989: { kamm@1007: for (int i = 0; i < global.params.fileImppath->dim; i++) kamm@1007: { kamm@1007: char *path = (char *)global.params.fileImppath->data[i]; kamm@1007: Array *a = FileName::splitPath(path); tomas@989: kamm@1007: if (a) kamm@1007: { kamm@1007: if (!global.filePath) kamm@1007: global.filePath = new Array(); kamm@1007: global.filePath->append(a); kamm@1007: } tomas@989: } tomas@989: } tomas@989: tomas@989: // Create Modules tomas@989: Array modules; tomas@989: modules.reserve(files.dim); tomas@989: for (int i = 0; i < files.dim; i++) tomas@989: { Identifier *id; kamm@1007: char *ext; kamm@1007: char *name; tomas@989: kamm@1007: p = (char *) files.data[i]; tomas@989: kamm@1007: p = FileName::name(p); // strip path kamm@1007: ext = FileName::ext(p); kamm@1007: if (ext) kamm@1007: { tomas@989: #if POSIX kamm@1007: if (strcmp(ext, global.obj_ext) == 0 || kamm@1007: strcmp(ext, global.bc_ext) == 0) tomas@989: #else kamm@1007: if (stricmp(ext, global.obj_ext) == 0 || kamm@1007: stricmp(ext, global.bc_ext) == 0) tomas@989: #endif kamm@1007: { kamm@1007: global.params.objfiles->push(files.data[i]); kamm@1007: continue; kamm@1007: } tomas@989: tomas@989: #if POSIX kamm@1007: if (strcmp(ext, "a") == 0) tomas@989: #elif __MINGW32__ kamm@1007: if (stricmp(ext, "a") == 0) tomas@989: #else kamm@1007: if (stricmp(ext, "lib") == 0) tomas@989: #endif kamm@1007: { kamm@1007: global.params.libfiles->push(files.data[i]); kamm@1007: continue; kamm@1007: } tomas@989: kamm@1007: if (strcmp(ext, global.ddoc_ext) == 0) kamm@1007: { kamm@1007: global.params.ddocfiles->push(files.data[i]); kamm@1007: continue; kamm@1007: } tomas@989: tomas@989: #if !POSIX kamm@1007: if (stricmp(ext, "res") == 0) kamm@1007: { kamm@1007: global.params.resfile = (char *)files.data[i]; kamm@1007: continue; kamm@1007: } kamm@1007: kamm@1007: if (stricmp(ext, "def") == 0) kamm@1007: { kamm@1007: global.params.deffile = (char *)files.data[i]; kamm@1007: continue; kamm@1007: } kamm@1007: kamm@1007: if (stricmp(ext, "exe") == 0) kamm@1007: { kamm@1007: global.params.exefile = (char *)files.data[i]; kamm@1007: continue; kamm@1007: } kamm@1007: #endif kamm@1007: kamm@1007: if (stricmp(ext, global.mars_ext) == 0 || kamm@1007: stricmp(ext, global.hdr_ext) == 0 || kamm@1007: stricmp(ext, "htm") == 0 || kamm@1007: stricmp(ext, "html") == 0 || kamm@1007: stricmp(ext, "xhtml") == 0) kamm@1007: { kamm@1007: ext--; // skip onto '.' kamm@1007: assert(*ext == '.'); kamm@1007: name = (char *)mem.malloc((ext - p) + 1); kamm@1007: memcpy(name, p, ext - p); kamm@1007: name[ext - p] = 0; // strip extension kamm@1007: kamm@1007: if (name[0] == 0 || kamm@1007: strcmp(name, "..") == 0 || kamm@1007: strcmp(name, ".") == 0) kamm@1007: { kamm@1007: Linvalid: kamm@1007: error("invalid file name '%s'", (char *)files.data[i]); kamm@1007: fatal(); kamm@1007: } kamm@1007: } kamm@1007: else kamm@1007: { error("unrecognized file extension %s\n", ext); kamm@1007: fatal(); kamm@1007: } kamm@1007: } kamm@1007: else kamm@1007: { name = p; kamm@1007: if (!*name) kamm@1007: goto Linvalid; tomas@989: } tomas@989: kamm@1007: id = new Identifier(name, 0); kamm@1007: m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); kamm@1007: modules.push(m); tomas@989: } tomas@989: tomas@989: // Read files, parse them tomas@989: for (int i = 0; i < modules.dim; i++) tomas@989: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("parse %s\n", m->toChars()); kamm@1007: if (!Module::rootModule) kamm@1007: Module::rootModule = m; kamm@1007: m->importedFrom = m; kamm@1007: m->read(0); kamm@1007: m->parse(); kamm@1007: m->buildTargetFiles(); kamm@1007: m->deleteObjFile(); kamm@1007: if (m->isDocFile) kamm@1007: { kamm@1007: m->gendocfile(); tomas@989: kamm@1007: // Remove m from list of modules kamm@1007: modules.remove(i); kamm@1007: i--; kamm@1007: } tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: #ifdef _DH tomas@989: if (global.params.doHdrGeneration) tomas@989: { kamm@1007: /* Generate 'header' import files. kamm@1007: * Since 'header' import files must be independent of command kamm@1007: * line switches and what else is imported, they are generated kamm@1007: * before any semantic analysis. kamm@1007: */ kamm@1007: for (int i = 0; i < modules.dim; i++) kamm@1007: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("import %s\n", m->toChars()); kamm@1007: m->genhdrfile(); kamm@1007: } tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: #endif tomas@989: kamm@1587: // load all unconditional imports for better symbol resolving kamm@1587: for (int i = 0; i < modules.dim; i++) kamm@1587: { kamm@1587: m = (Module *)modules.data[i]; kamm@1587: if (global.params.verbose) kamm@1587: printf("importall %s\n", m->toChars()); kamm@1587: m->importAll(0); kamm@1587: } kamm@1587: if (global.errors) kamm@1587: fatal(); kamm@1587: tomas@989: // Do semantic analysis tomas@989: for (int i = 0; i < modules.dim; i++) tomas@989: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("semantic %s\n", m->toChars()); kamm@1007: m->semantic(); tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: tomas@989: // Do pass 2 semantic analysis tomas@989: for (int i = 0; i < modules.dim; i++) tomas@989: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("semantic2 %s\n", m->toChars()); kamm@1007: m->semantic2(); tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: tomas@989: // Do pass 3 semantic analysis tomas@989: for (int i = 0; i < modules.dim; i++) tomas@989: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("semantic3 %s\n", m->toChars()); kamm@1007: m->semantic3(); tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: tomas@989: #if !IN_LLVM tomas@989: // Scan for functions to inline tomas@989: if (global.params.useInline) tomas@989: { kamm@1007: /* The problem with useArrayBounds and useAssert is that the kamm@1007: * module being linked to may not have generated them, so if kamm@1007: * we inline functions from those modules, the symbols for them will kamm@1007: * not be found at link time. kamm@1007: */ kamm@1007: if (!global.params.useArrayBounds && !global.params.useAssert) benny@1532: #else fvbommel@1482: // This doesn't play nice with debug info at the moment fvbommel@1482: if (!global.params.symdebug && willInline()) fvbommel@1482: { fvbommel@1482: global.params.useAvailableExternally = true; fvbommel@1482: Logger::println("Running some extra semantic3's for inlining purposes"); fvbommel@1482: #endif tomas@989: { kamm@1007: // Do pass 3 semantic analysis on all imported modules, kamm@1007: // since otherwise functions in them cannot be inlined kamm@1007: for (int i = 0; i < Module::amodules.dim; i++) kamm@1007: { kamm@1007: m = (Module *)Module::amodules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("semantic3 %s\n", m->toChars()); kamm@1007: m->semantic3(); kamm@1007: } kamm@1007: if (global.errors) kamm@1007: fatal(); kamm@1007: } tomas@989: fvbommel@1482: #if !IN_LLVM kamm@1007: for (int i = 0; i < modules.dim; i++) kamm@1007: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("inline scan %s\n", m->toChars()); kamm@1007: m->inlineScan(); kamm@1007: } fvbommel@1482: #endif tomas@989: } tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: kamm@1402: // write module dependencies to file if requested kamm@1402: if (global.params.moduleDepsFile != NULL) kamm@1402: { kamm@1402: assert (global.params.moduleDepsFile != NULL); kamm@1402: kamm@1402: File deps(global.params.moduleDepsFile); kamm@1402: OutBuffer* ob = global.params.moduleDeps; kamm@1402: deps.setbuffer((void*)ob->data, ob->offset); kamm@1402: deps.write(); kamm@1402: } kamm@1402: kamm@1052: // collects llvm modules to be linked if singleobj is passed kamm@1052: std::vector llvmModules; benny@1570: llvm::LLVMContext& context = llvm::getGlobalContext(); kamm@1052: tomas@989: // Generate output files tomas@989: for (int i = 0; i < modules.dim; i++) tomas@989: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: if (global.params.verbose) kamm@1007: printf("code %s\n", m->toChars()); kamm@1007: if (global.params.obj) kamm@1007: { benny@1535: llvm::Module* lm = m->genLLVMModule(context, &ir); kamm@1052: if (!singleObj) kamm@1052: { kamm@1052: m->deleteObjFile(); kamm@1052: writeModule(lm, m->objfile->name->str); kamm@1052: global.params.objfiles->push(m->objfile->name->str); kamm@1052: delete lm; kamm@1052: } kamm@1052: else kamm@1052: llvmModules.push_back(lm); kamm@1007: } kamm@1007: if (global.errors) kamm@1007: m->deleteObjFile(); kamm@1007: else kamm@1007: { kamm@1007: if (global.params.doDocComments) kamm@1007: m->gendocfile(); kamm@1007: } tomas@989: } kamm@1052: kamm@1052: // internal linking for singleobj kamm@1052: if (singleObj && llvmModules.size() > 0) kamm@1052: { kamm@1052: Module* m = (Module*)modules.data[0]; kamm@1052: char* name = m->toChars(); kamm@1052: char* filename = m->objfile->name->str; kamm@1052: benny@1535: llvm::Linker linker(name, name, context); benny@1532: kamm@1052: std::string errormsg; kamm@1052: for (int i = 0; i < llvmModules.size(); i++) kamm@1052: { kamm@1052: if(linker.LinkInModule(llvmModules[i], &errormsg)) fvbommel@1372: error("%s", errormsg.c_str()); kamm@1052: delete llvmModules[i]; kamm@1052: } kamm@1052: kamm@1052: m->deleteObjFile(); kamm@1052: writeModule(linker.getModule(), filename); kamm@1052: global.params.objfiles->push(filename); kamm@1052: } kamm@1052: tomas@989: backend_term(); tomas@989: if (global.errors) kamm@1007: fatal(); tomas@989: tomas@989: if (!global.params.objfiles->dim) tomas@989: { kamm@1007: if (global.params.link) kamm@1007: error("no object files to link"); tomas@989: } tomas@989: else tomas@989: { kamm@1007: if (global.params.link) kamm@1586: status = linkObjToExecutable(global.params.argv0); tomas@989: kamm@1007: if (global.params.run) tomas@989: { kamm@1007: if (!status) kamm@1007: { fvbommel@1313: status = runExecutable(); tomas@989: kamm@1007: /* Delete .obj files and .exe file kamm@1007: */ kamm@1007: for (int i = 0; i < modules.dim; i++) kamm@1007: { kamm@1007: m = (Module *)modules.data[i]; kamm@1007: m->deleteObjFile(); kamm@1007: } kamm@1007: deleteExecutable(); kamm@1007: } tomas@989: } tomas@989: } tomas@989: tomas@989: return status; tomas@989: }