Hi, Currently, the druntime and phobos unittests are compiled as a separate check program, then ran by the libphobos.unittest/unittest.exp script. As PR 89255 notes, this process lacks proper multilib handling.
What I want to do instead is compile and run each module that contains unittests as a standalone program using dg-runtest. Doing this however requires linking to libphobos, where a second copy of the module and all its symbols exist. This does not fair well at all with shared libraries where the D runtime module registry will error and abort because of two modules in different DSOs have the same name. To handle this conflict, I've added a new internal option that instructs the compiler to put the reference to all unittest functions in another symbol. Its use being along the lines of: # make: Compile module to then add to libphobos.a and libphobos.so gdc-c $PIC $MULTILIB $GDCFLAGS core/foo.d # make check: Compile module as standalone program linking # against libphobos, trusting that any symbol that appears in the # library is overridden without a linking error. gdc $MULTILIB -fmain -funittest -fbuilding-libphobos-tests core/foo.d I checked this on x86_64-linux-gnu, and all links, runs, and passes without problems. Would there be any problems in doing this with other linkers/platforms? -- Iain --- gcc/d/ChangeLog: 2019-03-29 Iain Buclaw <ibuc...@gdcproject.org> * lang.opt (-fbuiding-libphobos-tests): Add option. * modules.cc (build_module_tree): Generate second moduleinfo symbol to hold reference to unittests if flag_building_libphobos_tests. ---
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index 523f73c90de..f65be444d45 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -197,6 +197,10 @@ Enum(bounds_check) String(safeonly) Value(1) EnumValue Enum(bounds_check) String(on) Value(2) +; Generates a secondary ModuleInfo symbol for linking in unittests +fbuilding-libphobos-tests +D Undocumented Var(flag_building_libphobos_tests) + fbuiltin D Var(flag_no_builtin, 0) ; Documented in C diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index a1fc534c3b6..a863f525a27 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -718,6 +718,33 @@ build_module_tree (Module *decl) } } + /* For libphobos-internal use only. Generate a separate module info symbol + that references all compiled in unittests, this allows compiling library + modules and linking to libphobos without having run-time conflicts because + of two ModuleInfo records with the same name being present in two DSOs. */ + if (flag_building_libphobos_tests && mi.unitTests) + { + /* Associate the module info symbol with a mock module. */ + const char *name = concat (GDC_PREFIX ("modtest__"), + decl->ident->toChars (), NULL); + Module *tm = Module::create (decl->arg, Identifier::idPool (name), 0, 0); + Dsymbols members; + + /* Setting parent puts module in the same package as the current, to + avoid any symbol conflicts. */ + tm->parent = decl->parent; + tm->members = &members; + /* Register the current module as being imported by the mock module. + This informs run-time that there is a dependency between the two. */ + tm->aimports.push (decl); + + tm->stest = build_funcs_gates_fn (get_identifier ("*__modtest"), + mi.unitTests, NULL); + mi.unitTests = NULL; + + layout_moduleinfo (tm); + } + /* Default behavior is to always generate module info because of templates. Can be switched off for not compiling against runtime library. */ if (!global.params.betterC