Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

PyInit already defined – PyBind

I want to build a module for python, and it compiled fine when I had 1 header, 1 cpp file, but I wanted to extend it to 1 header, 2 cpp files, and now I get errors I don’t really understand.

My Header (fast_qs_module.h):

#ifndef FASTCOSINE_MODULE_INCLUDE_H
#define FASTCOSINE_MODULE_INCLUDE_H

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <Python.h>
#include <vector>

std::vector<double> get_dwds_distances(std::vector<std::vector<double>> unlabeled, std::vector<std::vector<double>> labeled, double alpha);
std::vector<double> get_euclidian_distances_to_reference(std::vector<std::vector<double>> unlabeled, std::vector<double> reference);

PYBIND11_MODULE(fast_cosine, mod) {
    mod.def("get_dwds_distances", &get_dwds_distances, "Multithreaded DWDS calculations to get the values for each unlabeled sample.");
    mod.def("get_euclidian_distances", &get_euclidian_distances_to_reference, "Multithreaded Euclidian distance calculations to get the values for each unlabeled sample.");
}

#endif  // FASTCOSINE_MODULE_INCLUDE_H

One cpp file:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

#include [...]

#include "fast_qs_module.h"

class EuclidianClass
{
    [...]
};

std::vector<double> get_euclidian_distances_to_reference(std::vector<std::vector<double>> unlabeled, std::vector<double> reference)
{
    EuclidianClass runner(unlabeled, reference);
    return runner.get_euclidian_result();
}

The other cpp file:

#include [...]

#include "fast_qs_module.h"

class CosineClass
{
     [...]
};

std::vector<double> get_dwds_distances(std::vector<std::vector<double>> unlabeled, std::vector<std::vector<double>> labeled, double alpha)
{
    CosineClass runner(unlabeled, labeled, alpha);
    return runner.get_dwds_result();
}

When I pack it all in one cpp it works, but why doesn’t it work with two cpp files? The header is include guarded…

The error I am getting:

 compiler_compat/ld: build/temp.linux-x86_64-cpython-38/src/euclidian.o: in function `PyInit_fast_cosine':
    euclidian.cpp:(.text+0x810): multiple definition of `PyInit_fast_cosine'; build/temp.linux-x86_64-cpython-38/src/cdist_cosine.o:cdist_cosine.cpp:(.text+0xfc0): first defined here
    collect2: error: ld returned 1 exit status

As per https://pybind11.readthedocs.io/en/stable/faq.html#how-can-i-reduce-the-build-time I split it like this:

Header:

void init_dwds(py::module_ &);
void init_euclidian(py::module_ &);

PYBIND11_MODULE(fast_cosine, mod) {
    init_dwds(mod);
    init_euclidian(mod);
}

Source files:

std::vector<double> get_dwds_distances(std::vector<std::vector<double>> unlabeled, std::vector<std::vector<double>> labeled, double alpha)
{
    CosineClass runner(unlabeled, labeled, alpha);
    return runner.get_dwds_result();
}

void init_dwds(py::module_ &mod)
{
    mod.def("get_dwds_distances", &get_dwds_distances, "Multithreaded DWDS calculations to get the values for each unlabeled sample.");
}

Source 2:

std::vector<double> get_euclidian_distances_to_reference(std::vector<std::vector<double>> unlabeled, std::vector<double> reference)
{
    EuclidianClass runner(unlabeled, reference);
    return runner.get_euclidian_result();
}

void init_euclidian(py::module_ &mod)
{
    mod.def("get_euclidian_distances", &get_euclidian_distances_to_reference, "Multithreaded Euclidian distance calculations to get the values for each unlabeled sample.");
}

but I still get

euclidian.cpp:(.text+0x810): multiple definition of `PyInit_fast_cosine'; build/temp.linux-x86_64-cpython-38/src/cdist_cosine.o:cdist_cosine.cpp:(.text+0xfc0): first defined here
    collect2: error: ld returned 1 exit status

>Solution :

Include guard only protects a header to be included more than once in a single translation unit. It does not help if a header contains something that needs not be placed in the header.

In your case, it looks like PYBIND11_MODULE expands to something like a definition rather than a declaration, which should not be in a header. Placing it in a cpp should solve.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading