Skip to content

Commit acf1c11

Browse files
authored
Python: Fix ODR Violation (#1521)
In pybind11 (and nanobind), auxiliary headers and `PYBIND11_MAKE_OPAQUE` definitions for distributed modules need to be included in every translation unit. Otherwise, a one-definition-rule violation occurs, which is undefined behavior.
1 parent 9d5bf96 commit acf1c11

26 files changed

+113
-182
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* Copyright 2023 The openPMD Community
2+
*
3+
* This header is used to centrally define classes that shall not violate the
4+
* C++ one-definition-rule (ODR) for various Python translation units.
5+
*
6+
* Authors: Axel Huebl
7+
* License: LGPL-3.0-or-later
8+
*/
9+
#pragma once
10+
11+
#include "openPMD/Iteration.hpp"
12+
#include "openPMD/Mesh.hpp"
13+
#include "openPMD/ParticlePatches.hpp"
14+
#include "openPMD/ParticleSpecies.hpp"
15+
#include "openPMD/Record.hpp"
16+
#include "openPMD/Series.hpp"
17+
#include "openPMD/backend/BaseRecord.hpp"
18+
#include "openPMD/backend/BaseRecordComponent.hpp"
19+
#include "openPMD/backend/MeshRecordComponent.hpp"
20+
#include "openPMD/backend/PatchRecord.hpp"
21+
#include "openPMD/backend/PatchRecordComponent.hpp"
22+
23+
#include <pybind11/gil.h>
24+
#include <pybind11/numpy.h>
25+
#include <pybind11/pybind11.h>
26+
#include <pybind11/stl.h>
27+
#include <pybind11/stl_bind.h>
28+
// not yet used:
29+
// pybind11/functional.h // for std::function
30+
31+
// used exclusively in all our Python .cpp files
32+
namespace py = pybind11;
33+
using namespace openPMD;
34+
35+
// opaque types
36+
using PyIterationContainer = Series::IterationsContainer_t;
37+
using PyMeshContainer = Container<Mesh>;
38+
using PyPartContainer = Container<ParticleSpecies>;
39+
using PyPatchContainer = Container<ParticlePatches>;
40+
using PyRecordContainer = Container<Record>;
41+
using PyPatchRecordContainer = Container<PatchRecord>;
42+
using PyRecordComponentContainer = Container<RecordComponent>;
43+
using PyMeshRecordComponentContainer = Container<MeshRecordComponent>;
44+
using PyPatchRecordComponentContainer = Container<PatchRecordComponent>;
45+
using PyBaseRecordComponentContainer = Container<BaseRecordComponent>;
46+
PYBIND11_MAKE_OPAQUE(PyIterationContainer)
47+
PYBIND11_MAKE_OPAQUE(PyMeshContainer)
48+
PYBIND11_MAKE_OPAQUE(PyPartContainer)
49+
PYBIND11_MAKE_OPAQUE(PyPatchContainer)
50+
PYBIND11_MAKE_OPAQUE(PyRecordContainer)
51+
PYBIND11_MAKE_OPAQUE(PyPatchRecordContainer)
52+
PYBIND11_MAKE_OPAQUE(PyRecordComponentContainer)
53+
PYBIND11_MAKE_OPAQUE(PyMeshRecordComponentContainer)
54+
PYBIND11_MAKE_OPAQUE(PyPatchRecordComponentContainer)
55+
PYBIND11_MAKE_OPAQUE(PyBaseRecordComponentContainer)

include/openPMD/binding/python/Numpy.hpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@
2222

2323
#include "openPMD/Datatype.hpp"
2424

25-
#include <pybind11/numpy.h>
26-
#include <pybind11/pybind11.h>
27-
#include <pybind11/stl.h>
25+
#include "Common.hpp"
2826

2927
#include <exception>
3028
#include <string>

include/openPMD/binding/python/Pickle.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
#include "openPMD/Series.hpp"
2525
#include "openPMD/backend/Attributable.hpp"
2626

27-
#include <pybind11/pybind11.h>
28-
#include <pybind11/stl.h>
27+
#include "Common.hpp"
2928

3029
#include <exception>
3130
#include <string>
@@ -46,8 +45,6 @@ template <typename... T_Args, typename T_SeriesAccessor>
4645
inline void
4746
add_pickle(pybind11::class_<T_Args...> &cl, T_SeriesAccessor &&seriesAccessor)
4847
{
49-
namespace py = pybind11;
50-
5148
// helper: get first class in py::class_ - that's the type we pickle
5249
using PickledClass =
5350
typename std::tuple_element<0, std::tuple<T_Args...> >::type;

src/binding/python/Access.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@
1818
* and the GNU Lesser General Public License along with openPMD-api.
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
21-
#include <pybind11/pybind11.h>
22-
#include <pybind11/stl.h>
23-
2421
#include "openPMD/IO/Access.hpp"
2522

26-
namespace py = pybind11;
27-
using namespace openPMD;
23+
#include "openPMD/binding/python/Common.hpp"
2824

2925
void init_Access(py::module &m)
3026
{

src/binding/python/Attributable.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@
2222
#include "openPMD/DatatypeHelpers.hpp"
2323
#include "openPMD/auxiliary/Variant.hpp"
2424
#include "openPMD/backend/Attribute.hpp"
25-
#include "openPMD/binding/python/Numpy.hpp"
2625

27-
#include <pybind11/pybind11.h>
28-
#include <pybind11/stl.h>
29-
#include <pybind11/stl_bind.h>
26+
#include "openPMD/binding/python/Common.hpp"
27+
#include "openPMD/binding/python/Numpy.hpp"
3028

3129
#include <algorithm>
3230
#include <array>
@@ -35,11 +33,7 @@
3533
#include <string>
3634
#include <vector>
3735

38-
namespace py = pybind11;
39-
using namespace openPMD;
40-
4136
using PyAttributeKeys = std::vector<std::string>;
42-
// PYBIND11_MAKE_OPAQUE(PyAttributeKeys)
4337

4438
bool setAttributeFromBufferInfo(
4539
Attributable &attr, std::string const &key, py::buffer &a)

src/binding/python/BaseRecord.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,14 @@
1818
* and the GNU Lesser General Public License along with openPMD-api.
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
21-
#include <pybind11/pybind11.h>
22-
#include <pybind11/stl.h>
23-
2421
#include "openPMD/backend/BaseRecord.hpp"
2522
#include "openPMD/backend/BaseRecordComponent.hpp"
2623
#include "openPMD/backend/Container.hpp"
2724
#include "openPMD/backend/MeshRecordComponent.hpp"
2825
#include "openPMD/backend/PatchRecordComponent.hpp"
29-
#include "openPMD/binding/python/UnitDimension.hpp"
3026

31-
namespace py = pybind11;
32-
using namespace openPMD;
27+
#include "openPMD/binding/python/Common.hpp"
28+
#include "openPMD/binding/python/UnitDimension.hpp"
3329

3430
void init_BaseRecord(py::module &m)
3531
{

src/binding/python/BaseRecordComponent.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,14 @@
1818
* and the GNU Lesser General Public License along with openPMD-api.
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
21-
#include <pybind11/numpy.h>
22-
#include <pybind11/pybind11.h>
23-
#include <pybind11/stl.h>
24-
25-
#include "openPMD/Datatype.hpp"
2621
#include "openPMD/backend/BaseRecordComponent.hpp"
22+
#include "openPMD/Datatype.hpp"
23+
24+
#include "openPMD/binding/python/Common.hpp"
2725
#include "openPMD/binding/python/Numpy.hpp"
2826

2927
#include <sstream>
3028

31-
namespace py = pybind11;
32-
using namespace openPMD;
33-
3429
void init_BaseRecordComponent(py::module &m)
3530
{
3631
py::class_<BaseRecordComponent, Attributable>(m, "Base_Record_Component")

src/binding/python/ChunkInfo.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,13 @@
1818
* and the GNU Lesser General Public License along with openPMD-api.
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
21-
#include <pybind11/pybind11.h>
22-
#include <pybind11/stl.h>
23-
2421
#include "openPMD/ChunkInfo.hpp"
2522

23+
#include "openPMD/binding/python/Common.hpp"
24+
2625
#include <exception>
2726
#include <string>
2827

29-
namespace py = pybind11;
30-
using namespace openPMD;
31-
3228
void init_Chunk(py::module &m)
3329
{
3430
py::class_<ChunkInfo>(m, "ChunkInfo")

src/binding/python/Container.cpp

Lines changed: 2 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,16 @@
2323
*
2424
* BSD-style license, see pybind11 LICENSE file.
2525
*/
26-
27-
#include <pybind11/pybind11.h>
28-
#include <pybind11/stl.h>
29-
#include <pybind11/stl_bind.h>
30-
31-
#include "openPMD/Iteration.hpp"
32-
#include "openPMD/Mesh.hpp"
33-
#include "openPMD/ParticlePatches.hpp"
34-
#include "openPMD/ParticleSpecies.hpp"
35-
#include "openPMD/Record.hpp"
36-
#include "openPMD/Series.hpp"
37-
#include "openPMD/backend/BaseRecord.hpp"
38-
#include "openPMD/backend/BaseRecordComponent.hpp"
3926
#include "openPMD/backend/Container.hpp"
40-
#include "openPMD/backend/MeshRecordComponent.hpp"
41-
#include "openPMD/backend/PatchRecord.hpp"
42-
#include "openPMD/backend/PatchRecordComponent.hpp"
27+
28+
#include "openPMD/binding/python/Common.hpp"
4329

4430
#include <cstddef>
4531
#include <memory>
4632
#include <sstream>
4733
#include <string>
4834
#include <utility>
4935

50-
namespace py = pybind11;
51-
using namespace openPMD;
52-
5336
namespace detail
5437
{
5538
/* based on std_bind.h in pybind11
@@ -156,27 +139,6 @@ bind_container(py::handle scope, std::string const &name, Args &&...args)
156139
}
157140
} // namespace detail
158141

159-
using PyIterationContainer = Series::IterationsContainer_t;
160-
using PyMeshContainer = Container<Mesh>;
161-
using PyPartContainer = Container<ParticleSpecies>;
162-
using PyPatchContainer = Container<ParticlePatches>;
163-
using PyRecordContainer = Container<Record>;
164-
using PyPatchRecordContainer = Container<PatchRecord>;
165-
using PyRecordComponentContainer = Container<RecordComponent>;
166-
using PyMeshRecordComponentContainer = Container<MeshRecordComponent>;
167-
using PyPatchRecordComponentContainer = Container<PatchRecordComponent>;
168-
using PyBaseRecordComponentContainer = Container<BaseRecordComponent>;
169-
PYBIND11_MAKE_OPAQUE(PyIterationContainer)
170-
PYBIND11_MAKE_OPAQUE(PyMeshContainer)
171-
PYBIND11_MAKE_OPAQUE(PyPartContainer)
172-
PYBIND11_MAKE_OPAQUE(PyPatchContainer)
173-
PYBIND11_MAKE_OPAQUE(PyRecordContainer)
174-
PYBIND11_MAKE_OPAQUE(PyPatchRecordContainer)
175-
PYBIND11_MAKE_OPAQUE(PyRecordComponentContainer)
176-
PYBIND11_MAKE_OPAQUE(PyMeshRecordComponentContainer)
177-
PYBIND11_MAKE_OPAQUE(PyPatchRecordComponentContainer)
178-
PYBIND11_MAKE_OPAQUE(PyBaseRecordComponentContainer)
179-
180142
void init_Container(py::module &m)
181143
{
182144
::detail::bind_container<PyIterationContainer>(m, "Iteration_Container");

src/binding/python/Dataset.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,13 @@
1818
* and the GNU Lesser General Public License along with openPMD-api.
1919
* If not, see <http://www.gnu.org/licenses/>.
2020
*/
21-
#include <pybind11/pybind11.h>
22-
#include <pybind11/stl.h>
23-
2421
#include "openPMD/Dataset.hpp"
22+
23+
#include "openPMD/binding/python/Common.hpp"
2524
#include "openPMD/binding/python/Numpy.hpp"
2625

2726
#include <string>
2827

29-
namespace py = pybind11;
30-
using namespace openPMD;
31-
3228
void init_Dataset(py::module &m)
3329
{
3430
py::class_<Dataset>(m, "Dataset")

0 commit comments

Comments
 (0)