Search code examples
c++dld

How can I link a C++ function with const parameters, or a C++ struct to a D executable?


I'm trying to link a C++ object file to a D executable.

dlang.org suggests that this should be possible: http://dlang.org/cpp_interface.html

and indeed, creating a D-interface file for the C++ object file I wanted to link to was straight forward. The exposed part of the C++ module is just a set of global C-style functions and a few structs anyway.

What I want to do should look like:

rdmd -main -unittest -L-lcurl -Lsvm.o "-L/usr/lib/libstdc++.a" svmWrapper.d

where svm.o is the C++ object file, and svmWrapper.d is the d file that builds to an executable (in this case, just one that will run unit tests).

However, for certain (but not all) functions from the C++ object file that are called in the D file, the linker spews an undefined reference error. I suspect that these problems arise from improper declarations in the D-interface file, but am unsure where I've gone wrong.

An example is for the svm_cross_validation function. The .di file contains:

 extern(C++) void svm_cross_validation(const(svm_problem) *prob, const(svm_parameter) *param, int nr_fold, double *target);

which I believe to be equivalent to the declaration in the C++ header file:

void svm_cross_validation(const struct svm_problem *prob, const struct svm_parameter* param, int nr_fold, double *target);

but which probably isn't quite right. I think something is wrong with the consts, but am unsure what. The linker says:

undefined reference to `svm_cross_validation(svm_problem const*, svm_parameter const*, int, double*)'

I assume the other complaints come about because D wants certain type information from the structures which is not present. This is less urgent because, in the worst case, I could hide all the information about these structures within the C++ module. I cannot see why this information isn't present however. The .di file contains:

struct svm_node
{
        int index;
        double value;
}

which I believe to be equivalent to the C++ header file's

struct svm_node 
{
        int index;
        double value;
};

The linker generates a number of errors:

undefined reference to `_D3svm8svm_node6__initZ'
undefined reference to `_D3svm8svm_node11__xopEqualsFKxS3svm8svm_nodeKxS3svm8svm_nodeZb'

I've verified that these errors only arise if the svm_node type's internal variables are accessed within the D file. Merely instantiating a pointer to an svm_node does not suffice.

Anyway, I'd be much obliged to anyone who can explain where I've gone wrong here.


Solution

  • You're probably being bitten by the struct definitions not being compiled into the necessary code because your file is called svm.di rather than svm.d and you're compiling using rdmd which hides most of the details for you.

    Because you have struct declarations in the svm.di file it has to get compiled. .di files are sort of like .h files for C/C++, but slightly different. The fastest way to fix this for rdmd is to rename svm.di to svm.d and to touch *.d and then your rdmd should build properly.

    As for the missing declaration, you definitely look like you defined it correctly in the svm.di file (which you should now have renamed svm.d. You need to verify that it exists in the svm.o file that you generated from the svm.cpp file by running nm svm.o | c++filt, which should yield a like akin to (amongst others):

    0000000000000010 T svm_cross_validation(svm_problem const*, svm_parameter const*, int, double*)
    

    i.e. your .o file contains an exported definition of svm_cross_validation matching the pattern you declared in the svm.di file.

    I'd recommend renaming the resulting output from the .cpp file to something that won't have an overlap in potential naming in relation to the svm.d file

    I'd generally use a Makefile for the building because I'm mixing multiple languages and files together. I've built a very small github project showing a Makefile building the relevant code to ensure that, for example, the C++ code gets compiled when the .cpp file changes.