Skip to content

Commit 31a541d

Browse files
committed
Generate the TypeOffset class automatically.
Rather than manually tweak the TypeOffset class for each Python release it's easier and more robust to generate it directly from the Python headers.
1 parent ca15fe8 commit 31a541d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1423
-215
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ before_install:
1515
- yes | sudo certmgr -ssl -m https://nuget.org
1616
install:
1717
- pip install six
18+
- pip install pycparser
1819
- python setup.py build_ext --inplace
1920
script:
2021
- export PYTHONPATH=`pwd`:$PYTHONPATH

setup.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,13 +155,20 @@ def build_extension(self, ext):
155155
if "u" in sys.abiflags:
156156
defines.append("PYTHON_WITH_WIDE_UNICODE")
157157

158+
# check the interop file exists, and create it if it doesn't
159+
interop_file = _get_interop_filename()
160+
if not os.path.exists(interop_file):
161+
geninterop = os.path.join("tools", "geninterop", "geninterop.py")
162+
_check_output([sys.executable, geninterop, interop_file])
163+
158164
cmd = [
159165
_xbuild,
160166
"pythonnet.sln",
161167
"/p:Configuration=%s" % _config,
162168
"/p:Platform=%s" % PLATFORM,
163169
"/p:DefineConstants=\"%s\"" % _defines_sep.join(defines),
164170
"/p:PythonBuildDir=\"%s\"" % os.path.abspath(dest_dir),
171+
"/p:PythonInteropFile=\"%s\"" % os.path.basename(interop_file),
165172
"/verbosity:%s" % VERBOSITY,
166173
]
167174

@@ -272,6 +279,15 @@ def _check_output(*popenargs, **kwargs):
272279
return output.decode("ascii")
273280
return output
274281

282+
def _get_interop_filename():
283+
"""interopXX.cs is auto-generated as part of the build.
284+
For common windows platforms pre-generated files are included
285+
as most windows users won't have Clang installed, which is
286+
required to generate the file.
287+
"""
288+
interop_file = "interop%d%s%s.cs" % (sys.version_info[0], sys.version_info[1], getattr(sys, "abiflags", ""))
289+
return os.path.join("src", "runtime", interop_file)
290+
275291

276292
if __name__ == "__main__":
277293
setupdir = os.path.dirname(__file__)
@@ -292,6 +308,11 @@ def _check_output(*popenargs, **kwargs):
292308
for filename in fnmatch.filter(filenames, "*" + ext):
293309
sources.append(os.path.join(root, filename))
294310

311+
setup_requires = []
312+
interop_file = _get_interop_filename()
313+
if not os.path.exists(interop_file):
314+
setup_requires.append("pycparser")
315+
295316
setup(
296317
name="pythonnet",
297318
version="2.1.0.dev1",
@@ -325,5 +346,6 @@ def _check_output(*popenargs, **kwargs):
325346
"build_ext" : PythonNET_BuildExt,
326347
"install_lib" : PythonNET_InstallLib,
327348
"install_data": PythonNET_InstallData,
328-
}
349+
},
350+
setup_requires=setup_requires
329351
)

src/runtime/Python.Runtime.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@
175175
<Compile Include="typemanager.cs" />
176176
<Compile Include="typemethod.cs" />
177177
</ItemGroup>
178+
<ItemGroup Condition=" '$(PythonInteropFile)' != '' ">
179+
<Compile Include="$(PythonInteropFile)" />
180+
</ItemGroup>
178181
<ItemGroup>
179182
<None Include="buildclrmodule.bat" />
180183
<None Include="clrmodule.il" />

src/runtime/interop.cs

Lines changed: 0 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -160,220 +160,6 @@ public static int Size()
160160
}
161161
#endif
162162

