// Pulled out of dmd/mars.c // some things are taken from llvm's llc tool // which uses the llvm license #include "gen/llvmcompat.h" #include "gen/llvm.h" #include "llvm/LinkAllVMCore.h" #include "llvm/Linker.h" #include "llvm/LLVMContext.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Host.h" #include "llvm/MC/SubtargetFeature.h" #include #include #include #include #include "rmem.h" #include "root.h" // stricmp #if __GNUC__ && !_WIN32 #include "gnuc.h" #endif #include "mars.h" #include "module.h" #include "mtype.h" #include "id.h" #include "cond.h" #include "json.h" #include "gen/logger.h" #include "gen/linkage.h" #include "gen/irstate.h" #include "gen/optimizer.h" #include "gen/metadata.h" #include "gen/passes/Passes.h" #include "driver/linker.h" #include "driver/cl_options.h" #include "gen/cl_helpers.h" using namespace opts; #include "driver/configfile.h" #include "driver/toobj.h" #if POSIX #include #elif _WIN32 #include #endif extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); extern void backend_init(); extern void backend_term(); static cl::opt noDefaultLib("nodefaultlib", cl::desc("Don't add a default library for linking implicitly"), cl::ZeroOrMore); static StringsAdapter impPathsStore("I", global.params.imppath); static cl::list importPaths("I", cl::desc("Where to look for imports"), cl::value_desc("path"), cl::location(impPathsStore), cl::Prefix); static StringsAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); static cl::list defaultlibs("defaultlib", cl::desc("Set default libraries for non-debug build"), cl::value_desc("lib,..."), cl::location(defaultLibStore), cl::CommaSeparated); static StringsAdapter debugLibStore("debuglib", global.params.debuglibnames); static cl::list debuglibs("debuglib", cl::desc("Set default libraries for debug build"), cl::value_desc("lib,..."), cl::location(debugLibStore), cl::CommaSeparated); void printVersion() { printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); printf("D Language Documentation: http://d-programming-language.org/index.html\n" "LDC Homepage: https://github.com/ldc-developers/ldc\n"); printf("\n"); printf(" Default target: %s\n", llvm::sys::getDefaultTargetTriple().c_str()); std::string CPU = llvm::sys::getHostCPUName(); if (CPU == "generic") CPU = "(unknown)"; printf(" Host CPU: %s\n", CPU.c_str()); printf("\n"); llvm::TargetRegistry::printRegisteredTargetsForVersion(); exit(EXIT_SUCCESS); } // Helper function to handle -d-debug=* and -d-version=* static void processVersions(std::vector& list, char* type, void (*setLevel)(unsigned), void (*addIdent)(const char*)) { typedef std::vector::iterator It; for(It I = list.begin(), E = list.end(); I != E; ++I) { const char* value = I->c_str(); if (isdigit(value[0])) { errno = 0; char* end; long level = strtol(value, &end, 10); if (*end || errno || level > INT_MAX) { error("Invalid %s level: %s", type, I->c_str()); } else { setLevel((unsigned)level); } } else { char* cstr = mem.strdup(value); if (Lexer::isValidIdentifier(cstr)) { addIdent(cstr); continue; } else { error("Invalid %s identifier or level: '%s'", type, I->c_str()); } } } } // Helper function to handle -of, -od, etc. static void initFromString(char*& dest, const cl::opt& src) { dest = 0; if (src.getNumOccurrences() != 0) { if (src.empty()) error("Expected argument to '-%s'", src.ArgStr); dest = mem.strdup(src.c_str()); } } #if _WIN32 && __DMC__ extern "C" { extern int _xi_a; extern int _end; } #endif int main(int argc, char** argv) { mem.init(); // initialize storage allocator mem.setStackBottom(&argv); #if _WIN32 && __DMC__ mem.addroots((char *)&_xi_a, (char *)&_end); #endif // stack trace on signals llvm::sys::PrintStackTraceOnErrorSignal(); Strings files; char *p, *ext; Module *m; int status = EXIT_SUCCESS; // Set some default values #if _WIN32 char buf[MAX_PATH]; GetModuleFileName(NULL, buf, MAX_PATH); global.params.argv0 = buf; #else global.params.argv0 = argv[0]; #endif global.params.useSwitchError = 1; global.params.linkswitches = new Strings(); global.params.libfiles = new Strings(); global.params.objfiles = new Strings(); global.params.ddocfiles = new Strings(); global.params.moduleDeps = NULL; global.params.moduleDepsFile = NULL; // Set predefined version identifiers VersionCondition::addPredefinedGlobalIdent("LLVM"); VersionCondition::addPredefinedGlobalIdent("LDC"); VersionCondition::addPredefinedGlobalIdent("all"); #if DMDV2 VersionCondition::addPredefinedGlobalIdent("D_Version2"); #endif // build complete fixed up list of command line arguments std::vector final_args; final_args.reserve(argc); // insert command line args until -run is reached int run_argnum = 1; while (run_argnum < argc && strncmp(argv[run_argnum], "-run", 4) != 0) ++run_argnum; final_args.insert(final_args.end(), &argv[0], &argv[run_argnum]); // read the configuration file ConfigFile cfg_file; // just ignore errors for now, they are still printed #if DMDV2 #define CFG_FILENAME "ldc2.conf" #else #define CFG_FILENAME "ldc.conf" #endif cfg_file.read(global.params.argv0, (void*)main, CFG_FILENAME); #undef CFG_FILENAME // insert config file additions to the argument list final_args.insert(final_args.end(), cfg_file.switches_begin(), cfg_file.switches_end()); // insert -run and everything beyond final_args.insert(final_args.end(), &argv[run_argnum], &argv[argc]); #if 0 for (size_t i = 0; i < final_args.size(); ++i) { printf("final_args[%zu] = %s\n", i, final_args[i]); } #endif // Initialize LLVM. // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); // Handle fixed-up arguments! cl::SetVersionPrinter(&printVersion); cl::ParseCommandLineOptions(final_args.size(), const_cast(&final_args[0]), "LLVM-based D Compiler\n", true); // Print config file path if -v was passed if (global.params.verbose) { const std::string& path = cfg_file.path(); if (!path.empty()) printf("config %s\n", path.c_str()); } bool skipModules = mCPU == "help" ||(!mAttrs.empty() && mAttrs.front() == "help"); // Negated options global.params.link = !compileOnly; global.params.obj = !dontWriteObj; global.params.useInlineAsm = !noAsm; // String options: std::string --> char* initFromString(global.params.objname, objectFile); initFromString(global.params.objdir, objectDir); initFromString(global.params.docdir, ddocDir); initFromString(global.params.docname, ddocFile); global.params.doDocComments |= global.params.docdir || global.params.docname; initFromString(global.params.xfilename, jsonFile); if (global.params.xfilename) global.params.doXGeneration = true; initFromString(global.params.hdrdir, hdrDir); initFromString(global.params.hdrname, hdrFile); global.params.doHdrGeneration |= global.params.hdrdir || global.params.hdrname; initFromString(global.params.moduleDepsFile, moduleDepsFile); if (global.params.moduleDepsFile != NULL) { global.params.moduleDeps = new OutBuffer; } processVersions(debugArgs, "debug", DebugCondition::setGlobalLevel, DebugCondition::addGlobalIdent); processVersions(versions, "version", VersionCondition::setGlobalLevel, VersionCondition::addGlobalIdent); global.params.output_o = (opts::output_o == cl::BOU_UNSET && !(opts::output_bc || opts::output_ll || opts::output_s)) ? OUTPUTFLAGdefault : opts::output_o == cl::BOU_TRUE ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; templateLinkage = opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage : LLGlobalValue::WeakODRLinkage; if (global.params.run || !runargs.empty()) { // FIXME: how to properly detect the presence of a PositionalEatsArgs // option without parameters? We want to emit an error in that case... // You'd think getNumOccurrences would do it, but it just returns the // number of parameters) // NOTE: Hacked around it by detecting -run in getenv_setargv(), where // we're looking for it anyway, and pre-setting the flag... global.params.run = true; if (!runargs.empty()) { files.push(mem.strdup(runargs[0].c_str())); } else { global.params.run = false; error("Expected at least one argument to '-run'\n"); } } files.reserve(fileList.size()); typedef std::vector::iterator It; for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) if (!I->empty()) files.push(mem.strdup(I->c_str())); if (global.errors) { fatal(); } if (files.dim == 0 && !skipModules) { cl::PrintHelpMessage(); return EXIT_FAILURE; } #if LDC_LLVM_VER >= 301 llvm::TargetOptions targetOptions; #endif Array* libs; if (global.params.symdebug) { libs = global.params.debuglibnames; #if LDC_LLVM_VER == 300 llvm::NoFramePointerElim = true; #else targetOptions.NoFramePointerElim = true; #endif } else libs = global.params.defaultlibnames; if (!noDefaultLib) { if (libs) { for (unsigned i = 0; i < libs->dim; i++) { char* lib = static_cast(libs->data[i]); char *arg = static_cast(mem.malloc(strlen(lib) + 3)); strcpy(arg, "-l"); strcpy(arg+2, lib); global.params.linkswitches->push(arg); } } else { #if DMDV2 global.params.linkswitches->push(mem.strdup("-ldruntime-ldc")); #else global.params.linkswitches->push(mem.strdup("-lldc-runtime")); global.params.linkswitches->push(mem.strdup("-ltango-cc-tango")); global.params.linkswitches->push(mem.strdup("-ltango-gc-basic")); // pass the runtime again to resolve issues // with linking order global.params.linkswitches->push(mem.strdup("-lldc-runtime")); #endif } } if (global.params.run) quiet = 1; if (global.params.useUnitTests) global.params.useAssert = 1; // LDC output determination // if we don't link, autodetect target from extension if(!global.params.link && global.params.objname) { ext = FileName::ext(global.params.objname); bool autofound = false; if (!ext) { // keep things as they are } else if (strcmp(ext, global.ll_ext) == 0) { global.params.output_ll = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.bc_ext) == 0) { global.params.output_bc = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.s_ext) == 0) { global.params.output_s = OUTPUTFLAGset; autofound = true; } else if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.obj_ext_alt) == 0) { global.params.output_o = OUTPUTFLAGset; autofound = true; } else { // append dot, so forceExt won't change existing name even if it contains dots size_t len = strlen(global.params.objname); char* s = static_cast(mem.malloc(len + 1 + 1)); memcpy(s, global.params.objname, len); s[len] = '.'; s[len+1] = 0; global.params.objname = s; } if(autofound && global.params.output_o == OUTPUTFLAGdefault) global.params.output_o = OUTPUTFLAGno; } // only link if possible if (!global.params.obj || !global.params.output_o || createStaticLib) global.params.link = 0; if (createStaticLib && createSharedLib) error("-lib and -shared switches cannot be used together"); if (createSharedLib && mRelocModel == llvm::Reloc::Default) mRelocModel = llvm::Reloc::PIC_; if (global.params.link && !createSharedLib) { global.params.exefile = global.params.objname; if (files.dim > 1) global.params.objname = NULL; } else if (global.params.run) { error("flags conflict with -run"); fatal(); } else if (global.params.objname && files.dim > 1) { if (createStaticLib || createSharedLib) { singleObj = true; } if (!singleObj) { error("multiple source files, but only one .obj name"); fatal(); } } if (soname.getNumOccurrences() > 0 && !createSharedLib) { error("-soname can be used only when building a shared library"); fatal(); } // create a proper target Ir ir; // check -m32/64 sanity if (m32bits && m64bits) error("cannot use both -m32 and -m64 options"); else if ((m32bits || m64bits) && (!mArch.empty() || !mTargetTriple.empty())) error("-m32 and -m64 switches cannot be used together with -march and -mtriple switches"); if (global.errors) fatal(); // override triple if needed std::string defaultTriple = llvm::sys::getDefaultTargetTriple(); if (sizeof(void*) == 4 && m64bits) { #if LDC_LLVM_VER >= 301 defaultTriple = llvm::Triple(defaultTriple).get64BitArchVariant().str(); #else defaultTriple = llvm::Triple__get64BitArchVariant(defaultTriple).str(); #endif } else if (sizeof(void*) == 8 && m32bits) { #if LDC_LLVM_VER >= 301 defaultTriple = llvm::Triple(defaultTriple).get32BitArchVariant().str(); #else defaultTriple = llvm::Triple__get32BitArchVariant(defaultTriple).str(); #endif } std::string triple; // did the user override the target triple? if (mTargetTriple.empty()) { if (!mArch.empty()) { error("you must specify a target triple as well with -mtriple when using the -march option"); fatal(); } triple = defaultTriple; } else { triple = llvm::Triple::normalize(mTargetTriple); } global.params.targetTriple = triple.c_str(); // Allocate target machine. const llvm::Target *theTarget = NULL; // Check whether the user has explicitly specified an architecture to compile for. if (mArch.empty()) { std::string Err; theTarget = llvm::TargetRegistry::lookupTarget(triple, Err); if (theTarget == 0) { error("%s Please use the -march option.", Err.c_str()); fatal(); } } else { for (llvm::TargetRegistry::iterator it = llvm::TargetRegistry::begin(), ie = llvm::TargetRegistry::end(); it != ie; ++it) { if (mArch == it->getName()) { theTarget = &*it; break; } } if (!theTarget) { error("invalid target '%s'", mArch.c_str()); fatal(); } } // Package up features to be passed to target/subtarget std::string FeaturesStr; if (mCPU.size() || mAttrs.size()) { llvm::SubtargetFeatures Features; for (unsigned i = 0; i != mAttrs.size(); ++i) Features.AddFeature(mAttrs[i]); FeaturesStr = Features.getString(); } // FIXME //std::auto_ptr target(theTarget->createTargetMachine(triple, FeaturesStr)); //assert(target.get() && "Could not allocate target machine!"); //gTargetMachine = target.get(); #if LDC_LLVM_VER == 300 llvm::TargetMachine* target = theTarget->createTargetMachine(triple, mCPU, FeaturesStr, mRelocModel, mCodeModel); #else llvm::TargetMachine * target = theTarget->createTargetMachine( llvm::StringRef(triple), llvm::StringRef(mCPU), llvm::StringRef(FeaturesStr), targetOptions, mRelocModel, mCodeModel, codeGenOptLevel() ); #endif gTargetMachine = target; gTargetData = target->getTargetData(); // get final data layout std::string datalayout = gTargetData->getStringRepresentation(); global.params.dataLayout = datalayout.c_str(); global.params.llvmArch = theTarget->getName(); if (strcmp(global.params.llvmArch,"x86")==0) { VersionCondition::addPredefinedGlobalIdent("X86"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHx86; if (global.params.useInlineAsm) { VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); } } else if (strcmp(global.params.llvmArch,"x86-64")==0) { VersionCondition::addPredefinedGlobalIdent("X86_64"); global.params.isLE = true; global.params.is64bit = true; global.params.cpu = ARCHx86_64; if (global.params.useInlineAsm) { VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); } } else if (strcmp(global.params.llvmArch,"ppc32")==0) { VersionCondition::addPredefinedGlobalIdent("PPC"); global.params.isLE = false; global.params.is64bit = false; global.params.cpu = ARCHppc; } else if (strcmp(global.params.llvmArch,"ppc64")==0) { VersionCondition::addPredefinedGlobalIdent("PPC64"); global.params.isLE = false; global.params.is64bit = true; global.params.cpu = ARCHppc_64; } else if (strcmp(global.params.llvmArch,"arm")==0) { VersionCondition::addPredefinedGlobalIdent("ARM"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHarm; } else if (strcmp(global.params.llvmArch,"thumb")==0) { VersionCondition::addPredefinedGlobalIdent("ARM"); VersionCondition::addPredefinedGlobalIdent("Thumb"); global.params.isLE = true; global.params.is64bit = false; global.params.cpu = ARCHthumb; } else { error("invalid cpu architecture specified: %s", global.params.llvmArch); fatal(); } // endianness if (global.params.isLE) { VersionCondition::addPredefinedGlobalIdent("LittleEndian"); } else { VersionCondition::addPredefinedGlobalIdent("BigEndian"); } // a generic 64bit version if (global.params.is64bit) { VersionCondition::addPredefinedGlobalIdent("LLVM64"); // FIXME: is this always correct? VersionCondition::addPredefinedGlobalIdent("D_LP64"); } if (mRelocModel == llvm::Reloc::PIC_) { VersionCondition::addPredefinedGlobalIdent("D_PIC"); } // parse the OS out of the target triple // see http://gcc.gnu.org/install/specific.html for details // also llvm's different SubTargets have useful information switch (llvm::Triple(triple).getOS()) { case llvm::Triple::Win32: global.params.os = OSWindows; VersionCondition::addPredefinedGlobalIdent("Windows"); VersionCondition::addPredefinedGlobalIdent("Win32"); if (global.params.is64bit) { VersionCondition::addPredefinedGlobalIdent("Win64"); } break; case llvm::Triple::MinGW32: global.params.os = OSWindows; VersionCondition::addPredefinedGlobalIdent("Windows"); VersionCondition::addPredefinedGlobalIdent("Win32"); VersionCondition::addPredefinedGlobalIdent("mingw32"); VersionCondition::addPredefinedGlobalIdent("MinGW"); if (global.params.is64bit) { VersionCondition::addPredefinedGlobalIdent("Win64"); } break; case llvm::Triple::Cygwin: error("CygWin is not yet supported"); fatal(); break; case llvm::Triple::Linux: global.params.os = OSLinux; VersionCondition::addPredefinedGlobalIdent("linux"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case llvm::Triple::Haiku: global.params.os = OSHaiku; VersionCondition::addPredefinedGlobalIdent("Haiku"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case llvm::Triple::Darwin: global.params.os = OSMacOSX; VersionCondition::addPredefinedGlobalIdent("OSX"); VersionCondition::addPredefinedGlobalIdent("darwin"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case llvm::Triple::FreeBSD: global.params.os = OSFreeBSD; VersionCondition::addPredefinedGlobalIdent("freebsd"); VersionCondition::addPredefinedGlobalIdent("FreeBSD"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; case llvm::Triple::Solaris: global.params.os = OSSolaris; VersionCondition::addPredefinedGlobalIdent("solaris"); VersionCondition::addPredefinedGlobalIdent("Solaris"); VersionCondition::addPredefinedGlobalIdent("Posix"); break; default: error("target '%s' is not yet supported", global.params.targetTriple); fatal(); } // Expose LLVM version to runtime #define STR(x) #x #define XSTR(x) STR(x) VersionCondition::addPredefinedGlobalIdent("LDC_LLVM_"XSTR(LDC_LLVM_VER)); #undef XSTR #undef STR if (global.params.os == OSWindows) { global.dll_ext = "dll"; global.lib_ext = "lib"; } else { global.dll_ext = "so"; global.lib_ext = "a"; } // added in 1.039 if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); #if DMDV2 // unittests? if (global.params.useUnitTests) VersionCondition::addPredefinedGlobalIdent("unittest"); #endif // Initialization Type::init(&ir); Id::initialize(); Module::init(); initPrecedence(); backend_init(); //printf("%d source files\n",files.dim); // Build import search path if (global.params.imppath) { for (unsigned i = 0; i < global.params.imppath->dim; i++) { char *path = static_cast(global.params.imppath->data[i]); Strings *a = FileName::splitPath(path); if (a) { if (!global.path) global.path = new Strings(); global.path->append(a); } } } // Build string import search path if (global.params.fileImppath) { for (unsigned i = 0; i < global.params.fileImppath->dim; i++) { char *path = static_cast(global.params.fileImppath->data[i]); Strings *a = FileName::splitPath(path); if (a) { if (!global.filePath) global.filePath = new Strings(); global.filePath->append(a); } } } // Create Modules Modules modules; modules.reserve(files.dim); for (unsigned i = 0; i < files.dim; i++) { Identifier *id; char *ext; char *name; p = static_cast(files.data[i]); p = FileName::name(p); // strip path ext = FileName::ext(p); if (ext) { #if POSIX if (strcmp(ext, global.obj_ext) == 0 || strcmp(ext, global.bc_ext) == 0) #else if (stricmp(ext, global.obj_ext) == 0 || stricmp(ext, global.bc_ext) == 0) #endif { global.params.objfiles->push(static_cast(files.data[i])); continue; } #if POSIX if (strcmp(ext, "a") == 0) #elif __MINGW32__ if (stricmp(ext, "a") == 0) #else if (stricmp(ext, "lib") == 0) #endif { global.params.libfiles->push(static_cast(files.data[i])); continue; } if (strcmp(ext, global.ddoc_ext) == 0) { global.params.ddocfiles->push(static_cast(files.data[i])); continue; } if (FileName::equals(ext, global.json_ext)) { global.params.doXGeneration = 1; global.params.xfilename = static_cast(files.data[i]); continue; } #if !POSIX if (stricmp(ext, "res") == 0) { global.params.resfile = static_cast(files.data[i]); continue; } if (stricmp(ext, "def") == 0) { global.params.deffile = static_cast(files.data[i]); continue; } if (stricmp(ext, "exe") == 0) { global.params.exefile = static_cast(files.data[i]); continue; } #endif if (stricmp(ext, global.mars_ext) == 0 || stricmp(ext, global.hdr_ext) == 0) { ext--; // skip onto '.' assert(*ext == '.'); name = static_cast(mem.malloc((ext - p) + 1)); memcpy(name, p, ext - p); name[ext - p] = 0; // strip extension if (name[0] == 0 || strcmp(name, "..") == 0 || strcmp(name, ".") == 0) { Linvalid: error("invalid file name '%s'", static_cast(files.data[i])); fatal(); } } else { error("unrecognized file extension %s\n", ext); fatal(); } } else { name = p; if (!*name) goto Linvalid; } id = Lexer::idPool(name); m = new Module(static_cast(files.data[i]), id, global.params.doDocComments, global.params.doHdrGeneration); m->isRoot = true; modules.push(m); } // Read files, parse them for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("parse %s\n", m->toChars()); if (!Module::rootModule) Module::rootModule = m; m->importedFrom = m; m->read(0); m->parse(global.params.doDocComments); m->buildTargetFiles(singleObj); m->deleteObjFile(); if (m->isDocFile) { m->gendocfile(); // Remove m from list of modules modules.remove(i); i--; } } if (global.errors) fatal(); if (global.params.doHdrGeneration) { /* Generate 'header' import files. * Since 'header' import files must be independent of command * line switches and what else is imported, they are generated * before any semantic analysis. */ for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("import %s\n", m->toChars()); m->genhdrfile(); } } if (global.errors) fatal(); // load all unconditional imports for better symbol resolving for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("importall %s\n", m->toChars()); m->importAll(0); } if (global.errors) fatal(); // Do semantic analysis for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("semantic %s\n", m->toChars()); m->semantic(); } if (global.errors) fatal(); Module::dprogress = 1; Module::runDeferredSemantic(); // Do pass 2 semantic analysis for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("semantic2 %s\n", m->toChars()); m->semantic2(); } if (global.errors) fatal(); // Do pass 3 semantic analysis for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("semantic3 %s\n", m->toChars()); m->semantic3(); } if (global.errors) fatal(); #if !IN_LLVM // Scan for functions to inline if (global.params.useInline) { /* The problem with useArrayBounds and useAssert is that the * module being linked to may not have generated them, so if * we inline functions from those modules, the symbols for them will * not be found at link time. */ if (!global.params.useArrayBounds && !global.params.useAssert) #else // This doesn't play nice with debug info at the moment if (!global.params.symdebug && willInline()) { global.params.useAvailableExternally = true; Logger::println("Running some extra semantic3's for inlining purposes"); #endif { // Do pass 3 semantic analysis on all imported modules, // since otherwise functions in them cannot be inlined for (unsigned i = 0; i < Module::amodules.dim; i++) { m = static_cast(Module::amodules.data[i]); if (global.params.verbose) printf("semantic3 %s\n", m->toChars()); m->semantic2(); m->semantic3(); } if (global.errors) fatal(); } #if !IN_LLVM for (int i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("inline scan %s\n", m->toChars()); m->inlineScan(); } #endif } if (global.errors || global.warnings) fatal(); // write module dependencies to file if requested if (global.params.moduleDepsFile != NULL) { assert (global.params.moduleDepsFile != NULL); File deps(global.params.moduleDepsFile); OutBuffer* ob = global.params.moduleDeps; deps.setbuffer(static_cast(ob->data), ob->offset); deps.write(); } // collects llvm modules to be linked if singleobj is passed std::vector llvmModules; llvm::LLVMContext& context = llvm::getGlobalContext(); // Generate output files for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); if (global.params.verbose) printf("code %s\n", m->toChars()); if (global.params.obj) { llvm::Module* lm = m->genLLVMModule(context, &ir); if (!singleObj) { m->deleteObjFile(); writeModule(lm, m->objfile->name->str); global.params.objfiles->push(m->objfile->name->str); delete lm; } else llvmModules.push_back(lm); } if (global.errors) m->deleteObjFile(); else { if (global.params.doDocComments) m->gendocfile(); } } // internal linking for singleobj if (singleObj && llvmModules.size() > 0) { Module* m = static_cast(modules.data[0]); char* name = m->toChars(); char* filename = m->objfile->name->str; llvm::Linker linker(name, name, context); std::string errormsg; for (int i = 0; i < llvmModules.size(); i++) { if(linker.LinkInModule(llvmModules[i], &errormsg)) error("%s", errormsg.c_str()); delete llvmModules[i]; } m->deleteObjFile(); writeModule(linker.getModule(), filename); global.params.objfiles->push(filename); } // output json file if (global.params.doXGeneration) json_generate(&modules); backend_term(); if (global.errors) fatal(); if (!global.params.objfiles->dim) { if (global.params.link) error("no object files to link"); else if (createStaticLib) error("no object files"); } else { if (global.params.link) status = linkObjToBinary(createSharedLib); else if (createStaticLib) createStaticLibrary(); if (global.params.run) { if (!status) { status = runExecutable(); /* Delete .obj files and .exe file */ for (unsigned i = 0; i < modules.dim; i++) { m = static_cast(modules.data[i]); m->deleteObjFile(); } deleteExecutable(); } } } return status; }