www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Linker error regarding importing and unit tests. Is this a bug?

reply "Gary Willoughby" <dev nomad.so> writes:
I have a small test case that displays a linker error. I wondered 
if this is an issue with the tool chain or whether i'm doing 
something wrong.

I have a simple directory structure like this:

test/methods.d
test/test1.d
test/test2.d

Here is the source code for the above modules:

methods.d:

	module test.methods;

	import std.array;

	public bool nothing(int[] x)
	{
		return x.empty();
	}

test1.d:

	module test.test1;

	struct S
	{
		int x[];
	}

	unittest
	{
		import test.methods;
		import std.stdio;

		writeln("test1 unit test");

		S s;

		assert(s.x.nothing());
	}

test2.d:

	module test.test2;

	import test.test1;

	struct T
	{
		int x[];
	}

I compile the following sources like this:

	rdmd --force -de -debug -I~/Desktop -m64 -main -property 
-unittest -w <file>

Where <file> is an individual file above. I do this because i 
like to compile and tests each module in isolation running the 
unit tests. When i try and compile `test2.d` i get the following 
error:

Undefined symbols for architecture x86_64:
   "_D4test7methods12__ModuleInfoZ", referenced from:
       _D4test5test112__ModuleInfoZ in test2.o
   "_D4test7methods7nothingFAiZb", referenced from:
       _D4test5test114__unittestL8_1FZv in test2.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to 
see invocation)

If i add the following to the bottom of `test2.d` it all compiles 
fine:

	unittest
	{
		import test.methods;
	}

Any idea what's going on here?
Nov 01 2013
parent reply "Daniel Davidson" <nospam spam.com> writes:
On Friday, 1 November 2013 at 12:59:24 UTC, Gary Willoughby wrote:
 I have a small test case that displays a linker error. I 
 wondered if this is an issue with the tool chain or whether i'm 
 doing something wrong.

 I have a simple directory structure like this:

 test/methods.d
 test/test1.d
 test/test2.d

 Here is the source code for the above modules:

 methods.d:

 	module test.methods;

 	import std.array;

 	public bool nothing(int[] x)
 	{
 		return x.empty();
 	}

 test1.d:

 	module test.test1;

 	struct S
 	{
 		int x[];
 	}

 	unittest
 	{
 		import test.methods;
 		import std.stdio;

 		writeln("test1 unit test");

 		S s;

 		assert(s.x.nothing());
 	}

 test2.d:

 	module test.test2;

 	import test.test1;

 	struct T
 	{
 		int x[];
 	}

 I compile the following sources like this:

 	rdmd --force -de -debug -I~/Desktop -m64 -main -property 
 -unittest -w <file>

 Where <file> is an individual file above. I do this because i 
 like to compile and tests each module in isolation running the 
 unit tests. When i try and compile `test2.d` i get the 
 following error:

 Undefined symbols for architecture x86_64:
   "_D4test7methods12__ModuleInfoZ", referenced from:
       _D4test5test112__ModuleInfoZ in test2.o
   "_D4test7methods7nothingFAiZb", referenced from:
       _D4test5test114__unittestL8_1FZv in test2.o
 ld: symbol(s) not found for architecture x86_64
 clang: error: linker command failed with exit code 1 (use -v to 
 see invocation)

 If i add the following to the bottom of `test2.d` it all 
 compiles fine:

 	unittest
 	{
 		import test.methods;
 	}

 Any idea what's going on here?
An alternative is to move the import statements in test1.d out of the unittest block, which becomes a function, to file scope. Then if you have multiple unittests in test1.d all are covered and the symbols are available. ... version(unittest) { import methods; } unittest { import std.stdio; writeln("test1 unit test"); S s; assert(s.x.nothing()); } Thanks Dan
Nov 01 2013
parent reply "Gary Willoughby" <dev nomad.so> writes:
On Friday, 1 November 2013 at 15:32:54 UTC, Daniel Davidson wrote:
 An alternative is to move the import statements in test1.d out 
 of the unittest block, which becomes a function, to file scope. 
 Then if you have multiple unittests in test1.d all are covered 
 and the symbols are available.

 ...
 version(unittest) {
   import methods;
 }
 unittest
 {
   import std.stdio;
   writeln("test1 unit test");
   S s;
   assert(s.x.nothing());
 }

 Thanks
 Dan
Ah right, if the unit tests are transformed into a function then is this a problem with the scoped import rules? It seems really odd, as the compiler seems to strip out the imports within the unit test block when that module is imported into another. This doesn't seem to affect the standard library only user modules.
Nov 01 2013
parent reply "Gary Willoughby" <dev nomad.so> writes:
On Friday, 1 November 2013 at 16:24:09 UTC, Gary Willoughby wrote:
 On Friday, 1 November 2013 at 15:32:54 UTC, Daniel Davidson 
 wrote:
 An alternative is to move the import statements in test1.d out 
 of the unittest block, which becomes a function, to file 
 scope. Then if you have multiple unittests in test1.d all are 
 covered and the symbols are available.

 ...
 version(unittest) {
  import methods;
 }
 unittest
 {
  import std.stdio;
  writeln("test1 unit test");
  S s;
  assert(s.x.nothing());
 }

 Thanks
 Dan
Ah right, if the unit tests are transformed into a function then is this a problem with the scoped import rules? It seems really odd, as the compiler seems to strip out the imports within the unit test block when that module is imported into another. This doesn't seem to affect the standard library only user modules.
Any one else got any input to this?
Nov 03 2013
parent "Gary Willoughby" <dev nomad.so> writes:
Raised as a bug: 
http://d.puremagic.com/issues/show_bug.cgi?id=11439
Nov 04 2013