Search code examples
c++dstatic-linkingdub

Use dub to output C++ linkable static library


I want to statically link my D library (which uses dub) with my C++ app.

I've followed the instructions on the wiki to successfully manually link the example.

But, I have my own library that uses dub, and I can't figure out how to make it output something I link to using cl.


Let me show you what I mean (example code from the wiki, but with dub added):

Project directory:

E:\Projects\foo
│   main.c
│
└───libadd
    │   dub.json
    │   libadd.lib
    │
    └───source
            main.d

main.c:

#include <stdio.h>

// Defined in dlib.d
int add(int, int);

int main(int argc, char ** argv) {
    int result = add(40, 2);
    printf("The result is: %i\n", result);

    return 0;
}

libadd/dub.json:

{
    "name": "libadd",
    "targetType": "staticLibrary",
    "mainSourceFile": "libadd.d",
    "buildOptions": [
        "verbose"
    ]
}

libadd/source/libadd.d:

module libadd;

extern (C) int add(int a, int b) {
    return a + b;
}

// Only needed on Linux.
extern (C) void _d_dso_registry() {}

Compiling and linking using instructions from the wiki works fine:

e:\Projects\foo> dmd -c -v -m32mscoff -betterC libadd/source/libadd.d
binary    C:\opt\D\dmd2\windows\bin\dmd.exe
version   v2.071.1
config    C:\opt\D\dmd2\windows\bin\sc.ini
parse     libadd
importall libadd
import    object        (C:\opt\D\dmd2\windows\bin\..\..\src\druntime\import\object.d)
semantic  libadd
semantic2 libadd
semantic3 libadd
code      libadd
function  libadd.add
function  libadd._d_dso_registry

e:\Projects\foo> cl /nologo /Fefoo.exe main.c libadd.obj
main.c

e:\Projects\foo> foo.exe
The result is: 42

But how do I do this with dub? I noticed that while manual compiling with dmd produces an .obj, dub produces an .lib. According to professor Google, .lib is a static library on Windows, but I can't link to it. I already set targetType to staticLibrary in dub.json.

I also noticed that the dmd flags -m32mscoff and -betterC have no corresponding buildOptions setting in dub.json. I'm not sure how to compensate, though.

e:\Projects\foo> cd libadd

e:\Projects\foo\libadd> dub
Performing "debug" build using dmd for x86.
libadd ~master: building configuration "library"...
binary    C:\opt\D\dmd2\windows\bin\dmd.exe
version   v2.071.1
config    C:\opt\D\dmd2\windows\bin\sc.ini
parse     libadd
importall libadd
import    object        (C:\opt\D\dmd2\windows\bin\..\..\src\druntime\import\object.d)
semantic  libadd
semantic2 libadd
semantic3 libadd
code      libadd
function  libadd.add
function  libadd._d_dso_registry
library   .dub\build\library-debug-windows-x86-dmd_2071-2DA862E35C1BEDC80780CBC1AB5F7478\libadd.lib
Target is a library. Skipping execution.

e:\Projects\foo\libadd> cd ..

e:\Projects\foo> cl /nologo /Fefoo.exe main.c libadd/libadd.lib
main.c
libadd/libadd.lib : fatal error LNK1136: invalid or corrupt file

How do I statically link my D library that uses dub, with a C++ app?


Solution

  • After some trouble I figured it out.

    It turns out, -m32mscoff is important, and it's required for 32-bit. Compiling and linking for 64-bit works fine as-is.

    Add into dub.json:

    "dflags-windows-x86-dmd": [
        "-m32mscoff"
    ]
    

    Even though dub passes -m32 to dmd, it's -m32mscoff that's needed. You can now link with cl as normal.