diff --git a/src/backend.d b/src/backend.d index 898ba6796528..cb0427633e71 100644 --- a/src/backend.d +++ b/src/backend.d @@ -26,6 +26,7 @@ extern extern (C++) Type getTypeInfoType(Type t, Scope* sc); extern extern (C++) Expression getInternalTypeInfo(Type t, Scope* sc); extern extern (C++) void genObjFile(Module m, bool multiobj); extern extern (C++) void genhelpers(Module m, bool multiobj); +extern extern (C++) void genHelpersObjFile(Module m); extern extern (C++) Symbol* toInitializer(AggregateDeclaration sd); extern extern (C++) Symbol* toModuleArray(Module m); diff --git a/src/glue.c b/src/glue.c index 9d0647aa917a..4bcb14c93a3e 100644 --- a/src/glue.c +++ b/src/glue.c @@ -94,7 +94,11 @@ 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(); + Module *m; + if (TemplateInstance *ti = s->isTemplateInstance()) + m = ti->tempdecl->getModule(); // tweak object file name + else + m = s->getModule(); char *mname; if (m) @@ -516,11 +520,9 @@ void genhelpers(Module *m, bool iscomdat) case 2: ma = m->munittest; rt = RTLSYM_DUNITTEST; bc = BCret; break; default: assert(0); } - if (!ma) continue; - localgot = NULL; // Call dassert(filename, line) @@ -560,6 +562,22 @@ void genhelpers(Module *m, bool iscomdat) } } +/************************************** + * Bugzilla 14828: If some template instantiations require + * non-root module helpers, they should be placed in + * separated object file. + */ +void genHelpersObjFile(Module *m) +{ + assert(!m->isRoot()); + + lastmname = m->srcfile->toChars(); + + objmod->initfile(lastmname, NULL, m->toPrettyChars()); + genhelpers(m, true); + objmod->termfile(); +} + /************************************** * Search for a druntime array op */ diff --git a/src/mars.c b/src/mars.c index 0041f6670b6a..bd9bb8274cd8 100644 --- a/src/mars.c +++ b/src/mars.c @@ -70,9 +70,10 @@ void parseConfFile(StringTable *environment, const char *path, size_t len, unsig void genObjFile(Module *m, bool multiobj); void genhelpers(Module *m, bool iscomdat); +void genHelpersObjFile(Module *m); /** Normalize path by turning forward slashes into backslashes */ -const char * toWinPath(const char *src) +const char *toWinPath(const char *src) { if (src == NULL) return NULL; @@ -1658,35 +1659,50 @@ Language changes listed by -transition=id:\n\ } } - if (!global.params.obj) + //printf("global.params.multiobj = %d, oneobj = %d, lib = %d\n", + // global.params.multiobj, global.params.oneobj, global.params.lib); + if (!global.params.obj || !modules.dim) { } else if (global.params.oneobj) { - if (modules.dim) - obj_start(modules[0]->srcfile->toChars()); + /* global.params.oneobj == true: + * Just only one object file is generated for the final link. + * e.g. + * dmd -ofout main.d // main.obj is generated + */ + obj_start(modules[0]->srcfile->toChars()); + for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; if (global.params.verbose) fprintf(global.stdmsg, "code %s\n", m->toChars()); + genObjFile(m, false); if (entrypoint && m == rootHasMain) genObjFile(entrypoint, false); } - for (size_t i = 0; i < Module::amodules.dim; i++) + for (size_t j = 0; j < Module::amodules.dim; j++) { - Module *m = Module::amodules[i]; - if (!m->isRoot() && (m->marray || m->massert || m->munittest)) - genhelpers(m, true); + Module *mx = Module::amodules[j]; + if (mx->isRoot()) + continue; + if (!mx->marray && !mx->massert && !mx->munittest) + continue; + genhelpers(mx, true); } - if (!global.errors && modules.dim) - { + + if (!global.errors) obj_end(library, modules[0]->objfile); - } } - else + else if (!global.params.multiobj) { + /* global.params.multiobj == false: + * The object files are generated per source files. + * e.g. + * dmd -c main.d code.d // main.obj and code.obj generated + */ for (size_t i = 0; i < modules.dim; i++) { Module *m = modules[i]; @@ -1694,21 +1710,76 @@ Language changes listed by -transition=id:\n\ fprintf(global.stdmsg, "code %s\n", m->toChars()); obj_start(m->srcfile->toChars()); - genObjFile(m, global.params.multiobj); + genObjFile(m, false); if (entrypoint && m == rootHasMain) - genObjFile(entrypoint, global.params.multiobj); + genObjFile(entrypoint, false); for (size_t j = 0; j < Module::amodules.dim; j++) { + // todo: This part is not the best for the total size of object files. + // For example: + // When both of main.d and code.d import mx, even if main.obj + // already contains mx->marray, it is stored in code.obj again. Module *mx = Module::amodules[j]; - if (mx != m && mx->importedFrom == m && (mx->marray || mx->massert || mx->munittest)) - genhelpers(mx, true); + if (mx == m || mx->importedFrom != m) + continue; + if (!mx->marray && !mx->massert && !mx->munittest) + continue; + genhelpers(mx, true); } obj_end(library, m->objfile); + + if (global.errors && !global.params.lib) + m->deleteObjFile(); + } + } + else + { + /* global.params.multiobj == true: + * Each compiled symbols are stored in separated doppelganger modules. + * The generated object files have numbered names. + * e.g. + * dmd -lib main.d code.d + * dmd -multiobj main.d code.d + * // main.foo() --> main_1_.obj + * // main.bar() --> main_2_.obj + * // code.baz() --> code_3_.obj + * // std.stdio.writeln!()() --> stdio_4_.obj + * // std.stdio.__array() --> stdio_5_.obj (Bugzilla 14828) + * // --> with -lib, all *.obj will be stored in one .lib file. + */ + for (size_t i = 0; i < modules.dim; i++) + { + Module *m = modules[i]; + if (global.params.verbose) + fprintf(global.stdmsg, "code %s\n", m->toChars()); + + obj_start(m->srcfile->toChars()); + genObjFile(m, true); + if (entrypoint && m == rootHasMain) + genObjFile(entrypoint, true); + obj_end(library, m->objfile); + obj_write_deferred(library); if (global.errors && !global.params.lib) m->deleteObjFile(); } + + for (size_t j = 0; j < Module::amodules.dim; j++) + { + Module *mx = Module::amodules[j]; + if (mx->isRoot()) + continue; + if (!mx->marray && !mx->massert && !mx->munittest) + continue; + + obj_start(mx->srcfile->toChars()); + genHelpersObjFile(mx); + obj_end(library, mx->objfile); + + if (global.errors && !global.params.lib) + mx->deleteObjFile(); + } } if (global.params.lib && !global.errors) diff --git a/src/template.c b/src/template.c index 42de24ee3768..3822d2a1bb39 100644 --- a/src/template.c +++ b/src/template.c @@ -5912,7 +5912,9 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) if (errors) goto Lerror; - if (Module *m = tempdecl->scope->module) // should use getModule() instead? + // todo: should we use getModule() instead? + // --> Yes, it's consistent with the way in glue.c. + if (Module *m = tempdecl->scope->module) { // Generate these functions as they may be used // when template is instantiated in other modules @@ -5920,6 +5922,15 @@ void TemplateInstance::semantic(Scope *sc, Expressions *fargs) toModuleArray(m); toModuleAssert(m); toModuleUnittest(m); + + // todo: This is a workaround for the object file generation pass. + // Currently, if m is a root module, this->toObjFile() may not happen + // during m->toObjFile(). For that, we have to request the module + // helpers in the early stage. + + // To avoid this hack, we should insert the primary instance 'inst' + // in the member of module m. + // It will be done by: https://github.com/D-Programming-Language/dmd/pull/4784 } /* See if there is an existing TemplateInstantiation that already diff --git a/test/runnable/extra-files/link14828a.d b/test/runnable/extra-files/link14828a.d new file mode 100644 index 000000000000..91069d8b089a --- /dev/null +++ b/test/runnable/extra-files/link14828a.d @@ -0,0 +1,8 @@ +module link14828a; + +void func1() +{ + import link14828stdio; + + writeln("ok1"); +} diff --git a/test/runnable/extra-files/link14828b.d b/test/runnable/extra-files/link14828b.d new file mode 100644 index 000000000000..90d93dc7ab10 --- /dev/null +++ b/test/runnable/extra-files/link14828b.d @@ -0,0 +1,6 @@ +module link14828b; + +void func2() +{ + import link14828stdio; +} diff --git a/test/runnable/extra-files/link14828c.d b/test/runnable/extra-files/link14828c.d new file mode 100644 index 000000000000..cd3fb0a7c559 --- /dev/null +++ b/test/runnable/extra-files/link14828c.d @@ -0,0 +1,10 @@ +module link14828c; + +import link14828a; +import link14828b; + +void test() +{ + func1(); + func2(); +} diff --git a/test/runnable/extra-files/link14828d.d b/test/runnable/extra-files/link14828d.d new file mode 100644 index 000000000000..1023aa51096e --- /dev/null +++ b/test/runnable/extra-files/link14828d.d @@ -0,0 +1,8 @@ +module link14828d; + +import link14828c; + +void main(string[] args) +{ + test(); +} diff --git a/test/runnable/extra-files/link14828stdio.d b/test/runnable/extra-files/link14828stdio.d new file mode 100644 index 000000000000..0941bf0123df --- /dev/null +++ b/test/runnable/extra-files/link14828stdio.d @@ -0,0 +1,9 @@ +module link14828stdio; + +void writeln()(string s) +{ + int[4] sa; + + sa[s.length] = 1; + // bounds check function (link14828stdio._array) +} diff --git a/test/runnable/link14828.sh b/test/runnable/link14828.sh new file mode 100755 index 000000000000..44a8aee9a2ed --- /dev/null +++ b/test/runnable/link14828.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +src=runnable${SEP}extra-files +dir=${RESULTS_DIR}${SEP}runnable +output_file=${dir}${SEP}link14828.sh.out + +rm -f ${output_file} + +if [ $OS == "win32" -o $OS == "win64" ]; then + LIBEXT=.lib +else + LIBEXT=.a +fi + +srcname=${src}${SEP}link14828 +outname=${dir}${SEP}link14828 + +libname=${outname}x${LIBEXT} +exename=${outname}y${EXE} + +# all0_order_flipped: +$DMD -m${MODEL} -I${src} -of${libname} -lib -g ${srcname}c.d ${srcname}a.d ${srcname}b.d || exit 1 +$DMD -m${MODEL} -I${src} -of${exename} -g ${libname} ${srcname}a.d ${srcname}d.d || exit 1 +${dir}/link14828y || exit 1 + +# all0: +$DMD -m${MODEL} -I${src} -of${libname} -lib -g ${srcname}c.d ${srcname}b.d ${srcname}a.d || exit 1 +$DMD -m${MODEL} -I${src} -of${exename} -g ${libname} ${srcname}a.d ${srcname}d.d || exit 1 +${dir}/link14828y || exit 1 + +# all1: +$DMD -m${MODEL} -I${src} -of${libname} -lib -g ${srcname}c.d ${srcname}a.d ${srcname}b.d || exit 1 +$DMD -m${MODEL} -I${src} -of${exename} -g ${libname} ${srcname}b.d ${srcname}d.d || exit 1 +${dir}/link14828y || exit 1 + +# all1_order_flipped: +$DMD -m${MODEL} -I${src} -of${libname} -lib -g ${srcname}c.d ${srcname}b.d ${srcname}a.d || exit 1 +$DMD -m${MODEL} -I${src} -of${exename} -g ${libname} ${srcname}b.d ${srcname}d.d || exit 1 +${dir}/link14828y || exit 1 + +rm ${libname} ${exename} ${outname}y${OBJ} + +echo Success > ${output_file}