I stumbled upon this while trying to build latest GtkD with gdc 5.4. It seems like the symbols related to template mixins get included twice. $ git clone 'https://github.com/gtkd-developers/GtkD.git' $ cd GtkD $ export DC=gdc $ make [...] ar rcs libgtkdgl-3.a srcgl/glgtk/GLCapability.o srcgl/glgtk/GLtInit.o srcgl/glgtk/GLWidget.o srcgl/glgdk/GLDrawable.o srcgl/glgdk/GLDrawableT.o srcgl/glgdk/GLQuery.o srcgl/glgdk/GLDrawableIF.o srcgl/glgdk/GLVersion.o srcgl/glgdk/GLWindow.o srcgl/glgdk/GLdInit.o srcgl/glgdk/GLConfig.o srcgl/glgdk/GLContext.o srcgl/gtkglc/gl.o srcgl/gtkglc/glgtktypes.o srcgl/gtkglc/glgtk.o srcgl/gtkglc/glgdk.o srcgl/gtkglc/glu.o srcgl/gtkglc/glgdktypes.o ar rcs libgtkdsv-3.a srcsv/gsv/SourceFileSaver.o srcsv/gsv/StyleSchemeChooserWidget.o srcsv/gsv/SourceUndoManagerT.o srcsv/gsv/SourceStyleSchemeManager.o srcsv/gsv/SourceSearchContext.o srcsv/gsv/SourceEncoding.o srcsv/gsv/SourceCompletionProviderT.o srcsv/gsv/SourceMap.o srcsv/gsv/SourceCompletionProvider.o srcsv/gsv/SourceCompletionItem.o srcsv/gsv/SourceGutterRendererText.o srcsv/gsv/SourceGutter.o srcsv/gsv/SourceMarkAttributes.o srcsv/gsv/SourceUndoManager.o srcsv/gsv/SourceBuffer.o srcsv/gsv/StyleSchemeChooserT.o srcsv/gsv/SourceCompletionInfo.o srcsv/gsv/SourceCompletionWords.o srcsv/gsv/Tag.o srcsv/gsv/SourceFileLoader.o srcsv/gsv/SourceStyle.o srcsv/gsv/SourcePrintCompositor.o srcsv/gsv/SourceGutterRenderer.o srcsv/gsv/SourceSearchSettings.o srcsv/gsv/SourceView.o srcsv/gsv/SourceFile.o srcsv/gsv/SourceCompletionProposalT.o srcsv/gsv/StyleSchemeChooserIF.o srcsv/gsv/SourceLanguage.o srcsv/gsv/SourceCompletion.o srcsv/gsv/Utils.o srcsv/gsv/SourceStyleScheme.o srcsv/gsv/SourceCompletionContext.o srcsv/gsv/SourceLanguageManager.o srcsv/gsv/SourceUndoManagerIF.o srcsv/gsv/SourceGutterRendererPixbuf.o srcsv/gsv/SourceCompletionProviderIF.o srcsv/gsv/SourceCompletionProposalIF.o srcsv/gsv/SourceMark.o srcsv/gsv/StyleSchemeChooserButton.o srcsv/gsvc/gsvtypes.o srcsv/gsvc/gsv.o gdc demos/gtkD/TestWindow/TestThemes.o demos/gtkD/TestWindow/TEditableCells.o demos/gtkD/TestWindow/TestEntries.o demos/gtkD/TestWindow/TestAspectFrame.o demos/gtkD/TestWindow/TestText.o demos/gtkD/TestWindow/TestScales.o demos/gtkD/TestWindow/TestImage.o demos/gtkD/TestWindow/TestIdle.o demos/gtkD/TestWindow/TestTreeView1.o demos/gtkD/TestWindow/TTextView.o demos/gtkD/TestWindow/TestWindow.o demos/gtkD/TestWindow/TestTreeView.o demos/gtkD/TestWindow/TestDrawingArea.o demos/gtkD/TestWindow/TestStock.o -o TestWindow -Xlinker -L. -Xlinker -lgtkd-3 -Xlinker -ldl -m64 ranlib libgtkdgl-3.a ranlib libgtkdsv-3.a ./libgtkd-3.a(Entry.o): In function `_D3gtk6Widget6Widget10__mixin56514customTagStartMFC3gtk7Builder7BuilderC7gobject7ObjectG7ObjectGAyaJS4gtkc9glibtypes13GMarkupParserJPvZb': Entry.d:(.text+0x1d40): multiple definition of `_D3gtk6Widget6Widget10__mixin56514customTagStartMFC3gtk7Builder7BuilderC7gobject7ObjectG7ObjectGAyaJS4gtkc9glibtypes13GMarkupParserJPvZb' ./libgtkd-3.a(Layout.o):Layout.d:(.text+0x60): first defined here ./libgtkd-3.a(Entry.o): In function `_DT1584_D3gtk6Widget6Widget10__mixin56514customTagStartMFC3gtk7Builder7BuilderC7gobject7ObjectG7ObjectGAyaJS4gtkc9glibtypes13GMarkupParserJPvZb': Entry.d:(.text+0x1e30): multiple definition of `_DT1584_D3gtk6Widget6Widget10__mixin56514customTagStartMFC3gtk7Builder7BuilderC7gobject7ObjectG7ObjectGAyaJS4gtkc9glibtypes13GMarkupParserJPvZb' ./libgtkd-3.a(Layout.o):Layout.d:(.text+0x150): first defined here ./libgtkd-3.a(Entry.o): In function `_D3gtk6Widget6Widget10__mixin56516buildableSetNameMFAyaZv': Entry.d:(.text+0x1ed0): multiple definition of `_D3gtk6Widget6Widget10__mixin56516buildableSetNameMFAyaZv' ./libgtkd-3.a(Layout.o):Layout.d:(.text+0x160): first defined here ./libgtkd-3.a(Entry.o): In function `_DT1584_D3gtk6Widget6Widget10__mixin56516buildableSetNameMFAyaZv': Entry.d:(.text+0x1f30): multiple definition of `_DT1584_D3gtk6Widget6Widget10__mixin56516buildableSetNameMFAyaZv' ./libgtkd-3.a(Layout.o):Layout.d:(.text+0x1c0): first defined here [...] And so on. When looking at the contents of object files, indeed, Entry.o and Layout.o are both defining symbols belonging to "gtk.Widget" module namespace: $ nm src/gtk/Entry.o | ddemangle | grep 'refAccessible()' -C 1 U bool gtk.Widget.Widget.isToplevel() 0000000000002920 T atk.ObjectAtk.ObjectAtk gtk.Widget.Widget.__mixin564.refAccessible() 0000000000000025 t atk.ObjectAtk.ObjectAtk gtk.Widget.Widget.__mixin564.refAccessible().part.75 00000000000028e0 T gtkc.atktypes.AtkImplementor* gtk.Widget.Widget.__mixin564.getImplementorStruct() $ nm src/gtk/Widget.o | ddemangle | grep 'refAccessible()' -C 1 0000000000000000 t bool gtk.Widget.Widget.isToplevel().part.138 000000000000eb40 T atk.ObjectAtk.ObjectAtk gtk.Widget.Widget.__mixin564.refAccessible() 0000000000000000 t atk.ObjectAtk.ObjectAtk gtk.Widget.Widget.__mixin564.refAccessible().part.363 000000000000bc90 T gtkc.atktypes.AtkImplementor* gtk.Widget.Widget.__mixin564.getImplementorStruct() This seems related to template mixins.
I've tracked this down: widget.d -------------------------------------- interface ImplementorIF { void* getImplementorStruct(); void* getStruct(); } template ImplementorT() { void* getImplementorStruct() { return null; } } class Widget : ImplementorIF { mixin ImplementorT; void* getStruct() { return null; } } -------------------------------------- range.d -------------------------------------- import Widget; class Range : Widget { void* getStruct() { return null; } } void main() {} -------------------------------------- gdc range.d widget.d The problem is our thunk emission. We call toObjfile in FuncDeclaration::toThunkSymbol, DMD does not. This code was initially added in cbd6d919559697bba6bb210acc2761ae43dbaf8a to fix issue 27. Back then we had a output_declaration_p check in toObjfile that prevented emitting getImplementorStruct. 9766ddee234a3db05b24d071bd15987373d962f5 changed the output_declaration_p check into a simple gcc_attribute_p(this) check which caused this regression. I wonder how dmd handles issue 27 without calling toObjfile and whether we should do the same thing. If we have to keep calling toObjfile I think we need to re-add this code to toObjfile: -------------------------------------- FuncDeclaration *fd = dsym->isFuncDeclaration(); if (fd != NULL) { for (FuncDeclaration *fdp = fd; fdp != NULL;) { if (!fdp->isInstantiated() && fdp->inNonRoot()) return false; if (!fdp->isNested()) break; fdp = fdp->toParent2()->isFuncDeclaration(); } } if (!flag_emit_templates) return !D_DECL_IS_TEMPLATE (dsym->toSymbol()->Stree); -------------------------------------- What do you think, Iain?
https://github.com/D-Programming-GDC/GDC/pull/245
https://github.com/D-Programming-GDC/GDC/commit/ef3141dcf92fc10e5f18eceff9207e39b75035b6