Thread overview
dmd -unittest -main -run: undefined reference to `_D1c12__ModuleInfoZ'
May 01, 2019
kdevel
May 01, 2019
ag0aep6g
May 01, 2019
kdevel
May 01, 2019
Seb
May 01, 2019
kdevel
May 02, 2019
ag0aep6g
May 01, 2019
In the current working directory b/ I have

package.d
```
module b;
import c;

void bar (string s)
{
   mkdir (s);
}
```

c/package.d
```
module c;
package import std.file;
```

   $ dmd -unittest -main package.d c/package.d

produces the binary "package" as expected, but

   $ dmd -unittest -main -run package.d c/package.d

fails with

   package.o:(.data.rel.ro+0x10): undefined reference to `_D1c12__ModuleInfoZ'
   collect2: ld returned 1 exit status
   Error: linker exited with status 1

Why this?
May 02, 2019
On 02.05.19 00:25, kdevel wrote:
> dmd -unittest -main -run package.d c/package.d

That doesn't compile c/package.d. Everything after `-run package.d` is interpreted as an argument to the compiled program.

I.e., that line effectively does this:

    dmd -unittest -main package.d
    ./package c/package.d

You need to put c/package.d before -run:

    dmd -unittest -main c/package.d -run package.d

Or use -i so that DMD compiles the imported module automatically:

    dmd -unittest -main -i -run package.d
May 01, 2019
On Wednesday, 1 May 2019 at 22:35:12 UTC, ag0aep6g wrote:
> On 02.05.19 00:25, kdevel wrote:
>> dmd -unittest -main -run package.d c/package.d
>
> That doesn't compile c/package.d. Everything after `-run package.d` is interpreted as an argument to the compiled program.

Thanks for the information. Wouldn't it be better, if everything directly
after the `-run` would be taken as argument to the programm? In this case

   dmd -unittest -main -run package.d

would immediately fail due to missing source.

[...]
>
> Or use -i so that DMD compiles the imported module automatically:
>
>     dmd -unittest -main -i -run package.d

That looks nice.
May 01, 2019
On Wednesday, 1 May 2019 at 22:35:12 UTC, ag0aep6g wrote:
[...]
> Or use -i so that DMD compiles the imported module automatically:
>
>     dmd -unittest -main -i -run package.d

Now I have:

a/main.d
a/b/package.d
a/b/c/package.d

b/package.d and c/package.d as before. a/main.d is

```
import b;

void dummy ()
{
   string s = "test";
   mkdir (s);
}
```

In cwd a/ with

   $ dmd -unittest -main -i -run main.d

I get

   b/package.d(2): Error: module `c` is in file 'c.d' which cannot be read
   import path[0] = /.../dmd2/linux/bin64/../../src/phobos
   import path[1] = /.../dmd2/linux/bin64/../../src/druntime/import

Why does dmd not get it? I have to supply -I=b explicitly. Which leads me to
the actual problem I wanted to post:

   $ dmd -unittest -main -I=b -run main.d
   main.d(6): Error: undefined identifier mkdir

The problem I see here is that b passes the isolated unittest. But when it is used undefined symbols show up. I stumbled over this problem while using a project as submodule which uses msgpack-d as its submodule. Only if I restrict
the import like in

   import msgpack : unpack, pack;

my submodule's unittest fails right away. My submodule corresponds to b/package.d in this thread. I suppose the line

    package import std.file, core.stdc.string;

in msgpack-d's file packer.d causes the export of mkdir. Right?
May 01, 2019
On Wednesday, 1 May 2019 at 22:46:34 UTC, kdevel wrote:
> On Wednesday, 1 May 2019 at 22:35:12 UTC, ag0aep6g wrote:
>> On 02.05.19 00:25, kdevel wrote:
>>> dmd -unittest -main -run package.d c/package.d
>>
>> That doesn't compile c/package.d. Everything after `-run package.d` is interpreted as an argument to the compiled program.
>
> Thanks for the information. Wouldn't it be better, if everything directly
> after the `-run` would be taken as argument to the programm? In this case
>
>    dmd -unittest -main -run package.d
>
> would immediately fail due to missing source.

Would be, but would also be a breaking change.
In the past it has been discussed to use e.g. `--` as a separator, but that PR was rejected because it could only be done in a useful way with breaking changes :/
May 02, 2019
On 02.05.19 01:18, kdevel wrote:
> Now I have:
> 
> a/main.d
> a/b/package.d
> a/b/c/package.d
> 
> b/package.d and c/package.d as before.

For reference, a/b/c/package.d is this:

    module c; package import std.file;

And a/b/package.d starts with:

   module b; import c;

> a/main.d is
> 
> ```
> import b;
> 
> void dummy ()
> {
>     string s = "test";
>     mkdir (s);
> }
> ```
> 
> In cwd a/ with
> 
>     $ dmd -unittest -main -i -run main.d
> 
> I get
> 
>     b/package.d(2): Error: module `c` is in file 'c.d' which cannot be read
>     import path[0] = /.../dmd2/linux/bin64/../../src/phobos
>     import path[1] = /.../dmd2/linux/bin64/../../src/druntime/import
> 
> Why does dmd not get it?

If you want c to be part of the package b, you have to state that in the module declaration and when importing it.

In c/package.d:

    module b.c;

In b/package.d:

    import b.c;

Module declarations and imports are always absolute. They're not relative to the current package. If you add a new root directory on top, you have to adjust those declarations in all files.

> I have to supply -I=b explicitly. Which leads me to
> the actual problem I wanted to post:
> 
>     $ dmd -unittest -main -I=b -run main.d
>     main.d(6): Error: undefined identifier mkdir

main only imports b. And b doesn't expose mkdir.

You can either import c (or rather b.c) in main, or make b's import of c public.

By the way, `package import` seems to work just like `public import`, not restricting anything. Looks like a compiler bug.

> The problem I see here is that b passes the isolated unittest. But when it is used undefined symbols show up. I stumbled over this problem while using a project as submodule which uses msgpack-d as its submodule. Only if I restrict
> the import like in
> 
>     import msgpack : unpack, pack;
> 
> my submodule's unittest fails right away. My submodule corresponds to b/package.d in this thread. I suppose the line
> 
>      package import std.file, core.stdc.string;
> 
> in msgpack-d's file packer.d causes the export of mkdir. Right?

"Export" in the sense of D identifier visibility, yes.

Note that an "undefined identifier" error is different from one about an "undefined reference". The former is the compiler saying it can't find the definition of a D identifier. The latter is the linker saying it can't find a symbol in the object files.