All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pyModule.h
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifdef PXR_BASE_TF_PY_MODULE_H
8#error This file should only be included once in any given source (.cpp) file.
9#endif
10#define PXR_BASE_TF_PY_MODULE_H
11
12#include "pxr/pxr.h"
13
15#include "pxr/base/tf/api.h"
16#include "pxr/base/tf/preprocessorUtilsLite.h"
17
18#include "pxr/external/boost/python/module.hpp"
19
20// Helper macros for module files. If you implement your wrappers for classes
21// as functions named wrapClassName(), then you can create your module like
22// this:
23//
24// TF_WRAP_MODULE(ModuleName) {
25// TF_WRAP(ClassName1);
26// TF_WRAP(ClassName2);
27// TF_WRAP(ClassName3);
28// }
29//
30
31// Forward declare the function that will be provided that does the wrapping.
32static void WrapModule();
33
34PXR_NAMESPACE_OPEN_SCOPE
35
36TF_API
37void Tf_PyInitWrapModule(void (*wrapModule)(),
38 const char* packageModule,
39 const char* packageName,
40 const char* packageTag,
41 const char* packageTag2);
42
43ARCH_EXPORT
44void TF_PP_CAT(init_module_, MFB_PACKAGE_NAME)() {
45
46 Tf_PyInitWrapModule(
47 WrapModule,
48 TF_PP_STRINGIZE(MFB_PACKAGE_MODULE),
49 TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME),
50 "Wrap " TF_PP_STRINGIZE(MFB_ALT_PACKAGE_NAME),
51 TF_PP_STRINGIZE(MFB_PACKAGE_NAME)
52 );
53}
54
55PXR_NAMESPACE_CLOSE_SCOPE
56
57// When we generate boost python bindings for a library named Foo,
58// we generate a python package that has __init__.py and _Foo.so,
59// and we put all the python bindings in _Foo.so. The __init__.py
60// file imports _Foo and then publishes _Foo's symbols as its own.
61// Since the module with the bindings is named _Foo, the PyInit routine
62// must be named PyInit_Foo. This little block produces that function.
63//
64// See https://docs.python.org/3/c-api/module.html#initializing-c-modules_
65//
66extern "C"
67ARCH_EXPORT
68PyObject* TF_PP_CAT(PyInit__, MFB_PACKAGE_NAME)() {
69
70 static struct PyModuleDef moduledef = {
71 PyModuleDef_HEAD_INIT,
72 TF_PP_STRINGIZE(TF_PP_CAT(_, MFB_PACKAGE_NAME)), // m_name
73 0, // m_doc
74 -1, // m_size
75 NULL, // m_methods
76 0, // m_reload
77 0, // m_traverse
78 0, // m_clear
79 0, // m_free
80 };
81
82 PXR_NAMESPACE_USING_DIRECTIVE
83 return pxr_boost::python::detail::init_module(moduledef,
84 TF_PP_CAT(init_module_, MFB_PACKAGE_NAME));
85}
86
87// We also support the case where both the library contents and the
88// python bindings go into libfoo.so. We still generate a package named foo
89// but the __init__.py file in the package foo imports libfoo and
90// publishes it's symbols as its own. Since the module with the
91// bindings is named libfoo, the init routine must be named PyInit_libfoo.
92// This little block produces that function.
93//
94// So there are two init routines in every library, but only the one
95// that matches the name of the python module will be called by python
96// when the module is imported. So the total cost is a 1-line
97// function that doesn't get called.
98//
99extern "C"
100ARCH_EXPORT
101PyObject* TF_PP_CAT(PyInit_lib, MFB_PACKAGE_NAME)() {
102
103 static struct PyModuleDef moduledef = {
104 PyModuleDef_HEAD_INIT,
105 TF_PP_STRINGIZE(TF_PP_CAT(lib, MFB_PACKAGE_NAME)), // m_name
106 0, // m_doc
107 -1, // m_size
108 NULL, // m_methods
109 0, // m_reload
110 0, // m_traverse
111 0, // m_clear
112 0, // m_free
113 };
114
115 PXR_NAMESPACE_USING_DIRECTIVE
116 return pxr_boost::python::detail::init_module(moduledef,
117 TF_PP_CAT(init_module_, MFB_PACKAGE_NAME));
118}
119
120
121#define TF_WRAP_MODULE static void WrapModule()
122
123// Declares and calls the class wrapper for x
124#define TF_WRAP(x) ARCH_HIDDEN void wrap ## x (); wrap ## x ()
Define function attributes.