This is a variation of the "template library bug," similar to why std.boxer is incompatible with debug user apps. Support for in/out contracts seems to be fixed, as they always seem to be generated within the template function body, but it appears that array bounds and assertion checks are still sometimes expected to exist in the object containing the declaration of the template code. Here is an example:
module a;
template ElemTypeOf( T )
{
alias typeof(T[0]) ElemTypeOf;
}
template removeIf_( Elem, Pred )
{
size_t fn( Elem[] buf, Pred pred )
{
void exch( size_t p1, size_t p2 )
{
Elem t = buf[p1];
buf[p1] = buf[p2];
buf[p2] = t;
}
size_t cnt = 0;
for( size_t pos = 0, len = buf.length; pos < len; ++pos )
{
if( pred( buf[pos] ) )
++cnt;
else
exch( pos, pos - cnt );
}
return buf.length - cnt;
}
}
template removeIf( Buf, Pred )
{
size_t removeIf( Buf buf, Pred pred )
{
return removeIf_!(ElemTypeOf!(Buf), Pred).fn( buf, pred );
}
}
----------
import a;
void main()
{
auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } );
}
C:\code\src\d\test>dmd b
c:\bin\dmd\bin\..\..\dm\bin\link.exe b,,,user32+kernel32/noi;
OPTLINK (R) for Win32 Release 7.50B1
Copyright (C) Digital Mars 1989 - 2001 All Rights Reserved
b.obj(b)
Error 42: Symbol Undefined _D1a7__arrayZ
--- errorlevel 1
It appears that whether this error occurs may somehow be related to the inlining mechanism, because I have some template functions that exhibit this behavior and others that do not. This bug is a major obstacle to building libraries containing template code in D, particularly when the user cannot manually link a debug library because the library name is selected automatically (as with phobos.lib). Also, I don't entirely understand why a separate bound-check and assert function must apparently be generated for every module, since the contents should be immutable. The easiest fix for std.boxer (if perhaps not user libraries) would be to link separate standard libraries for debug and release builds--phobos.lib vs. phobosd.lib, for example. But it would be far preferable if code generation could be fixed such that this problem no longer occurs.
Comment #1 by sean — 2007-01-23T13:09:49Z
This is related to issue 8.
Comment #2 by bugzilla — 2007-01-31T03:41:45Z
The problem is that the __array() function is not generated for module a if it is compiled with -release. I'll fix it so it does, but to get the example to work, you'll still need to link with a.obj.
Comment #3 by sean — 2007-01-31T11:50:29Z
[email protected] wrote:
>
> The problem is that the __array() function is not generated for module a if it
> is compiled with -release. I'll fix it so it does, but to get the example to
> work, you'll still need to link with a.obj.
That's fine. My only concern is that template code in release libraries
be usable in debug applications (since non-template code is). The only
remaining issues seem to be _array() and _assert() (and possibly not
_assert()--I haven't found a case where this breaks yet), and always
building it/them into the module should address this.
Comment #4 by bugzilla — 2007-02-12T03:39:18Z
Fixed DMD 1.005
Comment #5 by ultimate.macfan.atic — 2008-11-03T04:40:46Z
I'm getting linking errors when I compile and link a module I wrote using dmd that sound similar to what's described here. I've looked for other documentation of this issue, but I haven't found any so I'm going to go ahead and post this as a bug to see if anyone else can replicate it, even though this problem appears to have been fixed the last time it was rearing its (insert creative adjective here) head.
The error output:
C:\Documents and Settings\Christopher Johnson\My Documents>dmd -v edu\utah\eng\chjohnso\boggle.d
parse boggle
semantic boggle
import object (\dmd\src\phobos\object.d)
import std.c.stdlib (\dmd\src\phobos\std\c\stdlib.d)
import std.c.stddef (\dmd\src\phobos\std\c\stddef.d)
import std.ctype (\dmd\src\phobos\std\ctype.d)
import edu.utah.eng.chjohnso.set (edu\utah\eng\chjohnso\set.d)
import std.stdio (\dmd\src\phobos\std\stdio.d)
import std.c.stdio (\dmd\src\phobos\std\c\stdio.d)
import std.c.stdarg (\dmd\src\phobos\std\c\stdarg.d)
import std.format (\dmd\src\phobos\std\format.d)
import std.stdarg (\dmd\src\phobos\std\stdarg.d)
import std.utf (\dmd\src\phobos\std\utf.d)
import std.contracts (\dmd\src\phobos\std\contracts.d)
import std.conv (\dmd\src\phobos\std\conv.d)
import std.string (\dmd\src\phobos\std\string.d)
import std.algorithm (\dmd\src\phobos\std\algorithm.d)
import std.math (\dmd\src\phobos\std\math.d)
import std.c.math (\dmd\src\phobos\std\c\math.d)
import std.traits (\dmd\src\phobos\std\traits.d)
import std.typetuple (\dmd\src\phobos\std\typetuple.d)
import std.date (\dmd\src\phobos\std\date.d)
import std.dateparse (\dmd\src\phobos\std\dateparse.d)
import std.c.windows.windows (\dmd\src\phobos\std\c\windows\windows.d)
import std.functional (\dmd\src\phobos\std\functional.d)
import std.typecons (\dmd\src\phobos\std\typecons.d)
import std.metastrings (\dmd\src\phobos\std\metastrings.d)
import std.iterator (\dmd\src\phobos\std\iterator.d)
import std.c.string (\dmd\src\phobos\std\c\string.d)
import std.encoding (\dmd\src\phobos\std\encoding.d)
import std.uni (\dmd\src\phobos\std\uni.d)
import std.array (\dmd\src\phobos\std\array.d)
import std.system (\dmd\src\phobos\std\system.d)
import std.bitmanip (\dmd\src\phobos\std\bitmanip.d)
import std.intrinsic (\dmd\src\phobos\std\intrinsic.d)
import std.gc (\dmd\src\phobos\std\gc.d)
import gcstats (\dmd\src\phobos\gcstats.d)
import std.file (\dmd\src\phobos\std\file.d)
import std.path (\dmd\src\phobos\std\path.d)
import std.regexp (\dmd\src\phobos\std\regexp.d)
import std.outbuffer (\dmd\src\phobos\std\outbuffer.d)
import std.windows.syserror (\dmd\src\phobos\std\windows\syserror.d)
import std.windows.charset (\dmd\src\phobos\std\windows\charset.d)
semantic2 boggle
semantic3 boggle
code boggle
function this
function chooseChar
function randomize
function getFace
function playWord
function getScore
function __foreachbody21
function _makeSetConditionary
function __foreachbody22
function allLegalWordsPlayed
function __dgliteral1
function allSharedLegalWordsPlayed
function __dgliteral2
function allIllegalWordsPlayed
function __dgliteral3
function scoreByLength
function isLegal
function verify
function this
function empty
function length
function insert
function erase
function clear
function swap
function opIn_r
function opApply
function main
\dm\bin\link.exe boggle,,,user32+kernel32/noi;
OPTLINK (R) for Win32 Release 8.00.1
Copyright (C) Digital Mars 1989-2004 All rights reserved.
boggle.obj(boggle)
Error 42: Symbol Undefined _D3edu4utah3eng8chjohnso3set7__arrayZ
--- errorlevel 1
This link failure persists when I add the "-debug" switch, but goes away if I add the "-release" switch. So thankfully in the meantime there is some kind of work-around so I can at least get my code to *run*, but not being able to compile with -debug or without the extra baggage of -release sounds like it's an issue that could use some improvement both for saving keystrokes at the command-line as well as for optimal debugging.
Hope I'm doing this in proper procedure! :-)
Should my email not make it into this otherwise, it's [email protected] (and your Mac Fanatic only compiles D on windows because he can't get any D 2.0 compilers for his Mac OS X 10.5 :-P).
Comment #6 by bus_dbugzilla — 2012-01-16T18:42:58Z
This painful issue still exists in 2.057. Here's a simpler testcase for linux (tested on 32bit):
testa.d:
----------------------------
import testb;
void main()
{
string output;
bar!(output)();
}
----------------------------
testb.d
----------------------------
struct Foo(alias al)
{
int[] var;
int func()
{
return var[0];
}
}
void bar(alias al)()
{
auto foo = Foo!(al)();
}
----------------------------
$dmd testa.d testb.d
testa.o: In function `_D5testa4mainFZv37__T3FooS26_D5testa4mainFZv6outputAyaZ3Foo4funcMFZi':
testb.d:(.text._D5testa4mainFZv37__T3FooS26_D5testa4mainFZv6outputAyaZ3Foo4funcMFZi+0x3c): undefined reference to `_D5testa7__arrayZ'
collect2: ld returned 1 exit status
--- errorlevel 1
The bug goes away if you compile with "-release", or (interestingly) if you compile separately and then link.
The testcase above doesn't trigger the bug on Windows, but the problem *does* exist on Windows too (I just don't have a reduced Windows test case right now).
Comment #7 by bus_dbugzilla — 2012-01-16T18:55:12Z
Increasing severity since there's no clear workaround for non-release builds.
Comment #8 by kekeniro2 — 2012-02-20T21:18:43Z
(In reply to comment #6)
> $dmd testa.d testb.d
I reproduced it in Windows, with -g option.
dmd -g testa.d testb.d
and this works. ( b,a )
dmd -g testb.d testa.d
Comment #9 by github-bugzilla — 2014-05-17T16:17:51Z
(In reply to Walter Bright from comment #11)
> Different fix: https://github.com/D-Programming-Language/dmd/pull/4859
This fix also means that one will have to link with an import's object file if there are references to the helper functions. The fix always generates the helper functions for a module, regardless of the compiler switch settings.