从同一命名空间 [C++/pybind11] 中的 class 访问静态变量时出现 ImportError
ImportError when accessing static variables from class in same namespace [C++/pybind11]
首先,我对 C++ 编程和 pybind11 比较陌生。下面的例子应该可以解释我的问题:
a.h
:
namespace test {
class A {
public:
static int something;
};
void setSomething(int input);
}
a.cpp
:
#include <pybind11/pybind11.h>
#include "a.h"
int test::A::something;
void test::setSomething(int input) {
A::something = input;
}
PYBIND11_MODULE(a, handle) {
handle.doc() = "I'm a docstring hehe";
handle.def("setSomething", &test::setSomething);
}
b.h
:
namespace test {
class B {
public:
B();
int getSomething() const;
};
}
b.cpp
:
#include <pybind11/pybind11.h>
#include "a.h"
#include "b.h"
namespace py = pybind11;
// int test::A::something;
test::B::B(){}
int test::B::getSomething() const {
return A::something;
}
PYBIND11_MODULE(b, handle) {
handle.doc() = "I'm a docstring hehe";
py::class_<test::B>(handle, "B")
.def(py::init())
.def("getSomething", &test::B::getSomething);
}
所以我有两个 classes A 和 B,它们在 a.cpp
和 b.cpp
中定义,它们都有头文件 a.h
和 b.h
.基本上,我试图从 class A 在 class B 中访问静态变量。现在,如果我使用 CMake 编译它们并尝试 运行 一个 test.py 文件,我得到一个ImportError
告诉我 undefined symbol: _ZN4test1A9somethingE
。我希望这不是一个愚蠢的问题。提前感谢您的帮助!
编辑:如果我在 class 中定义变量,它不会获取 class 之前或之后设置的值。
想必你已经使用上面的代码构建了两个模块。 a.so
和 b.so
之类的东西,您可以使用单独的 import a
和 import b
语句将其导入 Python。
这是行不通的:您需要通过同一个二进制对象访问静态变量。即使您的链接正常工作,::test::A::something
在 a.so
和 b.so
中也会有不同的地址。 (如果您使用的是 pybind 的构建系统助手,您甚至不会注意到,因为“默认隐藏符号”会在您导入这两个模块时防止链接错误。)
您需要确保 a.cpp 和 b.cpp 链接到同一个库对象。
在 pybind 中,PYBIND11_MODULE
的第一个参数等同于您正在构建的共享对象库。如果你想像这样模块化地安排你的软件,我建议在一个单独的源文件中定义 pybind 模块,然后将模块对象(你命名为 handle
)传递给负责添加 class绑定。
示例:
module.cpp
PYBIND11_MODULE(m, handle) {
handle.doc() = "I'm a docstring hehe";
bind_a(handle);
bind_b(handle);
}
a.cpp
:
void bind_a(py::module& m) {
m.def("setSomething", &test::setSomething);
}
b.cpp
:
void bind_b(py::module& m) {
py::class_<test::B>(m, "B")
.def(py::init())
.def("getSomething", &test::B::getSomething);
}
首先,我对 C++ 编程和 pybind11 比较陌生。下面的例子应该可以解释我的问题:
a.h
:
namespace test {
class A {
public:
static int something;
};
void setSomething(int input);
}
a.cpp
:
#include <pybind11/pybind11.h>
#include "a.h"
int test::A::something;
void test::setSomething(int input) {
A::something = input;
}
PYBIND11_MODULE(a, handle) {
handle.doc() = "I'm a docstring hehe";
handle.def("setSomething", &test::setSomething);
}
b.h
:
namespace test {
class B {
public:
B();
int getSomething() const;
};
}
b.cpp
:
#include <pybind11/pybind11.h>
#include "a.h"
#include "b.h"
namespace py = pybind11;
// int test::A::something;
test::B::B(){}
int test::B::getSomething() const {
return A::something;
}
PYBIND11_MODULE(b, handle) {
handle.doc() = "I'm a docstring hehe";
py::class_<test::B>(handle, "B")
.def(py::init())
.def("getSomething", &test::B::getSomething);
}
所以我有两个 classes A 和 B,它们在 a.cpp
和 b.cpp
中定义,它们都有头文件 a.h
和 b.h
.基本上,我试图从 class A 在 class B 中访问静态变量。现在,如果我使用 CMake 编译它们并尝试 运行 一个 test.py 文件,我得到一个ImportError
告诉我 undefined symbol: _ZN4test1A9somethingE
。我希望这不是一个愚蠢的问题。提前感谢您的帮助!
编辑:如果我在 class 中定义变量,它不会获取 class 之前或之后设置的值。
想必你已经使用上面的代码构建了两个模块。 a.so
和 b.so
之类的东西,您可以使用单独的 import a
和 import b
语句将其导入 Python。
这是行不通的:您需要通过同一个二进制对象访问静态变量。即使您的链接正常工作,::test::A::something
在 a.so
和 b.so
中也会有不同的地址。 (如果您使用的是 pybind 的构建系统助手,您甚至不会注意到,因为“默认隐藏符号”会在您导入这两个模块时防止链接错误。)
您需要确保 a.cpp 和 b.cpp 链接到同一个库对象。
在 pybind 中,PYBIND11_MODULE
的第一个参数等同于您正在构建的共享对象库。如果你想像这样模块化地安排你的软件,我建议在一个单独的源文件中定义 pybind 模块,然后将模块对象(你命名为 handle
)传递给负责添加 class绑定。
示例:
module.cpp
PYBIND11_MODULE(m, handle) {
handle.doc() = "I'm a docstring hehe";
bind_a(handle);
bind_b(handle);
}
a.cpp
:
void bind_a(py::module& m) {
m.def("setSomething", &test::setSomething);
}
b.cpp
:
void bind_b(py::module& m) {
py::class_<test::B>(m, "B")
.def(py::init())
.def("getSomething", &test::B::getSomething);
}