November 13, 2022

Although I really don't like many things about how dub does, it brings many facilities. Imagine the following project structure:

Project A is using library B

Now, imagine that our module b has the following code:

module b;

void print(string s){imported!"std.stdio".writeln(s);}

else version(Have_A)
{
    void printA(string s){imported!"std.stdio".writeln("Printing from A!");}
}

Now, using the project A:

module a;

void main()
{
  import b;
  printA("Printing from my project");
}

Now, do try to build it.

It compiles! But then you get a linker error! Unresolved external function printA.
Now, do you understand why this just happened? If you execute dub --verbose You will be able to understand what just happened:

Build command for B: dmd b.d -lib
Build command for A: -Imodule/b -version=Have_A b.lib a.d

So: Your function printA does not get included in the process! As when the b.lib was built, there wasn't any version for doing the implementation, but when A imported B, it basically imports B as:

void print(string s);
void printA(string s);

So, it won't be actually implementing your function, it just knows about the symbol existence, so, why should you ever use Have_version?

The following code for B would have worked:

module b;
//Same thin above void print(string s)...

version(Have_A)
{
   public import a.print_a_implementation;
}

That way module a.print_a_implementation and then, you can guarantee that your code will be included (if print_a_implementation.d exists in your project)!

So, the key way to think about this is by when thinking about using version(Have_LibraryNameHere), you will need to think about a 2 compiler passes, one for implementing the functions, another for including them. If you remember that, you won't do the same mistake as me :)