163-
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
164-
internal class TypeOffset {
165-
166-
static TypeOffset() {
167-
Type type = typeof(TypeOffset);
168-
FieldInfo[] fi = type.GetFields();
169-
int size = IntPtr.Size;
170-
for (int i = 0; i < fi.Length; i++) {
171-
fi[i].SetValue(null, i * size);
172-
}
173-
}
174-
175-
public static int magic() {
176-
return ob_size;
177-
}
178-
179-
/* The *real* layout of a type object when allocated on the heap */
180-
//typedef struct _heaptypeobject {
181-
#if (Py_DEBUG) // #ifdef Py_TRACE_REFS
182-
/* _PyObject_HEAD_EXTRA defines pointers to support a doubly-linked list of all live heap objects. */
183-
public static int _ob_next = 0;
184-
public static int _ob_prev = 0;
185-
#endif
186-
// PyObject_VAR_HEAD {
187-
// PyObject_HEAD {
188-
public static int ob_refcnt = 0;
189-
public static int ob_type = 0;
190-
// }
191-
public static int ob_size = 0; /* Number of items in _VAR_iable part */
192-
// }
193-
public static int tp_name = 0; /* For printing, in format "<module>.<name>" */
194-
public static int tp_basicsize = 0; /* For allocation */
195-
public static int tp_itemsize = 0;
196-
197-
/* Methods to implement standard operations */
198-
public static int tp_dealloc = 0;
199-
public static int tp_print = 0;
200-
public static int tp_getattr = 0;
201-
public static int tp_setattr = 0;
202-
public static int tp_compare = 0; /* tp_reserved in Python 3 */
203-
public static int tp_repr = 0;
204-
205-
/* Method suites for standard classes */
206-
public static int tp_as_number = 0;
207-
public static int tp_as_sequence = 0;
208-
public static int tp_as_mapping = 0;
209-
210-
/* More standard operations (here for binary compatibility) */
211-
public static int tp_hash = 0;
212-
public static int tp_call = 0;
213-
public static int tp_str = 0;
214-
public static int tp_getattro = 0;
215-
public static int tp_setattro = 0;
216-
217-
/* Functions to access object as input/output buffer */
218-
public static int tp_as_buffer = 0;
219-
220-
/* Flags to define presence of optional/expanded features */
221-
public static int tp_flags = 0;
222-
223-
public static int tp_doc = 0; /* Documentation string */
224-
225-
/* Assigned meaning in release 2.0 */
226-
/* call function for all accessible objects */
227-
public static int tp_traverse = 0;
228-
/* delete references to contained objects */
229-
public static int tp_clear = 0;
230-
231-
/* Assigned meaning in release 2.1 */
232-
/* rich comparisons */
233-
public static int tp_richcompare = 0;
234-
/* weak reference enabler */
235-
public static int tp_weaklistoffset = 0;
236-
237-
/* Added in release 2.2 */
238-
/* Iterators */
239-
public static int tp_iter = 0;
240-
public static int tp_iternext = 0;
241-
/* Attribute descriptor and subclassing stuff */
242-
public static int tp_methods = 0;
243-
public static int tp_members = 0;
244-
public static int tp_getset = 0;
245-
public static int tp_base = 0;
246-
public static int tp_dict = 0;
247-
public static int tp_descr_get = 0;
248-
public static int tp_descr_set = 0;
249-
public static int tp_dictoffset = 0;
250-
public static int tp_init = 0;
251-
public static int tp_alloc = 0;
252-
public static int tp_new = 0;
253-
public static int tp_free = 0; /* Low-level free-memory routine */
254-
public static int tp_is_gc = 0; /* For PyObject_IS_GC */
255-
public static int tp_bases = 0;
256-
public static int tp_mro = 0; /* method resolution order */
257-
public static int tp_cache = 0;
258-
public static int tp_subclasses = 0;
259-
public static int tp_weaklist = 0;
260-
public static int tp_del = 0;
261-
#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
262-
/* Type attribute cache version tag. Added in version 2.6 */
263-
public static int tp_version_tag;
264-
#endif
265-
#if (PYTHON34)
266-
public static int tp_finalize = 0;
267-
#endif
268-
// COUNT_ALLOCS adds some more stuff to PyTypeObject
269-
#if (Py_COUNT_ALLOCS)
270-
/* these must be last and never explicitly initialized */
271-
public static int tp_allocs = 0;
272-
public static int tp_frees = 0;
273-
public static int tp_maxalloc = 0;
274-
public static int tp_prev = 0;
275-
public static int tp_next = 0;
276-
#endif
277-
//} PyTypeObject;
278-
279-
//typedef struct {
280-
public static int nb_add = 0;
281-
public static int nb_subtract = 0;
282-
public static int nb_multiply = 0;
283-
#if !(PYTHON32 || PYTHON33 || PYTHON34)
284-
public static int nb_divide = 0;
285-
#endif
286-
public static int nb_remainder = 0;
287-
public static int nb_divmod = 0;
288-
public static int nb_power = 0;
289-
public static int nb_negative = 0;
290-
public static int nb_positive = 0;
291-
public static int nb_absolute = 0;
292-
public static int nb_nonzero = 0;
293-
public static int nb_invert = 0;
294-
public static int nb_lshift = 0;
295-
public static int nb_rshift = 0;
296-
public static int nb_and = 0;
297-
public static int nb_xor = 0;
298-
public static int nb_or = 0;
299-
#if !(PYTHON32 || PYTHON33 || PYTHON34)
300-
public static int nb_coerce = 0;
301-
#endif
302-
public static int nb_int = 0;
303-
public static int nb_long = 0;
304-
public static int nb_float = 0;
305-
#if !(PYTHON32 || PYTHON33 || PYTHON34)
306-
public static int nb_oct = 0;
307-
public static int nb_hex = 0;
308-
#endif
309-
/* Added in release 2.0 */
310-
public static int nb_inplace_add = 0;
311-
public static int nb_inplace_subtract = 0;
312-
public static int nb_inplace_multiply = 0;
313-
#if !(PYTHON32 || PYTHON33 || PYTHON34)
314-
public static int nb_inplace_divide = 0;
315-
#endif
316-
public static int nb_inplace_remainder = 0;
317-
public static int nb_inplace_power = 0;
318-
public static int nb_inplace_lshift = 0;
319-
public static int nb_inplace_rshift = 0;
320-
public static int nb_inplace_and = 0;
321-
public static int nb_inplace_xor = 0;
322-
public static int nb_inplace_or = 0;
323-
/* Added in release 2.2 */
324-
/* The following require the Py_TPFLAGS_HAVE_CLASS flag */
325-
public static int nb_floor_divide = 0;
326-
public static int nb_true_divide = 0;
327-
public static int nb_inplace_floor_divide = 0;
328-
public static int nb_inplace_true_divide = 0;
329-
#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
330-
/* Added in release 2.5 */
331-
public static int nb_index = 0;
332-
#endif
333-
//} PyNumberMethods;
334-
//typedef struct {
335-
public static int mp_length = 0;
336-
public static int mp_subscript = 0;
337-
public static int mp_ass_subscript = 0;
338-
//} PyMappingMethods;
339-
//typedef struct {
340-
public static int sq_length = 0;
341-
public static int sq_concat = 0;
342-
public static int sq_repeat = 0;
343-
public static int sq_item = 0;
344-
public static int sq_slice = 0;
345-
public static int sq_ass_item = 0;
346-
public static int sq_ass_slice = 0;
347-
public static int sq_contains = 0;
348-
/* Added in release 2.0 */
349-
public static int sq_inplace_concat = 0;
350-
public static int sq_inplace_repeat = 0;
351-
//} PySequenceMethods;
352-
//typedef struct {
353-
#if !(PYTHON32 || PYTHON33 || PYTHON34)
354-
public static int bf_getreadbuffer = 0;
355-
public static int bf_getwritebuffer = 0;
356-
public static int bf_getsegcount = 0;
357-
public static int bf_getcharbuffer = 0;
358-
#endif
359-
#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
360-
// This addition is not actually noted in the 2.6.5 object.h
361-
public static int bf_getbuffer = 0;
362-
public static int bf_releasebuffer = 0;
363-
//} PyBufferProcs;
364-
#endif
365-
//PyObject *ht_name, *ht_slots;
366-
public static int name = 0;
367-
public static int slots = 0;
368-
369-
#if (PYTHON33 || PYTHON34)
370-
public static int qualname = 0;
371-
public static int cached_keys;
372-
#endif
373-
374-
/* here are optional user slots, followed by the members. */
375-
public static int members = 0;
376-
}
377163

378164
#if (PYTHON32 || PYTHON33 || PYTHON34)
379165
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

0 commit comments

Comments
 (0)