I'm trying to expose one of my classes to python using boost's python module. I have a class called StatusEffect that I'd like to expose to python. To do so, I'm creating this in the StatusEffect.h file after the class definition of StatusEffect
BOOST_PYTHON_MODULE(StatusEffect)
{
boost::python::class_<StatusEffect>("StatusEffect")
.def("GetPriority", &StatusEffect::GetPriority)
.def("GetDescription", &StatusEffect::GetDescription)
.def("GetName", &StatusEffect::GetName);
}
I want to use it inside python from a function declared inside a header as so:
Primaries.h
#include <boost\python.hpp>
#include <StatusEffects\StatusEffect.h>
#include "ScriptDeclarations.h";
extern void Test();
and in Primaries.cpp
#include "Primaries.h"
class StatusEffect;
using namespace boost::python;
class CppClass {
public:
int getNum() {
return 7;
}
};
BOOST_PYTHON_MODULE(CppMod) {
class_<CppClass>("CppClass")
.def("getNum",&CppClass::getNum);
}
void Test()
{
CppClass mClass;
try
{
PyImport_AppendInittab("CppMod", &initCppMod);
PyImport_AppendInittab("StatusEffect", &initStatusEffect);
Py_Initialize();
object main_module((
handle<>(borrowed(PyImport_AddModule("__main__")))));
object main_namespace = main_module.attr("__dict__");
StatusEffect effect("Haste");
main_namespace["eff"] = ptr(&effect);
handle<> ignored((PyRun_String("print eff.GetName()\n",
Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ));
/*main_namespace["CppClass"] = class_<CppClass>("CppClass")
.def("getNum",&CppClass::getNum);
main_namespace["cpp"] = ptr(&mClass);
handle<> ignored(( PyRun_String("print cpp.getNum()\n",
Py_file_input,
main_namespace.ptr(),
main_namespace.ptr() ) ));*/
}
catch( error_already_set )
{
PyErr_Print();
}
}
however, when I do this, I get the following error:
Error 16 error LNK2001: unresolved external symbol "public: class std::basic_string,class std::allocator > __thiscall StatusEffect::GetDescription(void)" (?GetDescription#StatusEffect##QAE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) C:\KHMP\Game_Cpp\KHMPCpp\KHMPCpp\GameCharacter.obj KHMPCpp
I'm quite sure this is related to my python declaration as when I remove that, and the corresponding code from Test() it compiles correctly. If I uncomment the code concerning the CppCLass in Primaries.cpp and use CppClass however, everything works fine. Do python module declarations need to be in the same source file as where they're used? If so, is there some way around that? I'd like to ultimately be able to put all the Python wrappers for my classes in a single header file.
Can anyone guide me as to what I'm doing wrong?
thanks
One thing to note is that your wrapper should be in your StatusEffect.cpp, not StatusEffect.h or a separate CPP file. However, it should be OK anyway, since everything should still get exported. I would also write a test script in Python, instead of trying to test it from C.
There is not enough information to figure out why your code is not working. Some of the things to consider:
Does GetDescription have an implementation? Is it a pure-virtual function?
Is your StatusEffect class in a different module? If it is, is it __dllexport'ed (if you're on Windows)?
The error seems to point at a problem before you get to the boost::python wrapper. Have you tried commenting out your python stuff and just trying to call StatusEffect::GetDescription directly from your test program?
Related
I am new to C++ but not to programming. I'm developing a plugin and learning the language at the same time. The plugin is for old software but still being used, so I'm using VS2015 and an SDK to match. I'm having a problem that I just don't know enough to solve but I know that it's the result of something that I'm doing wrong or don't understand. Please also consider that I'm using a third party SDK, with only .H/.HPP files and an occasional .CPP, but that's it. Everything else is wrapped in their libraries. Therefore, I don't have the liberty to change any behavior.
My code snippets are parts of their headers (can't change) and the .cpp is my modified sample code that comes along with their SDK and which I'm using as my base. It is also the area of code that causes the link error. Their samples all work, I can compile them and run them no problem. My code also works and is doing what I want. Things only break when I use my modified code. The reason I'm doing this is because I need access to the message passed into the plugin and can't find any other way to get it other than to try and override "PluginMain". The original sample code actually does call into PluginSetup.cpp because it runs other code within it as setup prior to continuing on. I've only posted the part of my code which is my attempt to override the function as I mentioned and I just included the variable declaration that causes the error. If I comment my variable declaration and other code related to it, program compiles and works again. If I move the variable declaration to another .cpp file in my codebase, code compiles no problem. It just don't like being in PluginSetup.cpp but part from maybe the main.cpp file (which I can't do anything with), PluginSetup.cpp is the first that gets called. So this is where I chose to put my override.
Am I using the friend function correctly? As you can see from the codebase, they've made the ctor as well as the friend function private.
This may also go hand in hand with a question I asked before on how to instantiate a class from this implementation using private friend function and ctors?
Hopefully, what I've posted is enough to give someone all that's needed to figure out what the problem might be.
ns1ns2Main.h
namespace ns1
{
namespace ns2
{
class Plugin;
...
}
}
extern "C" __declspec(dllexport) __MainError PluginMain(const char* caller_, const char* selector_, void* message_);
ns1ns2Plugin.h
#include "ns1ns2Main.h"
namespace ns1
{
namespace ns2
{
class Plugin
{
Public:
static Plugin* const instance();
private:
friend __MainError (::PluginMain) (const char*, const char*, void*);
Plugin();
Plugin(const Plugin&);
virtual ~Plugin();
};
}
}
PluginSetup.cpp
#include "ns1ns2Main.h"
#include "ns1ns2Plugin.h"
//-> My Modification Begins
__MainError (::PluginMain) (const char* caller, const char* selector, void* message)
{
ns1::ns2::Plugin plugin;
if (!plugin.instance())
{
plugin = ns1::ns2::Plugin();
}
if (strcmp(caller, kSPInterfaceCaller) == 0)
{
if (strcmp(selector, kSPInterfaceStartupSelector) == 0)
{
bool bStatus = ns1::ns2::pluginSetup(&plugin);
if (bStatus)
{
plugin_ = clpcsx::Plugin::instance();
plugin_->startup();
}
}
else if (strcmp(selector, kSPInterfaceShutdownSelector) == 0)
{
plugin_ = clpcsx::Plugin::instance();
plugin_->shutdown();
}
}
return error;
}
//<- My Modification Ends
namespace ns1
{
namespace ns2
{
void pluginLoaded()
{
// no-op
}
bool pluginSetup(Plugin* const plugin)
{
clpcsx::Plugin::create(plugin);
plugin->setStartupCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, startup));
plugin->setPostStartupCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, postStartup));
plugin->setPreShutdownCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, preShutdown));
plugin->setShutdownCallback(NS1_NS2_CALLBACK(clpcsx::Plugin, CLPCSX_PLUG_INST, shutdown));
return true;
}
void pluginDestroy(Plugin* const plugin)
{
clpcsx::Plugin::destroy();
}
}
}
Link Error
1>PluginSetup.obj : error LNK2019: unresolved external symbol "private: __cdecl ns1::ns2::Plugin::Plugin(void)" (??0Plugin#ns2#ns1##AEAA#XZ) referenced in function PluginMain
You have to tell the linker to include the libraries. Since this is VS you can add to the main .cpp file
#pragma comment(lib, "xxxx.lib")
where 'xxxx.lib' is the name of the library that has those ns functions. You need to make sure they are in the VS linker path too
I do not really believe that this question was never asked before, but i really tried to search without success, if you got a link to an already answered similar question, please share it.
I am porting a C++/Win32 program to C++/CLI, and, of course, I am trying to make the fewer number of modifications possible to the code in order to speed-up the re-testing phase.
I am having some trouble due to global functions having objects as parameters, here a short example:
Class header file
namespace MyNamespace {
public ref class MyClass {
public:
void test();
};
}
Class cpp file
using MyNamespace;
void myFunction(MyClass ^obj);
void MyClass::test() {
myFunction(this);
}
And here comes the problem: if I leave out myFunction from MyNamspace, it cannot use MyClass as a parameter's type. If I include myFunction in MyNamespace, every cpp file will compile correctly, but i will get a linker error "LNK2028 unresolved token".
An idea is to define a new class and include myFunction as a public static method, but to do this will be a long job, because myFunction, in the real project, is not alone... Any other idea?
If MyClass is in MyNamespace and myFunction is not, you could use MyClass with full name qualification:
void myFunction(MyNamespace::MyClass ^obj);
Of course your myFunction should be implemented somewhere.
I made some tests following Nikita's suggestion, and the final, working, code looks like this:
Class header file
namespace MyNamespace {
public ref class MyClass {
public:
void test();
};
}
Class cpp file
void myFunction(MyClass ^obj);
using MyNamespace;
void MyClass::test() {
myFunction(this);
}
Global function cpp file
using namespace MyNamespace;
void myFunction(MyClass ^obj) {
//do something
}
Using this approach in global function's cpp file is possible to use MyClass while myFunction remains (or pretend to remain) global, and MyClass::test can access myFunction even if not in the same namespace, just using a prototype declaration as in "old" c++.
I am using OOLUA 2.0.0 and am receiving the error undefined reference to OOLUA::Proxy_class<TestClass>::class_name.
The code is:
class TestClass
{
int test_member;
public:
void setTestMember(int x) { test_member = x; }
int getTestMember() { return test_member; }
};
OOLUA_PROXY(TestClass)
OOLUA_MEM_FUNC(void, setTestMember, int)
OOLUA_MEM_FUNC(int, getTestMember)
OOLUA_PROXY_END
int main()
{
OOLUA::Script script;
script.register_class<TestClass>();
OOLUA::run_chunk(script, "local n = TestClass.new() \n n:setTestMember(42) \n print(\"test_member is: \" .. n:getTestMember()");
return 0;
}
The documentation here does not appear to say anything about this error. I'm not sure what class_name even is. Any help is appreciated.
By the way, I'm using GCC 4.9.2 to compile it.
So this is late but hopefully it will help if anyone else runs across a similar issue. Basically your example is missing an important but subtle part that will help explain why you got the link errors you got.
TestClass.hpp
class TestClass
{
int test_member;
public:
void setTestMember(int x) { test_member = x; }
int getTestMember() const { return test_member; }
static void aStaticMember() { }
};
OOLUA_PROXY(TestClass)
OOLUA_MEM_FUNC(void, setTestMember, int)
OOLUA_MEM_FUNC_CONST(int, getTestMember)
OOLUA_SFUNC(aStaticMember)
OOLUA_PROXY_END
TestClass.cpp
OOLUA_EXPORT_FUNCTIONS(TestClass
,setTestMember
)
OOLUA_EXPORT_FUNCTIONS_CONST(TestClass
,getTestMember
)
You must always put a OOLUA_EXPORT_FUNCTIONS block in the associated .cpp file so that the declarations from the OOLUA_PROXY block are defined. Even if you only have const member functions, you must still place an empty block e.g. OOLUA_EXPORT_FUNCTIONS(TestClass) in the .cpp file. In the event that your class only has static functions, you would be required to use a slightly different setup.
In summary:
OOLUA_PROXY declares a proxy class
OOLUA_EXPORT_FUNCTIONS blocks define the members of that class
Also, if your class has only static member functions exposed, you will need to include a OOLUA_EXPORT_NO_FUNCTIONS(TestClass) in the .cpp file. For every static member you must then use special syntax for registering the static functions with the Script.
using namespace OOLUA; //NOLINT(build/namespaces)
Script vm;
vm.register_class_static<TestClass>("aStaticMember",
&OOLUA::Proxy_class<TestClass>::aStaticMember);
The documentation is not very helpful in this matter, but if you reveiw the associated test source files, they in combination with the documentation are enough to get past most issues.
It would be better posting questions about the library to the mailing list oolua.org/mailinglist
Have a look at the documentation for the library, specifically exporting class functions[1]. Personally I would use the minimalist DSL for your functions instead of the expressive, this would then make your proxied functions like the following (however the get should really be a constant function):
OOLUA_MFUNC(setTestMember)
OOLUA_MFUNC(getTestMember)
[1] https://docs.oolua.org/_o_o_lua_proxying.html
EDIT: I know there are similar questions, but I cannot find an answer to a following issue: Why the methods inside the class are working correctly and outside are not.
I've got a weird problem in my project which I'm developing in MSVC++ 2012. My project consists of different modules of code. The important modules from the problem's point of view is a library and the GUI. They exist as different projects in the same solution.
I have some methods in the library which are part of the classes (in this case Calibration3D):
void Calibration3D::load(const std::string &path)
I use it without problems when I need it in the GUI, however I need to use a following method (outside the class):
void xxxyyy()
But when I'm trying to use that function (outside the class but in the same namespace) I get a following error:
1>project_xml.obj : error LNK2001: unresolved external symbol "void __cdecl cci::xxxyyy(void)" (?xxxyyy#cci##YAXXZ) 1>D:\praca_pw\cci\build-msvc2012\x64\Release\\ccigui.exe : fatal error LNK1120: 1 unresolved externals
Anybody knows how to solve it?
When I have a header file like this:
namespace xyz {
void foo();
class bar { ... };
}
then I write the cpp file like this:
#include "xyz.h"
namespace xyz {
void foo() { ... }
bar::bar() { ... }
}
This means I have to type a lot less and make fewer mistakes with regard to namespaces.
OK, solved, it seems that when a method is defined inside the namespace in header file, it should also be defined explicitly as part of namespace in implementation file, in this case:
cci::xxxyyy()
{
...
}
will work and
xxxyyy()
{
...
}
will not.
Prior to refactoring my previous question, which I believe was a little bit off...
The title pretty much asks my question.
How can I keep a class definition on it's own without giving it methods & producing the error below?
The reason for this is because I want to create an object in a separate DLL (which contains the methods), but only return a reference pointer to my main program.
This is explicit exporting by the way.
Error 1 error LNK2001: unresolved external symbol "public: int
__thiscall ObjTest::getValue(void)" (?getValue#ObjTest##QAEHXZ)
class ObjTest
{
private:
int x;
public:
int getValue();
};
Since you need to load the .dll with LoadLibrary(), you can expose a pure virtual class, and have the .dll return a sub class of it:
You separate them in two files:
File ObjTest.h:
class ObjTest
{
public:
virtual int getValue() = 0;
};
ObjTest *CreateObjTest();
File ObjTest.cpp:
#include "ObjTest.h"
class ObjTestImpl : public ObjTest
{
int x;
public:
virtual int getValue();
};
int ObjTestImpl::getValue()
{
return x;
}
ObjTest *CreateObjTest()
{
return new ObjTestImpl();
}
You compile ObjTest.cpp and create a .dll out of it. Your main executable program will need to LoadLibrary() your .dll, use GetProcAddress() to extract the CreateObjTest as a function pointer and call it to return a new ObjTest .
(You might have to create a DeleteObjTest() function too - if your main executable and .dll end up with a different CRT, they'll have different heaps, so you need to call into the .dll instead of just doing delete myObj.)
The other approach is to wrap everying in a C API, and just pass opaque handles to C functions across the .dll instead of dealing with C++ objects.
You are confusing definition and implementation. You have the method defined but not implemented. Hence, the compiler compiles the code without error, as the method is defined, the linker creates an error as there is no implementation for the method (undefined symbol).
The DevStudio compiler does let you import classes from DLLs into an application:-
class __declspec (dllimport) ClassName
{
// members, etc
}
and in the DLL source, change the 'dllimport' to 'dllexport'.
See this MSDN article for more information.
If you want to hide the data members and the private methods then you'd need to look into the pimpl idiom.