Jason_optControlnerd
Jason_optControlnerd

Reputation: 43

Using automatic conversion in Pybind11

I'm trying to take advantage of some C++ functions by calling them from Python. To do that, I was trying to construct a small demo function to show myself how python types are converted to C++ types. According to the Pybind11 documentation, if you include pybind11/stl.h in your header, automatic conversion should take place for many common types:

https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html

What is wrong with the following code?

my.cpp

#include <vector>
int add_these(std::vector<int> &v) {
    int sum=0;
    for (int i = 0; i < v.size(); ++i) {
            sum += v[i];
    }
    return sum;
    }

wrap.cpp

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include "my.cpp"
namespace py=pybind11;
PYBIND11_MODULE(python_example, m) {
    m.def("addup", &add_these);
#ifdef VERSION_INFO
    m.attr("__version__") = VERSION_INFO;
#else
    m.attr("__version__") = "dev";
#endif
}

I have successfully compiled other demos that I've built, so I don't think it's an error in my compiling process. But compiling this demo I get this error:

 wrap.cpp
    creating C:\Users\scottjr1\AppData\Local\Temp\pip-req-build-wyi5ezw1\build\lib.win-amd64-3.7
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:c:\users\scottjr1\appdata\python\python37\libs /LIBPATH:c:\users\scottjr1\appdata\python\python37\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\ATLMFC\lib\x64" "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\lib\um\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64" /EXPORT:PyInit_python_example build\temp.win-amd64-3.7\Release\src/my.obj build\temp.win-amd64-3.7\Release\src/wrap.obj /OUT:build\lib.win-amd64-3.7\python_example.cp37-win_amd64.pyd /IMPLIB:build\temp.win-amd64-3.7\Release\src\python_example.cp37-win_amd64.lib
    wrap.obj : error LNK2005: "int __cdecl add_these(class std::vector<int,class std::allocator<int> > &)" (?add_these@@YAHAEAV?$vector@HV?$allocator@H@std@@@std@@@Z) already defined in my.obj
       Creating library build\temp.win-amd64-3.7\Release\src\python_example.cp37-win_amd64.lib and object build\temp.win-amd64-3.7\Release\src\python_example.cp37-win_amd64.exp
    build\lib.win-amd64-3.7\python_example.cp37-win_amd64.pyd : fatal error LNK1169: one or more multiply defined symbols found
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Professional\\VC\\Tools\\MSVC\\14.16.27023\\bin\\HostX86\\x64\\link.exe' failed with exit status 1169

Upvotes: 3

Views: 1041

Answers (2)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

#include "my.cpp" is wrong. Replace with #include "my.h".

my.h should contain:

#include <vector>
int add_these(std::vector<int> const &v);

the declaration of your function.

and my.cpp should contain the definition:

#include "my.h"
int add_these(std::vector<int> const&v) {
  int sum=0;
  for (int i = 0; i < v.size(); ++i) {
      sum += v[i];
  }
  return sum;
}

the error you are seeing is that you have two .cpp files that contain the definition of the function; that is not allowed in C++.

#include "my.cpp" copy pastes the content of my.cpp where the include directive is. This is not the same as import in python.

This didn't occur in other cases probably because you didn't link the cpp file; regardless including cpp files breaks convention, don't do it.

Upvotes: 0

Jason_optControlnerd
Jason_optControlnerd

Reputation: 43

The problem was simple: header guards don't work on .cpp files so the solution was to break up my.cpp into my.hpp and my.cpp files and include the my.hpp file in the wrap.cpp file.

Of the few demos I've done, this was only required for this demo so far. I'm not sure why breaking up the file is necessary for this demo but not others where I've included the .cpp files directly.

Upvotes: 1

Related Questions