Home > Net >  PyInit already defined - PyBind
PyInit already defined - PyBind

Time:10-11

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:

#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

CodePudding user response:

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.

  • Related