void StaticAssert::semantic2(Scope *sc) { Expression *e; //printf("StaticAssert::semantic2() %s\n", toChars()); e = exp->semantic(sc); e = e->optimize(WANTvalue | WANTinterpret); if (e->isBool(FALSE)) { if (msg) { HdrGenState hgs; OutBuffer buf; msg = msg->semantic(sc); msg = msg->optimize(WANTvalue | WANTinterpret); hgs.console = 1; msg->toCBuffer(&buf, &hgs); error("%s", buf.toChars()); } else error("(%s) is false", exp->toChars()); if(sc->tinst) sc->tinst->printInstantiationTrace(); if (!global.gag) { fatal(); } } else if (!e->isBool(TRUE)) { error("(%s) is not evaluatable at compile time", exp->toChars()); } }
void vwarning(Loc loc, const char *format, va_list ap) { if (global.params.warnings && !global.gag) { char *p = loc.toChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "Warning: "); #if _MSC_VER // MS doesn't recognize %zu format OutBuffer tmp; tmp.vprintf(format, ap); fprintf(stdmsg, "%s", tmp.toChars()); #else vfprintf(stdmsg, format, ap); #endif fprintf(stdmsg, "\n"); fflush(stdmsg); //halt(); if (global.params.warnings == 1) global.warnings++; // warnings don't count if gagged } }
char *TemplateInstance::mangle() { OutBuffer buf; #if 0 printf("TemplateInstance::mangle() %p %s", this, toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif char *id = ident ? ident->toChars() : toChars(); if (!tempdecl) error("is not defined"); else { Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent; if (par) { char *p = par->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } } buf.printf("%zu%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); return id; }
char *TemplateInstance::mangle() { OutBuffer buf; char *id; #if 0 printf("TemplateInstance::mangle() %s", toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif id = ident ? ident->toChars() : toChars(); if (tempdecl->parent) { char *p = tempdecl->parent->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } buf.printf(ZU "%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); return id; }
char *Dsymbol::mangle() { OutBuffer buf; char *id; #if 0 printf("Dsymbol::mangle() '%s'", toChars()); if (parent) printf(" parent = %s %s", parent->kind(), parent->toChars()); printf("\n"); #endif id = ident ? ident->toChars() : toChars(); if (parent) { char *p = parent->mangle(); if (p[0] == '_' && p[1] == 'D') p += 2; buf.writestring(p); } buf.printf("%zu%s", strlen(id), id); id = buf.toChars(); buf.data = NULL; //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); return id; }
void verror(Loc loc, const char *format, va_list ap) { if (!global.gag) { char *p = loc.toChars(); if (*p) fprintf(stdmsg, "%s: ", p); mem.free(p); fprintf(stdmsg, "Error: "); // MS doesn't recognize %zu format OutBuffer tmp; tmp.vprintf(format, ap); #if _MSC_VER fprintf(stdmsg, "%s", tmp.toChars()); #else vfprintf(stdmsg, format, ap); #endif fprintf(stdmsg, "\n"); fflush(stdmsg); //halt(); } global.errors++; }
Expression *BinExp::arrayOp(Scope *sc) { //printf("BinExp::arrayOp() %s\n", toChars()); Type *tb = type->toBasetype(); assert(tb->ty == Tarray || tb->ty == Tsarray); if (tb->nextOf()->toBasetype()->ty == Tvoid) { error("Cannot perform array operations on void[] arrays"); return new ErrorExp(); } if (!isArrayOpValid(e2)) { e2->error("invalid array operation %s (did you forget a [] ?)", toChars()); return new ErrorExp(); } Expressions *arguments = new Expressions(); /* The expression to generate an array operation for is mangled * into a name to use as the array operation function name. * Mangle in the operands and operators in RPN order, and type. */ OutBuffer buf; buf.writestring("_array"); buildArrayIdent(&buf, arguments); buf.writeByte('_'); /* Append deco of array element type */ #if DMDV2 buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); #else buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); #endif buf.writeByte(0); char *name = buf.toChars(); Identifier *ident = Lexer::idPool(name); #if IN_LLVM ArrayOp **pOp = (ArrayOp **)_aaGet(&sc->module->arrayfuncs, ident); #else ArrayOp **pOp = (ArrayOp **)_aaGet(&arrayfuncs, ident); #endif ArrayOp *op = *pOp; if (!op) op = buildArrayOp(ident, this, sc, loc); *pOp = op; FuncDeclaration *fd = op->cFunc ? op->cFunc : op->dFunc; Expression *ec = new VarExp(loc, fd); Expression *e = new CallExp(loc, ec, arguments); return e->semantic(sc); }
char *Initializer::toChars() { OutBuffer *buf; HdrGenState hgs; memset(&hgs, 0, sizeof(hgs)); buf = new OutBuffer(); toCBuffer(buf, &hgs); return buf->toChars(); }
char *mangle(Declaration *sthis) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangle(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->ident) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangle(fd); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); int len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", len); buf.prependstring(tmp); } } else buf.prependstring("0"); s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType); } id = buf.toChars(); buf.data = NULL; return id; }
Identifier *Identifier::generateId(const char *prefix, size_t i) { OutBuffer buf; buf.writestring(prefix); buf.printf("%llu", (ulonglong)i); char *id = buf.toChars(); buf.data = NULL; return Lexer::idPool(id); }
Identifier *Identifier::generateId(char *prefix) { OutBuffer buf; char *id; static unsigned i; buf.writestring(prefix); buf.printf("%u", ++i); id = buf.toChars(); buf.data = NULL; return new Identifier(id, TOKidentifier); }
void StaticAssert::semantic2(Scope *sc) { //printf("StaticAssert::semantic2() %s\n", toChars()); ScopeDsymbol *sd = new ScopeDsymbol(); sc = sc->push(sd); sc->flags |= SCOPEstaticassert; Expression *e = exp->ctfeSemantic(sc); e = resolveProperties(sc, e); // Simplify expression, to make error messages nicer if CTFE fails e = e->optimize(0); sc = sc->pop(); if (!e->type->checkBoolean()) { if (e->type->toBasetype() != Type::terror) exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); return; } unsigned olderrs = global.errors; e = e->ctfeInterpret(); if (global.errors != olderrs) { errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); } else if (e->isBool(FALSE)) { if (msg) { HdrGenState hgs; OutBuffer buf; msg = msg->ctfeSemantic(sc); msg = resolveProperties(sc, msg); msg = msg->ctfeInterpret(); hgs.console = 1; StringExp * s = msg->toString(); if (s) { s->postfix = 0; // Don't display a trailing 'c' msg = s; } msg->toCBuffer(&buf, &hgs); error("%s", buf.toChars()); } else error("(%s) is false", exp->toChars()); if (sc->tinst) sc->tinst->printInstantiationTrace(); if (!global.gag) fatal(); } else if (!e->isBool(TRUE)) { error("(%s) is not evaluatable at compile time", exp->toChars()); } }
char *Dsymbol::mangle() { OutBuffer buf; char *id; //printf("Dsymbol::mangle() '%s'\n", toChars()); id = ident ? ident->toChars() : toChars(); if (parent) { //printf(" parent = '%s', kind = '%s'\n", parent->mangle(), parent->kind()); buf.writestring(parent->mangle()); } buf.printf("%d%s", strlen(id), id); //buf.writestring("_"); //buf.writestring(id); id = buf.toChars(); buf.data = NULL; return id; }
void StaticAssert::semantic2(Scope *sc) { //printf("StaticAssert::semantic2() %s\n", toChars()); Expression *e = exp->semantic(sc); if (!e->type->checkBoolean()) { if (e->type->toBasetype() != Type::terror) exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars()); return; } unsigned olderrs = global.errors; e = e->ctfeInterpret(); if (global.errors != olderrs) { errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); } else if (e->isBool(FALSE)) { if (msg) { HdrGenState hgs; OutBuffer buf; msg = msg->semantic(sc); msg = msg->ctfeInterpret(); hgs.console = 1; msg->toCBuffer(&buf, &hgs); error("%s", buf.toChars()); } else error("(%s) is false", exp->toChars()); if (sc->tinst) sc->tinst->printInstantiationTrace(); if (!global.gag) fatal(); } else if (!e->isBool(TRUE)) { error("(%s) is not evaluatable at compile time", exp->toChars()); } }
int runLINK() { #if _WIN32 if (global.params.is64bit) { OutBuffer cmdbuf; cmdbuf.writestring("/NOLOGO "); for (size_t i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte(' '); const char *p = (*global.params.objfiles)[i]; const char *basename = FileName::removeExt(FileName::name(p)); const char *ext = FileName::ext(p); if (ext && !strchr(basename, '.')) // Write name sans extension (but not if a double extension) writeFilename(&cmdbuf, p, ext - p - 1); else writeFilename(&cmdbuf, p); FileName::free(basename); } if (global.params.resfile) { cmdbuf.writeByte(' '); writeFilename(&cmdbuf, global.params.resfile); } cmdbuf.writeByte(' '); if (global.params.exefile) { cmdbuf.writestring("/OUT:"); writeFilename(&cmdbuf, global.params.exefile); } else { /* Generate exe file name from first obj name. * No need to add it to cmdbuf because the linker will default to it. */ const char *n = (*global.params.objfiles)[0]; n = FileName::name(n); global.params.exefile = (char *)FileName::forceExt(n, "exe"); } // Make sure path to exe file exists FileName::ensurePathToNameExists(global.params.exefile); cmdbuf.writeByte(' '); if (global.params.mapfile) { cmdbuf.writestring("/MAP:"); writeFilename(&cmdbuf, global.params.mapfile); } else if (global.params.map) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; cmdbuf.writestring("/MAP:"); writeFilename(&cmdbuf, p); } for (size_t i = 0; i < global.params.libfiles->dim; i++) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEFAULTLIB:"); writeFilename(&cmdbuf, (*global.params.libfiles)[i]); } if (global.params.deffile) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEF:"); writeFilename(&cmdbuf, global.params.deffile); } if (global.params.symdebug) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DEBUG"); } if (global.params.dll) { cmdbuf.writeByte(' '); cmdbuf.writestring("/DLL"); } for (size_t i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writeByte(' '); cmdbuf.writestring((*global.params.linkswitches)[i]); } /* Append the path to the VC lib files, and then the SDK lib files */ const char *vcinstalldir = getenv("VCINSTALLDIR"); if (vcinstalldir) { cmdbuf.writestring(" \"/LIBPATH:"); cmdbuf.writestring(vcinstalldir); cmdbuf.writestring("lib\\amd64\""); } const char *windowssdkdir = getenv("WindowsSdkDir"); if (windowssdkdir) { cmdbuf.writestring(" \"/LIBPATH:"); cmdbuf.writestring(windowssdkdir); cmdbuf.writestring("lib\\x64\""); } char *p = cmdbuf.toChars(); const char *lnkfilename = NULL; size_t plen = strlen(p); if (plen > 7000) { lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); File flnk(lnkfilename); flnk.setbuffer(p, plen); flnk.ref = 1; if (flnk.write()) error(Loc(), "error writing file %s", lnkfilename); if (strlen(lnkfilename) < plen) sprintf(p, "@%s", lnkfilename); } char *linkcmd = getenv("LINKCMD64"); if (!linkcmd) { if (vcinstalldir) { OutBuffer linkcmdbuf; linkcmdbuf.writestring(vcinstalldir); linkcmdbuf.writestring("bin\\amd64\\link"); linkcmd = linkcmdbuf.toChars(); linkcmdbuf.extractData(); } else linkcmd = "link"; } int status = executecmd(linkcmd, p, 1); if (lnkfilename) { remove(lnkfilename); FileName::free(lnkfilename); } return status; } else { OutBuffer cmdbuf; global.params.libfiles->push("user32"); global.params.libfiles->push("kernel32"); for (size_t i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); const char *p = (*global.params.objfiles)[i]; const char *basename = FileName::removeExt(FileName::name(p)); const char *ext = FileName::ext(p); if (ext && !strchr(basename, '.')) // Write name sans extension (but not if a double extension) writeFilename(&cmdbuf, p, ext - p - 1); else writeFilename(&cmdbuf, p); FileName::free(basename); } cmdbuf.writeByte(','); if (global.params.exefile) writeFilename(&cmdbuf, global.params.exefile); else { /* Generate exe file name from first obj name. * No need to add it to cmdbuf because the linker will default to it. */ const char *n = (*global.params.objfiles)[0]; n = FileName::name(n); global.params.exefile = (char *)FileName::forceExt(n, "exe"); } // Make sure path to exe file exists FileName::ensurePathToNameExists(global.params.exefile); cmdbuf.writeByte(','); if (global.params.mapfile) writeFilename(&cmdbuf, global.params.mapfile); else if (global.params.map) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; writeFilename(&cmdbuf, p); } else cmdbuf.writestring("nul"); cmdbuf.writeByte(','); for (size_t i = 0; i < global.params.libfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); writeFilename(&cmdbuf, (*global.params.libfiles)[i]); } if (global.params.deffile) { cmdbuf.writeByte(','); writeFilename(&cmdbuf, global.params.deffile); } /* Eliminate unnecessary trailing commas */ while (1) { size_t i = cmdbuf.offset; if (!i || cmdbuf.data[i - 1] != ',') break; cmdbuf.offset--; } if (global.params.resfile) { cmdbuf.writestring("/RC:"); writeFilename(&cmdbuf, global.params.resfile); } if (global.params.map || global.params.mapfile) cmdbuf.writestring("/m"); #if 0 if (debuginfo) cmdbuf.writestring("/li"); if (codeview) { cmdbuf.writestring("/co"); if (codeview3) cmdbuf.writestring(":3"); } #else if (global.params.symdebug) cmdbuf.writestring("/co"); #endif cmdbuf.writestring("/noi"); for (size_t i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writestring((*global.params.linkswitches)[i]); } cmdbuf.writeByte(';'); char *p = cmdbuf.toChars(); const char *lnkfilename = NULL; size_t plen = strlen(p); if (plen > 7000) { lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); File flnk(lnkfilename); flnk.setbuffer(p, plen); flnk.ref = 1; if (flnk.write()) error(Loc(), "error writing file %s", lnkfilename); if (strlen(lnkfilename) < plen) sprintf(p, "@%s", lnkfilename); } char *linkcmd = getenv("LINKCMD"); if (!linkcmd) linkcmd = "link"; int status = executecmd(linkcmd, p, 1); if (lnkfilename) { remove(lnkfilename); FileName::free(lnkfilename); } return status; } #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun pid_t childpid; int status; // Build argv[] Strings argv; const char *cc = getenv("CC"); if (!cc) cc = "gcc"; argv.push((char *)cc); argv.insert(1, global.params.objfiles); #if __APPLE__ // If we are on Mac OS X and linking a dynamic library, // add the "-dynamiclib" flag if (global.params.dll) argv.push((char *) "-dynamiclib"); #elif linux || __FreeBSD__ || __OpenBSD__ || __sun if (global.params.dll) argv.push((char *) "-shared"); #endif // None of that a.out stuff. Use explicit exe file name, or // generate one from name of first source file. argv.push((char *)"-o"); if (global.params.exefile) { argv.push(global.params.exefile); } else { // Generate exe file name from first obj name const char *n = (*global.params.objfiles)[0]; char *ex; n = FileName::name(n); const char *e = FileName::ext(n); if (e) { e--; // back up over '.' ex = (char *)mem.malloc(e - n + 1); memcpy(ex, n, e - n); ex[e - n] = 0; // If generating dll then force dll extension if (global.params.dll) ex = (char *)FileName::forceExt(ex, global.dll_ext); } else ex = (char *)"a.out"; // no extension, so give up argv.push(ex); global.params.exefile = ex; } // Make sure path to exe file exists FileName::ensurePathToNameExists(global.params.exefile); if (global.params.symdebug) argv.push((char *)"-g"); if (global.params.is64bit) argv.push((char *)"-m64"); else argv.push((char *)"-m32"); if (global.params.map || global.params.mapfile) { argv.push((char *)"-Xlinker"); #if __APPLE__ argv.push((char *)"-map"); #else argv.push((char *)"-Map"); #endif if (!global.params.mapfile) { const char *fn = FileName::forceExt(global.params.exefile, "map"); const char *path = FileName::path(global.params.exefile); const char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn); else p = fn; global.params.mapfile = (char *)p; } argv.push((char *)"-Xlinker"); argv.push(global.params.mapfile); } if (0 && global.params.exefile) { /* This switch enables what is known as 'smart linking' * in the Windows world, where unreferenced sections * are removed from the executable. It eliminates unreferenced * functions, essentially making a 'library' out of a module. * Although it is documented to work with ld version 2.13, * in practice it does not, but just seems to be ignored. * Thomas Kuehne has verified that it works with ld 2.16.1. * BUG: disabled because it causes exception handling to fail * because EH sections are "unreferenced" and elided */ argv.push((char *)"-Xlinker"); argv.push((char *)"--gc-sections"); } for (size_t i = 0; i < global.params.linkswitches->dim; i++) { char *p = (*global.params.linkswitches)[i]; if (!p || !p[0] || !(p[0] == '-' && (p[1] == 'l' || p[1] == 'L'))) // Don't need -Xlinker if switch starts with -l or -L. // Eliding -Xlinker is significant for -L since it allows our paths // to take precedence over gcc defaults. argv.push((char *)"-Xlinker"); argv.push(p); } /* Add each library, prefixing it with "-l". * The order of libraries passed is: * 1. any libraries passed with -L command line switch * 2. libraries specified on the command line * 3. libraries specified by pragma(lib), which were appended * to global.params.libfiles. * 4. standard libraries. */ for (size_t i = 0; i < global.params.libfiles->dim; i++) { char *p = (*global.params.libfiles)[i]; size_t plen = strlen(p); if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a') argv.push(p); else { char *s = (char *)mem.malloc(plen + 3); s[0] = '-'; s[1] = 'l'; memcpy(s + 2, p, plen + 1); argv.push(s); } } /* Standard libraries must go after user specified libraries * passed with -l. */ const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; size_t slen = strlen(libname); if (slen) { char *buf = (char *)malloc(3 + slen + 1); strcpy(buf, "-l"); /* Use "-l:libname.a" if the library name is complete */ if (slen > 3 + 2 && memcmp(libname, "lib", 3) == 0 && (memcmp(libname + slen - 2, ".a", 2) == 0 || memcmp(libname + slen - 3, ".so", 3) == 0) ) { strcat(buf, ":"); } strcat(buf, libname); argv.push(buf); // turns into /usr/lib/libphobos2.a } #ifdef __sun argv.push((char *)"-mt"); #endif // argv.push((void *)"-ldruntime"); argv.push((char *)"-lpthread"); argv.push((char *)"-lm"); #if linux && DMDV2 // Changes in ld for Ubuntu 11.10 require this to appear after phobos2 argv.push((char *)"-lrt"); #endif if (!global.params.quiet || global.params.verbose) { // Print it for (size_t i = 0; i < argv.dim; i++) printf("%s ", argv[i]); printf("\n"); fflush(stdout); } argv.push(NULL); // set up pipes int fds[2]; if (pipe(fds) == -1) { perror("Unable to create pipe to linker"); return -1; } childpid = fork(); if (childpid == 0) { // pipe linker stderr to fds[0] dup2(fds[1], STDERR_FILENO); close(fds[0]); execvp(argv[0], argv.tdata()); perror(argv[0]); // failed to execute return -1; } else if (childpid == -1) { perror("Unable to fork"); return -1; } close(fds[1]); const int nme = findNoMainError(fds[0]); waitpid(childpid, &status, 0); if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status) { if (nme == -1) { perror("Error with the linker pipe"); return -1; } else { printf("--- errorlevel %d\n", status); if (nme == 1) error(Loc(), "no main function specified"); } } } else if (WIFSIGNALED(status)) { printf("--- killed by signal %d\n", WTERMSIG(status)); status = 1; } return status; #else printf ("Linking is not yet supported for this version of DMD.\n"); return -1; #endif }
llvm::GlobalVariable * IrAggr::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index) { ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base); if (it != interfaceVtblMap.end()) return it->second; IF_LOG Logger::println("Building vtbl for implementation of interface %s in class %s", b->base->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not a class aggregate"); FuncDeclarations vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); std::vector<llvm::Constant*> constants; constants.reserve(vtbl_array.dim); if (!b->base->isCPPinterface()) { // skip interface info for CPP interfaces // start with the interface info VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); // index into the interfaces array llvm::Constant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(interfaces_index) }; llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr( getInterfaceArraySymbol(), idxs, true); constants.push_back(c); } // add virtual function pointers size_t n = vtbl_array.dim; for (size_t i = b->base->vtblOffset(); i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(vtbl_array.data[i]); if (dsym == NULL) { // FIXME // why is this null? // happens for mini/s.d constants.push_back(getNullValue(getVoidPtrType())); continue; } FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); assert((!fd->isAbstract() || fd->fbody) && "null symbol in interface implementation vtable"); fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); LLFunction *fn = fd->ir.irFunc->func; // If the base is a cpp interface, 'this' parameter is a pointer to // the interface not the underlying object as expected. Instead of // the function, we place into the vtable a small wrapper, called thunk, // that casts 'this' to the object and then pass it to the real function. if (b->base->isCPPinterface()) { TypeFunction *f = (TypeFunction*)fd->type->toBasetype(); assert(f->fty.arg_this); // create the thunk function OutBuffer name; name.writestring("Th"); name.printf("%i", b->offset); name.writestring(fd->mangle()); LLFunction *thunk = LLFunction::Create(isaFunction(fn->getType()->getContainedType(0)), DtoLinkage(fd), name.toChars(), gIR->module); // create entry and end blocks llvm::BasicBlock* beginbb = llvm::BasicBlock::Create(gIR->context(), "entry", thunk); llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endentry", thunk); gIR->scopes.push_back(IRScope(beginbb, endbb)); // copy the function parameters, so later we can pass them to the real function std::vector<LLValue*> args; llvm::Function::arg_iterator iarg = thunk->arg_begin(); for (; iarg != thunk->arg_end(); ++iarg) args.push_back(iarg); // cast 'this' to Object LLValue* &thisArg = args[(f->fty.arg_sret == 0) ? 0 : 1]; LLType* thisType = thisArg->getType(); thisArg = DtoBitCast(thisArg, getVoidPtrType()); thisArg = DtoGEP1(thisArg, DtoConstInt(-b->offset)); thisArg = DtoBitCast(thisArg, thisType); // call the real vtbl function. LLValue *retVal = gIR->ir->CreateCall(fn, args); // return from the thunk if (thunk->getReturnType() == LLType::getVoidTy(gIR->context())) llvm::ReturnInst::Create(gIR->context(), beginbb); else llvm::ReturnInst::Create(gIR->context(), retVal, beginbb); // clean up gIR->scopes.pop_back(); thunk->getBasicBlockList().pop_back(); fn = thunk; } constants.push_back(fn); } // build the vtbl constant llvm::Constant* vtbl_constant = LLConstantStruct::getAnon(gIR->context(), constants, false); // create the global variable to hold it llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); std::string mangle("_D"); mangle.append(cd->mangle()); mangle.append("11__interface"); mangle.append(b->base->mangle()); mangle.append("6__vtblZ"); llvm::GlobalVariable* GV = getOrCreateGlobal(cd->loc, *gIR->module, vtbl_constant->getType(), true, _linkage, vtbl_constant, mangle ); // insert into the vtbl map interfaceVtblMap.insert(std::make_pair(b->base, GV)); return GV; }
int runLINK() { #if _WIN32 char *p; int i; int status; OutBuffer cmdbuf; global.params.libfiles->push("user32"); global.params.libfiles->push("kernel32"); for (i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); p = global.params.objfiles->tdata()[i]; char *basename = FileName::removeExt(FileName::name(p)); char *ext = FileName::ext(p); if (ext && !strchr(basename, '.')) // Write name sans extension (but not if a double extension) writeFilename(&cmdbuf, p, ext - p - 1); else writeFilename(&cmdbuf, p); mem.free(basename); } cmdbuf.writeByte(','); if (global.params.exefile) writeFilename(&cmdbuf, global.params.exefile); else { /* Generate exe file name from first obj name. * No need to add it to cmdbuf because the linker will default to it. */ char *n = global.params.objfiles->tdata()[0]; n = FileName::name(n); FileName *fn = FileName::forceExt(n, "exe"); global.params.exefile = fn->toChars(); } // Make sure path to exe file exists { char *p = FileName::path(global.params.exefile); FileName::ensurePathExists(p); mem.free(p); } cmdbuf.writeByte(','); if (global.params.mapfile) writeFilename(&cmdbuf, global.params.mapfile); else if (global.params.map) { FileName *fn = FileName::forceExt(global.params.exefile, "map"); char *path = FileName::path(global.params.exefile); char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn->toChars()); else p = fn->toChars(); writeFilename(&cmdbuf, p); } else cmdbuf.writestring("nul"); cmdbuf.writeByte(','); for (i = 0; i < global.params.libfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); writeFilename(&cmdbuf, global.params.libfiles->tdata()[i]); } if (global.params.deffile) { cmdbuf.writeByte(','); writeFilename(&cmdbuf, global.params.deffile); } /* Eliminate unnecessary trailing commas */ while (1) { i = cmdbuf.offset; if (!i || cmdbuf.data[i - 1] != ',') break; cmdbuf.offset--; } if (global.params.resfile) { cmdbuf.writestring("/RC:"); writeFilename(&cmdbuf, global.params.resfile); } if (global.params.map || global.params.mapfile) cmdbuf.writestring("/m"); #if 0 if (debuginfo) cmdbuf.writestring("/li"); if (codeview) { cmdbuf.writestring("/co"); if (codeview3) cmdbuf.writestring(":3"); } #else if (global.params.symdebug) cmdbuf.writestring("/co"); #endif cmdbuf.writestring("/noi"); for (i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writestring(global.params.linkswitches->tdata()[i]); } cmdbuf.writeByte(';'); p = cmdbuf.toChars(); FileName *lnkfilename = NULL; size_t plen = strlen(p); if (plen > 7000) { lnkfilename = FileName::forceExt(global.params.exefile, "lnk"); File flnk(lnkfilename); flnk.setbuffer(p, plen); flnk.ref = 1; if (flnk.write()) error("error writing file %s", lnkfilename); if (lnkfilename->len() < plen) sprintf(p, "@%s", lnkfilename->toChars()); } char *linkcmd = getenv("LINKCMD"); if (!linkcmd) linkcmd = "link"; status = executecmd(linkcmd, p, 1); if (lnkfilename) { remove(lnkfilename->toChars()); delete lnkfilename; } return status; #elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 pid_t childpid; int i; int status; // Build argv[] Strings argv; const char *cc = getenv("CC"); if (!cc) cc = "gcc"; argv.push((char *)cc); argv.insert(1, global.params.objfiles); #if __APPLE__ // If we are on Mac OS X and linking a dynamic library, // add the "-dynamiclib" flag if (global.params.dll) argv.push((char *) "-dynamiclib"); #endif // None of that a.out stuff. Use explicit exe file name, or // generate one from name of first source file. argv.push((char *)"-o"); if (global.params.exefile) { if (global.params.dll) global.params.exefile = FileName::forceExt(global.params.exefile, global.dll_ext)->toChars(); argv.push(global.params.exefile); } else { // Generate exe file name from first obj name char *n = global.params.objfiles->tdata()[0]; char *e; char *ex; n = FileName::name(n); e = FileName::ext(n); if (e) { e--; // back up over '.' ex = (char *)mem.malloc(e - n + 1); memcpy(ex, n, e - n); ex[e - n] = 0; // If generating dll then force dll extension if (global.params.dll) ex = FileName::forceExt(ex, global.dll_ext)->toChars(); } else ex = (char *)"a.out"; // no extension, so give up argv.push(ex); global.params.exefile = ex; } // Make sure path to exe file exists { char *p = FileName::path(global.params.exefile); FileName::ensurePathExists(p); mem.free(p); } if (global.params.symdebug) argv.push((char *)"-g"); if (global.params.isX86_64) argv.push((char *)"-m64"); else argv.push((char *)"-m32"); if (global.params.map || global.params.mapfile) { argv.push((char *)"-Xlinker"); #if __APPLE__ argv.push((char *)"-map"); #else argv.push((char *)"-Map"); #endif if (!global.params.mapfile) { FileName *fn = FileName::forceExt(global.params.exefile, "map"); char *path = FileName::path(global.params.exefile); char *p; if (path[0] == '\0') p = FileName::combine(global.params.objdir, fn->toChars()); else p = fn->toChars(); global.params.mapfile = p; } argv.push((char *)"-Xlinker"); argv.push(global.params.mapfile); } if (0 && global.params.exefile) { /* This switch enables what is known as 'smart linking' * in the Windows world, where unreferenced sections * are removed from the executable. It eliminates unreferenced * functions, essentially making a 'library' out of a module. * Although it is documented to work with ld version 2.13, * in practice it does not, but just seems to be ignored. * Thomas Kuehne has verified that it works with ld 2.16.1. * BUG: disabled because it causes exception handling to fail * because EH sections are "unreferenced" and elided */ argv.push((char *)"-Xlinker"); argv.push((char *)"--gc-sections"); } for (i = 0; i < global.params.linkswitches->dim; i++) { char *p = global.params.linkswitches->tdata()[i]; if (!p || !p[0] || !(p[0] == '-' && p[1] == 'l')) // Don't need -Xlinker if switch starts with -l argv.push((char *)"-Xlinker"); argv.push(p); } /* Add each library, prefixing it with "-l". * The order of libraries passed is: * 1. any libraries passed with -L command line switch * 2. libraries specified on the command line * 3. libraries specified by pragma(lib), which were appended * to global.params.libfiles. * 4. standard libraries. */ for (i = 0; i < global.params.libfiles->dim; i++) { char *p = global.params.libfiles->tdata()[i]; size_t plen = strlen(p); if (plen > 2 && p[plen - 2] == '.' && p[plen -1] == 'a') argv.push(p); else { char *s = (char *)mem.malloc(plen + 3); s[0] = '-'; s[1] = 'l'; memcpy(s + 2, p, plen + 1); argv.push(s); } } /* Standard libraries must go after user specified libraries * passed with -l. */ const char *libname = (global.params.symdebug) ? global.params.debuglibname : global.params.defaultlibname; char *buf = (char *)malloc(2 + strlen(libname) + 1); strcpy(buf, "-l"); strcpy(buf + 2, libname); argv.push(buf); // turns into /usr/lib/libphobos2.a // argv.push((void *)"-ldruntime"); argv.push((char *)"-lpthread"); argv.push((char *)"-lm"); if (!global.params.quiet || global.params.verbose) { // Print it for (i = 0; i < argv.dim; i++) printf("%s ", argv.tdata()[i]); printf("\n"); fflush(stdout); } argv.push(NULL); childpid = fork(); if (childpid == 0) { execvp(argv.tdata()[0], argv.tdata()); perror(argv.tdata()[0]); // failed to execute return -1; } waitpid(childpid, &status, 0); if (WIFEXITED(status)) { status = WEXITSTATUS(status); if (status) printf("--- errorlevel %d\n", status); } else if (WIFSIGNALED(status)) { printf("--- killed by signal %d\n", WTERMSIG(status)); status = 1; } return status; #else printf ("Linking is not yet supported for this version of DMD.\n"); return -1; #endif }
void obj_write_deferred(Library *library) { for (size_t i = 0; i < obj_symbols_towrite.dim; i++) { Dsymbol *s = obj_symbols_towrite[i]; Module *m = s->getModule(); char *mname; if (m) { mname = m->srcfile->toChars(); lastmname = mname; } else { //mname = s->ident->toChars(); mname = lastmname; assert(mname); } obj_start(mname); static int count; count++; // sequence for generating names /* Create a module that's a doppelganger of m, with just * enough to be able to create the moduleinfo. */ OutBuffer idbuf; idbuf.printf("%s.%d", m ? m->ident->toChars() : mname, count); char *idstr = idbuf.toChars(); if(!m) { // it doesn't make sense to make up a module if we don't know where to put the symbol // so output it into it's own object file without ModuleInfo objmod->initfile(idstr, NULL, mname); s->toObjFile(0); objmod->termfile(); } else { idbuf.data = NULL; Identifier *id = Identifier::create(idstr, TOKidentifier); Module *md = Module::create(mname, id, 0, 0); md->members = Dsymbols_create(); md->members->push(s); // its only 'member' is s md->doppelganger = 1; // identify this module as doppelganger md->md = m->md; md->aimports.push(m); // it only 'imports' m md->massert = m->massert; md->munittest = m->munittest; md->marray = m->marray; md->genobjfile(0); } /* Set object file name to be source name with sequence number, * as mangled symbol names get way too long. */ const char *fname = FileName::removeExt(mname); OutBuffer namebuf; unsigned hash = 0; for (char *p = s->toChars(); *p; p++) hash += *p; namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext); namebuf.writeByte(0); FileName::free((char *)fname); fname = (char *)namebuf.extractData(); //printf("writing '%s'\n", fname); File *objfile = File::create(fname); obj_end(library, objfile); } obj_symbols_towrite.dim = 0; }
Expression *BinExp::arrayOp(Scope *sc) { //printf("BinExp::arrayOp() %s\n", toChars()); Type *tb = type->toBasetype(); assert(tb->ty == Tarray || tb->ty == Tsarray); if (tb->nextOf()->toBasetype()->ty == Tvoid) { error("Cannot perform array operations on void[] arrays"); return new ErrorExp(); } if (!isArrayOpValid(e2)) { e2->error("invalid array operation %s (did you forget a [] ?)", toChars()); return new ErrorExp(); } Expressions *arguments = new Expressions(); /* The expression to generate an array operation for is mangled * into a name to use as the array operation function name. * Mangle in the operands and operators in RPN order, and type. */ OutBuffer buf; buf.writestring("_array"); buildArrayIdent(&buf, arguments); buf.writeByte('_'); /* Append deco of array element type */ #if DMDV2 buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); #else buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); #endif size_t namelen = buf.offset; buf.writeByte(0); char *name = buf.toChars(); Identifier *ident = Lexer::idPool(name); /* Look up name in hash table */ FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident); FuncDeclaration *fd = (FuncDeclaration *)*pfd; if (!fd) { /* Some of the array op functions are written as library functions, * presumably to optimize them with special CPU vector instructions. * List those library functions here, in alpha order. */ static const char *libArrayopFuncs[] = { "_arrayExpSliceAddass_a", "_arrayExpSliceAddass_d", // T[]+=T "_arrayExpSliceAddass_f", // T[]+=T "_arrayExpSliceAddass_g", "_arrayExpSliceAddass_h", "_arrayExpSliceAddass_i", "_arrayExpSliceAddass_k", "_arrayExpSliceAddass_s", "_arrayExpSliceAddass_t", "_arrayExpSliceAddass_u", "_arrayExpSliceAddass_w", "_arrayExpSliceDivass_d", // T[]/=T "_arrayExpSliceDivass_f", // T[]/=T "_arrayExpSliceMinSliceAssign_a", "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] "_arrayExpSliceMinSliceAssign_g", "_arrayExpSliceMinSliceAssign_h", "_arrayExpSliceMinSliceAssign_i", "_arrayExpSliceMinSliceAssign_k", "_arrayExpSliceMinSliceAssign_s", "_arrayExpSliceMinSliceAssign_t", "_arrayExpSliceMinSliceAssign_u", "_arrayExpSliceMinSliceAssign_w", "_arrayExpSliceMinass_a", "_arrayExpSliceMinass_d", // T[]-=T "_arrayExpSliceMinass_f", // T[]-=T "_arrayExpSliceMinass_g", "_arrayExpSliceMinass_h", "_arrayExpSliceMinass_i", "_arrayExpSliceMinass_k", "_arrayExpSliceMinass_s", "_arrayExpSliceMinass_t", "_arrayExpSliceMinass_u", "_arrayExpSliceMinass_w", "_arrayExpSliceMulass_d", // T[]*=T "_arrayExpSliceMulass_f", // T[]*=T "_arrayExpSliceMulass_i", "_arrayExpSliceMulass_k", "_arrayExpSliceMulass_s", "_arrayExpSliceMulass_t", "_arrayExpSliceMulass_u", "_arrayExpSliceMulass_w", "_arraySliceExpAddSliceAssign_a", "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T "_arraySliceExpAddSliceAssign_g", "_arraySliceExpAddSliceAssign_h", "_arraySliceExpAddSliceAssign_i", "_arraySliceExpAddSliceAssign_k", "_arraySliceExpAddSliceAssign_s", "_arraySliceExpAddSliceAssign_t", "_arraySliceExpAddSliceAssign_u", "_arraySliceExpAddSliceAssign_w", "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T "_arraySliceExpMinSliceAssign_a", "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T "_arraySliceExpMinSliceAssign_g", "_arraySliceExpMinSliceAssign_h", "_arraySliceExpMinSliceAssign_i", "_arraySliceExpMinSliceAssign_k", "_arraySliceExpMinSliceAssign_s", "_arraySliceExpMinSliceAssign_t", "_arraySliceExpMinSliceAssign_u", "_arraySliceExpMinSliceAssign_w", "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T "_arraySliceExpMulSliceAddass_f", "_arraySliceExpMulSliceAddass_r", "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T "_arraySliceExpMulSliceAssign_i", "_arraySliceExpMulSliceAssign_k", "_arraySliceExpMulSliceAssign_s", "_arraySliceExpMulSliceAssign_t", "_arraySliceExpMulSliceAssign_u", "_arraySliceExpMulSliceAssign_w", "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T "_arraySliceExpMulSliceMinass_f", "_arraySliceExpMulSliceMinass_r", "_arraySliceSliceAddSliceAssign_a", "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] "_arraySliceSliceAddSliceAssign_g", "_arraySliceSliceAddSliceAssign_h", "_arraySliceSliceAddSliceAssign_i", "_arraySliceSliceAddSliceAssign_k", "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] "_arraySliceSliceAddSliceAssign_s", "_arraySliceSliceAddSliceAssign_t", "_arraySliceSliceAddSliceAssign_u", "_arraySliceSliceAddSliceAssign_w", "_arraySliceSliceAddass_a", "_arraySliceSliceAddass_d", // T[]+=T[] "_arraySliceSliceAddass_f", // T[]+=T[] "_arraySliceSliceAddass_g", "_arraySliceSliceAddass_h", "_arraySliceSliceAddass_i", "_arraySliceSliceAddass_k", "_arraySliceSliceAddass_s", "_arraySliceSliceAddass_t", "_arraySliceSliceAddass_u", "_arraySliceSliceAddass_w", "_arraySliceSliceMinSliceAssign_a", "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] "_arraySliceSliceMinSliceAssign_g", "_arraySliceSliceMinSliceAssign_h", "_arraySliceSliceMinSliceAssign_i", "_arraySliceSliceMinSliceAssign_k", "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] "_arraySliceSliceMinSliceAssign_s", "_arraySliceSliceMinSliceAssign_t", "_arraySliceSliceMinSliceAssign_u", "_arraySliceSliceMinSliceAssign_w", "_arraySliceSliceMinass_a", "_arraySliceSliceMinass_d", // T[]-=T[] "_arraySliceSliceMinass_f", // T[]-=T[] "_arraySliceSliceMinass_g", "_arraySliceSliceMinass_h", "_arraySliceSliceMinass_i", "_arraySliceSliceMinass_k", "_arraySliceSliceMinass_s", "_arraySliceSliceMinass_t", "_arraySliceSliceMinass_u", "_arraySliceSliceMinass_w", "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] "_arraySliceSliceMulSliceAssign_i", "_arraySliceSliceMulSliceAssign_k", "_arraySliceSliceMulSliceAssign_s", "_arraySliceSliceMulSliceAssign_t", "_arraySliceSliceMulSliceAssign_u", "_arraySliceSliceMulSliceAssign_w", "_arraySliceSliceMulass_d", // T[]*=T[] "_arraySliceSliceMulass_f", // T[]*=T[] "_arraySliceSliceMulass_i", "_arraySliceSliceMulass_k", "_arraySliceSliceMulass_s", "_arraySliceSliceMulass_t", "_arraySliceSliceMulass_u", "_arraySliceSliceMulass_w", }; int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); if (i == -1) { #ifdef DEBUG // Make sure our array is alphabetized for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) { if (strcmp(name, libArrayopFuncs[i]) == 0) assert(0); } #endif /* Not in library, so generate it. * Construct the function body: * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) * loopbody; * return p; */ Parameters *fparams = new Parameters(); Expression *loopbody = buildArrayLoop(fparams); Parameter *p = (*fparams)[0 /*fparams->dim - 1*/]; #if DMDV1 // for (size_t i = 0; i < p.length; i++) Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); Statement *s1 = new ForStatement(0, new DeclarationStatement(0, d), new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), new ExpStatement(0, loopbody)); #else // foreach (i; 0 .. p.length) Statement *s1 = new ForeachRangeStatement(0, TOKforeach, new Parameter(0, NULL, Id::p, NULL), new IntegerExp(0, 0, Type::tsize_t), new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), new ExpStatement(0, loopbody)); #endif Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); //printf("s2: %s\n", s2->toChars()); Statement *fbody = new CompoundStatement(0, s1, s2); /* Construct the function */ TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); //printf("ftype: %s\n", ftype->toChars()); fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype); fd->fbody = fbody; fd->protection = PROTpublic; fd->linkage = LINKc; fd->isArrayOp = 1; sc->module->importedFrom->members->push(fd); sc = sc->push(); sc->parent = sc->module->importedFrom; sc->stc = 0; sc->linkage = LINKc; fd->semantic(sc); fd->semantic2(sc); fd->semantic3(sc); sc->pop(); } else { /* In library, refer to it. */ fd = FuncDeclaration::genCfunc(type, ident); } *pfd = fd; // cache symbol in hash table } /* Call the function fd(arguments) */ Expression *ec = new VarExp(0, fd); Expression *e = new CallExp(loc, ec, arguments); e->type = type; return e; }
int runLINK() { #if _WIN32 char *p; int i; int status; OutBuffer cmdbuf; global.params.libfiles->push((void *) "user32"); global.params.libfiles->push((void *) "kernel32"); for (i = 0; i < global.params.objfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); p = (char *)global.params.objfiles->data[i]; char *ext = FileName::ext(p); if (ext) cmdbuf.write(p, ext - p - 1); else cmdbuf.writestring(p); } cmdbuf.writeByte(','); if (global.params.exefile) cmdbuf.writestring(global.params.exefile); else { // Generate exe file name from first obj name char *n = (char *)global.params.objfiles->data[0]; char *ex; n = FileName::name(n); FileName *fn = FileName::forceExt(n, "exe"); global.params.exefile = fn->toChars(); } cmdbuf.writeByte(','); if (global.params.run) cmdbuf.writestring("nul"); // if (mapfile) // cmdbuf.writestring(output); cmdbuf.writeByte(','); for (i = 0; i < global.params.libfiles->dim; i++) { if (i) cmdbuf.writeByte('+'); cmdbuf.writestring((char *) global.params.libfiles->data[i]); } if (global.params.deffile) { cmdbuf.writeByte(','); cmdbuf.writestring(global.params.deffile); } /* Eliminate unnecessary trailing commas */ while (1) { i = cmdbuf.offset; if (!i || cmdbuf.data[i - 1] != ',') break; cmdbuf.offset--; } if (global.params.resfile) { cmdbuf.writestring("/RC:"); cmdbuf.writestring(global.params.resfile); } #if 0 if (mapfile) cmdbuf.writestring("/m"); if (debuginfo) cmdbuf.writestring("/li"); if (codeview) { cmdbuf.writestring("/co"); if (codeview3) cmdbuf.writestring(":3"); } #else if (global.params.symdebug) cmdbuf.writestring("/co"); #endif cmdbuf.writestring("/noi"); for (i = 0; i < global.params.linkswitches->dim; i++) { cmdbuf.writestring((char *) global.params.linkswitches->data[i]); } cmdbuf.writeByte(';'); p = cmdbuf.toChars(); char *linkcmd = getenv("LINKCMD"); if (!linkcmd) linkcmd = "link"; status = executecmd(linkcmd, p, 1); return status; #elif linux pid_t childpid; int i; int status; // Build argv[] Array argv; char *cc = getenv("CC"); if (!cc) cc = "gcc"; argv.push((void *)cc); argv.insert(1, global.params.objfiles); // None of that a.out stuff. Use explicit exe file name, or // generate one from name of first source file. argv.push((void *)"-o"); if (global.params.exefile) { argv.push(global.params.exefile); } else { // Generate exe file name from first obj name char *n = (char *)global.params.objfiles->data[0]; char *e; char *ex; n = FileName::name(n); e = FileName::ext(n); if (e) { e--; // back up over '.' ex = (char *)mem.malloc(e - n + 1); memcpy(ex, n, e - n); ex[e - n] = 0; } else ex = (char *)"a.out"; // no extension, so give up argv.push(ex); global.params.exefile = ex; } argv.insert(argv.dim, global.params.libfiles); if (global.params.symdebug) argv.push((void *)"-g"); argv.push((void *)"-m32"); argv.push((void *)"-lphobos"); // turns into /usr/lib/libphobos.a argv.push((void *)"-lpthread"); argv.push((void *)"-lm"); if (0 && global.params.exefile) { /* This switch enables what is known as 'smart linking' * in the Windows world, where unreferenced sections * are removed from the executable. It eliminates unreferenced * functions, essentially making a 'library' out of a module. * Although it is documented to work with ld version 2.13, * in practice it does not, but just seems to be ignored. * Thomas Kuehne has verified that it works with ld 2.16.1. * BUG: disabled because it causes exception handling to fail */ argv.push((void *)"-Xlinker"); argv.push((void *)"--gc-sections"); } for (i = 0; i < global.params.linkswitches->dim; i++) { argv.push((void *)"-Xlinker"); argv.push((void *) global.params.linkswitches->data[i]); } if (!global.params.quiet) { // Print it for (i = 0; i < argv.dim; i++) printf("%s ", (char *)argv.data[i]); printf("\n"); fflush(stdout); } argv.push(NULL); childpid = fork(); if (childpid == 0) { execvp((char *)argv.data[0], (char **)argv.data); perror((char *)argv.data[0]); // failed to execute return -1; } waitpid(childpid, &status, 0); status=WEXITSTATUS(status); if (status) printf("--- errorlevel %d\n", status); return status; #else printf ("Linking is not yet supported for this version of DMD.\n"); return -1; #endif }
const char *inifile(const char *argv0x, const char *inifilex) { char *argv0 = (char *)argv0x; char *inifile = (char *)inifilex; // do const-correct later char *path; // need path for @P macro char *filename; OutBuffer buf; int i; int k; int envsection = 0; #if LOG printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); #endif if (FileName::absolute(inifile)) { filename = inifile; } else { /* Look for inifile in the following sequence of places: * o current directory * o home directory * o directory off of argv0 * o /etc/ */ if (FileName::exists(inifile)) { filename = inifile; } else { filename = FileName::combine(getenv("HOME"), inifile); if (!FileName::exists(filename)) { #if _WIN32 // This fix by Tim Matthews char resolved_name[MAX_PATH + 1]; if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name)) { filename = (char *)FileName::replaceName(resolved_name, inifile); if(FileName::exists(filename)) goto Ldone; } #endif filename = (char *)FileName::replaceName(argv0, inifile); if (!FileName::exists(filename)) { #if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 #if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne /* argv0 might be a symbolic link, * so try again looking past it to the real path */ #if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 char resolved_name[PATH_MAX + 1]; char* real_argv0 = realpath(argv0, resolved_name); #else char* real_argv0 = realpath(argv0, NULL); #endif //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0); if (real_argv0) { filename = (char *)FileName::replaceName(real_argv0, inifile); #if linux free(real_argv0); #endif if (FileName::exists(filename)) goto Ldone; } #else #error use of glibc non-standard extension realpath(char*, NULL) #endif if (1) { // Search PATH for argv0 const char *p = getenv("PATH"); #if LOG printf("\tPATH='%s'\n", p); #endif Strings *paths = FileName::splitPath(p); filename = FileName::searchPath(paths, argv0, 0); if (!filename) goto Letc; // argv0 not found on path filename = (char *)FileName::replaceName(filename, inifile); if (FileName::exists(filename)) goto Ldone; } #endif // Search /etc/ for inifile Letc: filename = FileName::combine((char *)"/etc/", inifile); Ldone: ; } } } } path = FileName::path(filename); #if LOG printf("\tpath = '%s', filename = '%s'\n", path, filename); #endif File file(filename); if (file.read()) return filename; // error reading file // Parse into lines int eof = 0; for (i = 0; i < file.len && !eof; i++) { int linestart = i; for (; i < file.len; i++) { switch (file.buffer[i]) { case '\r': break; case '\n': // Skip if it was preceded by '\r' if (i && file.buffer[i - 1] == '\r') goto Lskip; break; case 0: case 0x1A: eof = 1; break; default: continue; } break; } // The line is file.buffer[linestart..i] char *line; int len; char *p; char *pn; line = (char *)&file.buffer[linestart]; len = i - linestart; buf.reset(); // First, expand the macros. // Macros are bracketed by % characters. for (k = 0; k < len; k++) { if (line[k] == '%') { int j; for (j = k + 1; j < len; j++) { if (line[j] == '%') { if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0) { // %@P% is special meaning the path to the .ini file p = path; if (!*p) p = (char *)"."; } else { int len = j - k; char tmp[10]; // big enough most of the time if (len <= sizeof(tmp)) p = tmp; else p = (char *)alloca(len); len--; memcpy(p, &line[k + 1], len); p[len] = 0; strupr(p); p = getenv(p); if (!p) p = (char *)""; } buf.writestring(p); k = j; goto L1; } } } buf.writeByte(line[k]); L1: ; } // Remove trailing spaces while (buf.offset && isspace(buf.data[buf.offset - 1])) buf.offset--; p = buf.toChars(); // The expanded line is in p. // Now parse it for meaning. p = skipspace(p); switch (*p) { case ';': // comment case 0: // blank break; case '[': // look for [Environment] p = skipspace(p + 1); for (pn = p; isalnum(*pn); pn++) ; if (pn - p == 11 && memicmp(p, "Environment", 11) == 0 && *skipspace(pn) == ']' ) envsection = 1; else envsection = 0; break; default: if (envsection) { pn = p; // Convert name to upper case; // remove spaces bracketing = for (p = pn; *p; p++) { if (islower(*p)) *p &= ~0x20; else if (isspace(*p)) memmove(p, p + 1, strlen(p)); else if (*p == '=') { p++; while (isspace(*p)) memmove(p, p + 1, strlen(p)); break; } } putenv(strdup(pn)); #if LOG printf("\tputenv('%s')\n", pn); //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); #endif } break; } Lskip: ; } return filename; }
/****************************************************************************** * isv : for the enclosing auto functions of an inner class/struct type. * An aggregate type which defined inside auto function, it might * become Voldemort Type so its object might be returned. * This flag is necessary due to avoid mutual mangling * between return type and enclosing scope. See bugzilla 8847. */ char *mangle(Declaration *sthis, bool isv) { OutBuffer buf; char *id; Dsymbol *s; //printf("::mangle(%s)\n", sthis->toChars()); s = sthis; do { //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); if (s->ident) { FuncDeclaration *fd = s->isFuncDeclaration(); if (s != sthis && fd) { id = mangle(fd, isv); buf.prependstring(id); goto L1; } else { id = s->ident->toChars(); size_t len = strlen(id); char tmp[sizeof(len) * 3 + 1]; buf.prependstring(id); sprintf(tmp, "%d", (int)len); buf.prependstring(tmp); } } else buf.prependstring("0"); s = s->parent; } while (s); // buf.prependstring("_D"); L1: //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); //printf("sthis->type = %s\n", sthis->type->toChars()); FuncDeclaration *fd = sthis->isFuncDeclaration(); if (fd && (fd->needThis() || fd->isNested())) buf.writeByte(Type::needThisPrefix()); if (isv && fd && (fd->inferRetType || getFuncTemplateDecl(fd))) { TypeFunction tfn = *(TypeFunction *)sthis->type; TypeFunction *tfo = (TypeFunction *)sthis->originalType; tfn.purity = tfo->purity; tfn.isnothrow = tfo->isnothrow; tfn.isproperty = tfo->isproperty; tfn.isref = fd->storage_class & STCauto ? false : tfo->isref; tfn.trust = tfo->trust; tfn.next = NULL; // do not mangle return type tfn.toDecoBuffer(&buf, 0); } else if (sthis->type->deco) buf.writestring(sthis->type->deco); else { #ifdef DEBUG if (!fd->inferRetType) printf("%s\n", fd->toChars()); #endif assert(fd && fd->inferRetType); } id = buf.toChars(); buf.data = NULL; return id; }
void obj_write_deferred(Library *library) { for (int i = 0; i < obj_symbols_towrite.dim; i++) { Dsymbol *s = (Dsymbol *)obj_symbols_towrite.data[i]; Module *m = s->getModule(); char *mname; if (m) { mname = m->srcfile->toChars(); lastmname = mname; } else { //mname = s->ident->toChars(); mname = lastmname; assert(mname); } obj_start(mname); static int count; count++; // sequence for generating names /* Create a module that's a doppelganger of m, with just * enough to be able to create the moduleinfo. */ OutBuffer idbuf; idbuf.printf("%s.%d", m ? m->ident->toChars() : mname, count); char *idstr = idbuf.toChars(); idbuf.data = NULL; Identifier *id = new Identifier(idstr, TOKidentifier); Module *md = new Module(mname, id, 0, 0); md->members = new Array(); md->members->push(s); // its only 'member' is s if (m) { md->doppelganger = 1; // identify this module as doppelganger md->md = m->md; md->aimports.push(m); // it only 'imports' m md->massert = m->massert; md->marray = m->marray; } md->genobjfile(0); /* Set object file name to be source name with sequence number, * as mangled symbol names get way too long. */ char *fname = FileName::removeExt(mname); OutBuffer namebuf; unsigned hash = 0; for (char *p = s->toChars(); *p; p++) hash += *p; namebuf.printf("%s_%x_%x.%s", fname, count, hash, global.obj_ext); namebuf.writeByte(0); mem.free(fname); fname = (char *)namebuf.extractData(); //printf("writing '%s'\n", fname); File *objfile = new File(fname); obj_end(library, objfile); } obj_symbols_towrite.dim = 0; }
int linkObjToBinary(bool sharedLib) { Logger::println("*** Linking executable ***"); // error string std::string errstr; // find gcc for linking llvm::sys::Path gcc = getGcc(); // get a string version for argv[0] const char* gccStr = gcc.c_str(); // build arguments std::vector<const char*> args; // first the program name ?? args.push_back(gccStr); // object files for (unsigned i = 0; i < global.params.objfiles->dim; i++) { char *p = (char *)global.params.objfiles->data[i]; args.push_back(p); } // output filename std::string output; if (!sharedLib && global.params.exefile) { // explicit output = global.params.exefile; } else if (sharedLib && global.params.objname) { // explicit output = global.params.objname; } else { // inferred // try root module name if (Module::rootModule) output = Module::rootModule->toChars(); else if (global.params.objfiles->dim) output = FileName::removeExt((char*)global.params.objfiles->data[0]); else output = "a.out"; if (sharedLib) { std::string libExt = std::string(".") + global.dll_ext; if (!endsWith(output, libExt)) { if (global.params.os != OSWindows) output = "lib" + output + libExt; else output.append(libExt); } args.push_back("-shared"); } else if (global.params.os == OSWindows && !endsWith(output, ".exe")) { output.append(".exe"); } } args.push_back("-o"); args.push_back(output.c_str()); // set the global gExePath gExePath.set(output); assert(gExePath.isValid()); // create path to exe llvm::sys::Path exedir(llvm::sys::path::parent_path(gExePath.str())); if (!exedir.empty() && !llvm::sys::fs::exists(exedir.str())) { exedir.createDirectoryOnDisk(true, &errstr); if (!errstr.empty()) { error("failed to create path to linking output: %s\n%s", exedir.c_str(), errstr.c_str()); fatal(); } } // additional linker switches for (unsigned i = 0; i < global.params.linkswitches->dim; i++) { char *p = (char *)global.params.linkswitches->data[i]; args.push_back("-Xlinker"); args.push_back(p); } // user libs for (unsigned i = 0; i < global.params.libfiles->dim; i++) { char *p = (char *)global.params.libfiles->data[i]; args.push_back(p); } // default libs bool addSoname = false; switch(global.params.os) { case OSLinux: addSoname = true; args.push_back("-lrt"); // fallthrough case OSMacOSX: args.push_back("-ldl"); // fallthrough case OSFreeBSD: addSoname = true; args.push_back("-lpthread"); args.push_back("-lm"); break; case OSSolaris: args.push_back("-lm"); args.push_back("-lumem"); // solaris TODO break; case OSWindows: // FIXME: I'd assume kernel32 etc break; } //FIXME: enforce 64 bit if (global.params.is64bit) args.push_back("-m64"); else // Assume 32-bit? args.push_back("-m32"); OutBuffer buf; if (opts::createSharedLib && addSoname) { std::string soname = opts::soname.getNumOccurrences() == 0 ? output : opts::soname; if (!soname.empty()) { buf.writestring("-Wl,-soname,"); buf.writestring(soname.c_str()); args.push_back(buf.toChars()); } } // print link command? if (!quiet || global.params.verbose) { // Print it for (int i = 0; i < args.size(); i++) printf("%s ", args[i]); printf("\n"); fflush(stdout); } Logger::println("Linking with: "); std::vector<const char*>::const_iterator I = args.begin(), E = args.end(); Stream logstr = Logger::cout(); for (; I != E; ++I) if (*I) logstr << "'" << *I << "'" << " "; logstr << "\n"; // FIXME where's flush ? // terminate args list args.push_back(NULL); // try to call linker if (int status = llvm::sys::Program::ExecuteAndWait(gcc, &args[0], NULL, NULL, 0,0, &errstr)) { error("linking failed:\nstatus: %d", status); if (!errstr.empty()) error("message: %s", errstr.c_str()); return status; } return 0; }