Thread overview
What is this undefined reference with -betterC about?
Jun 16, 2021
jfondren
Jun 16, 2021
jfondren
Jun 16, 2021
Dennis
Jun 16, 2021
Dennis
Jun 16, 2021
jfondren
June 16, 2021

Here's a complete script that you can run right now, using
a dub module that I just updated:

#!/usr/bin/env dub
/+ dub.sdl:
    dependency "hostname" version="~>0.1.1"
    buildOptions "betterC"
+/

extern(C) void main() {
    import hostname : hostnamez;
    import core.stdc.stdio : printf;

    printf("hostname: %s", hostnamez);
}

... which fails:

/usr/bin/ld: /tmp/.dub/build/hostnameex2-~master/application-debug-linux.posix-x86_64-dmd_v2.097.0-96F370DD71342805A23ECDFD2C6CCE6C/hostnameex2.o: in function `main':
/home/jfondren/mars/learn/./hostnameex2.d:11: undefined reference to `_D8hostname9hostnamezPa'

I've rm -rf'd /tmp/.dub and ~/.dub/packages , I've gotten things to a point
where I could modify dub's cached hostname/source.d and confirm that e.g.
pragma(msg, hostnamez.mangleof) has exactly the same output in that file
as in the script above. This all works fine if instead of a dub dependency
I add the path to hostname.d in dflags.

And this script works fine, without betterC:

#!/usr/bin/env dub
/+ dub.sdl:
    dependency "hostname" version="~>0.1.1"
+/

void main() {
    import std.stdio : writeln;
    import hostname : hostname, hostnamez;
    import std.string : fromStringz;

    writeln("hostname: ", hostname);
    writeln("hostname: ", hostnamez.fromStringz);
}

Why isn't this linking?

June 16, 2021

On Wednesday, 16 June 2021 at 14:21:40 UTC, jfondren wrote:

>

Why isn't this linking?

OK, with verbose commands I see that libhostname.a is built without -betterC

So that's why this fails to link.

What do I change to

  1. a script like this that uses hostname
  2. the hostname module

so that both can be built with -betterC when and only when
the script is using -betterC?

June 16, 2021

On Wednesday, 16 June 2021 at 14:38:10 UTC, jfondren wrote:

>

What do I change to

  1. a script like this that uses hostname
  2. the hostname module

so that both can be built with -betterC when and only when
the script is using -betterC?

That's currently the situation: you can only build when both are betterC or else you get a linker error. It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa.

It noticed your code looks like this:

version(D_BetterC) {
    char* hostnamez;
} else {
    immutable char* hostnamez;
}

The different types result in different mangles, causing the linking errors. Why not simply give them the same type?

June 16, 2021

On Wednesday, 16 June 2021 at 16:27:13 UTC, Dennis wrote:

>

It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa.

Well I suppose you could use a specific dub configuration, maybe giving 'hostname' a targetType "sourceLibrary" or something, but I would just make the abi consistent.

June 16, 2021

On Wednesday, 16 June 2021 at 16:27:13 UTC, Dennis wrote:

>

On Wednesday, 16 June 2021 at 14:38:10 UTC, jfondren wrote:

>

What do I change to

  1. a script like this that uses hostname
  2. the hostname module

so that both can be built with -betterC when and only when
the script is using -betterC?

That's currently the situation: you can only build when both are betterC or else you get a linker error. It has to be a linker error, dmd cannot know at the time of compiling project A how project B is going to be compiled and vice versa.

It's dub that's calling dmd though. Cargo handles this situation with
features: https://doc.rust-lang.org/cargo/reference/features.html Where
this case would look something like

[dependencies]
hostname = { version = "0.1.1", features = ["betterC"] }

in the script's dub config that uses hostname.

I feel like I've seen similar configurations in dub configs, but I see
nothing about this in the documentation.

>

It noticed your code looks like this:

version(D_BetterC) {
    char* hostnamez;
} else {
    immutable char* hostnamez;
}

The different types result in different mangles, causing the linking errors. Why not simply give them the same type?

the pragma(crt_constructor) function can't initialize immutables:
https://forum.dlang.org/post/wvjfygxfvmoaortmndcv@forum.dlang.org