Skip to content

Commit e421106

Browse files
authored
bpo-35134: Create Include/cpython/ subdirectory (GH-10624)
Include/*.h should be the "portable Python API", whereas Include/cpython/*.h should be the "CPython API": CPython implementation details. Changes: * Create Include/cpython/ subdirectory * "make install" now creates $prefix/include/cpython and copy Include/cpython/* to $prefix/include/cpython * Create Include/cpython/objimpl.h: move objimpl.h code surrounded by "#ifndef Py_LIMITED_API" to cpython/objimpl.h. * objimpl.h now includes cpython/objimpl.h * Windows installer (MSI) now also install Include/ subdirectories: Include/cpython/ and Include/internal/.
1 parent b409ffa commit e421106

File tree

7 files changed

+138
-108
lines changed

7 files changed

+138
-108
lines changed

Include/cpython/objimpl.h

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#ifndef Py_CPYTHON_OBJIMPL_H
2+
# error "this header file must not be included directly"
3+
#endif
4+
5+
#ifdef __cplusplus
6+
extern "C" {
7+
#endif
8+
9+
/* This function returns the number of allocated memory blocks, regardless of size */
10+
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
11+
12+
/* Macros */
13+
#ifdef WITH_PYMALLOC
14+
PyAPI_FUNC(int) _PyObject_DebugMallocStats(FILE *out);
15+
#endif
16+
17+
18+
typedef struct {
19+
/* user context passed as the first argument to the 2 functions */
20+
void *ctx;
21+
22+
/* allocate an arena of size bytes */
23+
void* (*alloc) (void *ctx, size_t size);
24+
25+
/* free an arena */
26+
void (*free) (void *ctx, void *ptr, size_t size);
27+
} PyObjectArenaAllocator;
28+
29+
/* Get the arena allocator. */
30+
PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator);
31+
32+
/* Set the arena allocator. */
33+
PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator);
34+
35+
36+
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
37+
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);
38+
39+
40+
/* Test if an object has a GC head */
41+
#define PyObject_IS_GC(o) \
42+
(PyType_IS_GC(Py_TYPE(o)) \
43+
&& (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
44+
45+
/* GC information is stored BEFORE the object structure. */
46+
typedef struct {
47+
// Pointer to next object in the list.
48+
// 0 means the object is not tracked
49+
uintptr_t _gc_next;
50+
51+
// Pointer to previous object in the list.
52+
// Lowest two bits are used for flags documented later.
53+
uintptr_t _gc_prev;
54+
} PyGC_Head;
55+
56+
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
57+
58+
/* True if the object is currently tracked by the GC. */
59+
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)
60+
61+
/* True if the object may be tracked by the GC in the future, or already is.
62+
This can be useful to implement some optimizations. */
63+
#define _PyObject_GC_MAY_BE_TRACKED(obj) \
64+
(PyObject_IS_GC(obj) && \
65+
(!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
66+
67+
68+
/* Bit flags for _gc_prev */
69+
/* Bit 0 is set when tp_finalize is called */
70+
#define _PyGC_PREV_MASK_FINALIZED (1)
71+
/* Bit 1 is set when the object is in generation which is GCed currently. */
72+
#define _PyGC_PREV_MASK_COLLECTING (2)
73+
/* The (N-2) most significant bits contain the real address. */
74+
#define _PyGC_PREV_SHIFT (2)
75+
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
76+
77+
// Lowest bit of _gc_next is used for flags only in GC.
78+
// But it is always 0 for normal code.
79+
#define _PyGCHead_NEXT(g) ((PyGC_Head*)(g)->_gc_next)
80+
#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))
81+
82+
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
83+
#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))
84+
#define _PyGCHead_SET_PREV(g, p) do { \
85+
assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
86+
(g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \
87+
| ((uintptr_t)(p)); \
88+
} while (0)
89+
90+
#define _PyGCHead_FINALIZED(g) \
91+
(((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
92+
#define _PyGCHead_SET_FINALIZED(g) \
93+
((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)
94+
95+
#define _PyGC_FINALIZED(o) \
96+
_PyGCHead_FINALIZED(_Py_AS_GC(o))
97+
#define _PyGC_SET_FINALIZED(o) \
98+
_PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
99+
100+
101+
PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size);
102+
PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size);
103+
104+
105+
/* Test if a type supports weak references */
106+
#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0)
107+
108+
#define PyObject_GET_WEAKREFS_LISTPTR(o) \
109+
((PyObject **) (((char *) (o)) + Py_TYPE(o)->tp_weaklistoffset))
110+
111+
#ifdef __cplusplus
112+
}
113+
#endif

Include/objimpl.h

+3-105
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,6 @@ PyAPI_FUNC(void *) PyObject_Calloc(size_t nelem, size_t elsize);
101101
PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size);
102102
PyAPI_FUNC(void) PyObject_Free(void *ptr);
103103

104-
#ifndef Py_LIMITED_API
105-
/* This function returns the number of allocated memory blocks, regardless of size */
106-
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
107-
#endif /* !Py_LIMITED_API */
108-
109-
/* Macros */
110-
#ifdef WITH_PYMALLOC
111-
#ifndef Py_LIMITED_API
112-
PyAPI_FUNC(int) _PyObject_DebugMallocStats(FILE *out);
113-
#endif /* #ifndef Py_LIMITED_API */
114-
#endif
115104

116105
/* Macros */
117106
#define PyObject_MALLOC PyObject_Malloc
@@ -226,24 +215,6 @@ _PyObject_INIT_VAR(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size)
226215
constructor you would start directly with PyObject_Init/InitVar
227216
*/
228217

229-
#ifndef Py_LIMITED_API
230-
typedef struct {
231-
/* user context passed as the first argument to the 2 functions */
232-
void *ctx;
233-
234-
/* allocate an arena of size bytes */
235-
void* (*alloc) (void *ctx, size_t size);
236-
237-
/* free an arena */
238-
void (*free) (void *ctx, void *ptr, size_t size);
239-
} PyObjectArenaAllocator;
240-
241-
/* Get the arena allocator. */
242-
PyAPI_FUNC(void) PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator);
243-
244-
/* Set the arena allocator. */
245-
PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator);
246-
#endif
247218

248219

249220
/*
@@ -254,11 +225,6 @@ PyAPI_FUNC(void) PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator);
254225
/* C equivalent of gc.collect() which ignores the state of gc.enabled. */
255226
PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void);
256227

257-
#ifndef Py_LIMITED_API
258-
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectNoFail(void);
259-
PyAPI_FUNC(Py_ssize_t) _PyGC_CollectIfEnabled(void);
260-
#endif
261-
262228
/* Test if a type has a GC head */
263229
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
264230

@@ -267,72 +233,7 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t);
267233
( (type *) _PyObject_GC_Resize(_PyVarObject_CAST(op), (n)) )
268234

269235

270-
#ifndef Py_LIMITED_API
271-
/* Test if an object has a GC head */
272-
#define PyObject_IS_GC(o) \
273-
(PyType_IS_GC(Py_TYPE(o)) \
274-
&& (Py_TYPE(o)->tp_is_gc == NULL || Py_TYPE(o)->tp_is_gc(o)))
275-
276-
/* GC information is stored BEFORE the object structure. */
277-
typedef struct {
278-
// Pointer to next object in the list.
279-
// 0 means the object is not tracked
280-
uintptr_t _gc_next;
281-
282-
// Pointer to previous object in the list.
283-
// Lowest two bits are used for flags documented later.
284-
uintptr_t _gc_prev;
285-
} PyGC_Head;
286-
287-
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
288-
289-
/* True if the object is currently tracked by the GC. */
290-
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)
291-
292-
/* True if the object may be tracked by the GC in the future, or already is.
293-
This can be useful to implement some optimizations. */
294-
#define _PyObject_GC_MAY_BE_TRACKED(obj) \
295-
(PyObject_IS_GC(obj) && \
296-
(!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
297-
298-
299-
/* Bit flags for _gc_prev */
300-
/* Bit 0 is set when tp_finalize is called */
301-
#define _PyGC_PREV_MASK_FINALIZED (1)
302-
/* Bit 1 is set when the object is in generation which is GCed currently. */
303-
#define _PyGC_PREV_MASK_COLLECTING (2)
304-
/* The (N-2) most significant bits contain the real address. */
305-
#define _PyGC_PREV_SHIFT (2)
306-
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
307-
308-
// Lowest bit of _gc_next is used for flags only in GC.
309-
// But it is always 0 for normal code.
310-
#define _PyGCHead_NEXT(g) ((PyGC_Head*)(g)->_gc_next)
311-
#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))
312-
313-
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
314-
#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))
315-
#define _PyGCHead_SET_PREV(g, p) do { \
316-
assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
317-
(g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \
318-
| ((uintptr_t)(p)); \
319-
} while (0)
320-
321-
#define _PyGCHead_FINALIZED(g) \
322-
(((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
323-
#define _PyGCHead_SET_FINALIZED(g) \
324-
((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)
325-
326-
#define _PyGC_FINALIZED(o) \
327-
_PyGCHead_FINALIZED(_Py_AS_GC(o))
328-
#define _PyGC_SET_FINALIZED(o) \
329-
_PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
330-
#endif /* !defined(Py_LIMITED_API) */
331236

332-
#ifndef Py_LIMITED_API
333-
PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size);
334-
PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size);
335-
#endif /* !Py_LIMITED_API */
336237
PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
337238
PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t);
338239

@@ -368,13 +269,10 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *);
368269
} \
369270
} while (0)
370271

371-
372-
/* Test if a type supports weak references */
373272
#ifndef Py_LIMITED_API
374-
#define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0)
375-
376-
#define PyObject_GET_WEAKREFS_LISTPTR(o) \
377-
((PyObject **) (((char *) (o)) + Py_TYPE(o)->tp_weaklistoffset))
273+
# define Py_CPYTHON_OBJIMPL_H
274+
# include "cpython/objimpl.h"
275+
# undef Py_CPYTHON_OBJIMPL_H
378276
#endif
379277

380278
#ifdef __cplusplus

Makefile.pre.in

+14
Original file line numberDiff line numberDiff line change
@@ -1021,9 +1021,13 @@ PYTHON_HEADERS= \
10211021
$(srcdir)/Include/unicodeobject.h \
10221022
$(srcdir)/Include/warnings.h \
10231023
$(srcdir)/Include/weakrefobject.h \
1024+
\
10241025
pyconfig.h \
10251026
$(PARSER_HEADERS) \
10261027
$(srcdir)/Include/Python-ast.h \
1028+
\
1029+
$(srcdir)/Include/cpython/objimpl.h \
1030+
\
10271031
$(srcdir)/Include/internal/pycore_accu.h \
10281032
$(srcdir)/Include/internal/pycore_atomic.h \
10291033
$(srcdir)/Include/internal/pycore_ceval.h \
@@ -1446,6 +1450,11 @@ inclinstall:
14461450
else true; \
14471451
fi; \
14481452
done
1453+
@if test ! -d $(DESTDIR)$(INCLUDEPY)/cpython; then \
1454+
echo "Creating directory $(DESTDIR)$(INCLUDEPY)/cpython"; \
1455+
$(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(INCLUDEPY)/cpython; \
1456+
else true; \
1457+
fi
14491458
@if test ! -d $(DESTDIR)$(INCLUDEPY)/internal; then \
14501459
echo "Creating directory $(DESTDIR)$(INCLUDEPY)/internal"; \
14511460
$(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(INCLUDEPY)/internal; \
@@ -1456,6 +1465,11 @@ inclinstall:
14561465
echo $(INSTALL_DATA) $$i $(INCLUDEPY); \
14571466
$(INSTALL_DATA) $$i $(DESTDIR)$(INCLUDEPY); \
14581467
done
1468+
@for i in $(srcdir)/Include/cpython/*.h; \
1469+
do \
1470+
echo $(INSTALL_DATA) $$i $(INCLUDEPY)/cpython; \
1471+
$(INSTALL_DATA) $$i $(DESTDIR)$(INCLUDEPY)/cpython; \
1472+
done
14591473
@for i in $(srcdir)/Include/internal/*.h; \
14601474
do \
14611475
echo $(INSTALL_DATA) $$i $(INCLUDEPY)/internal; \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Creation of a new ``Include/cpython/`` subdirectory.

PCbuild/pythoncore.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
<ClInclude Include="..\Include\complexobject.h" />
9696
<ClInclude Include="..\Include\context.h" />
9797
<ClInclude Include="..\Include\coreconfig.h" />
98+
<ClInclude Include="..\Include\cpython\objimpl.h" />
9899
<ClInclude Include="..\Include\datetime.h" />
99100
<ClInclude Include="..\Include\descrobject.h" />
100101
<ClInclude Include="..\Include\dictobject.h" />

PCbuild/pythoncore.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@
8484
<ClInclude Include="..\Include\coreconfig.h">
8585
<Filter>Include</Filter>
8686
</ClInclude>
87+
<ClInclude Include="..\Include\cpython\objimpl.h">
88+
<Filter>Include</Filter>
89+
</ClInclude>
8790
<ClInclude Include="..\Include\datetime.h">
8891
<Filter>Include</Filter>
8992
</ClInclude>

Tools/msi/dev/dev.wixproj

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
<EmbeddedResource Include="*.wxl" />
2222
</ItemGroup>
2323
<ItemGroup>
24-
<InstallFiles Include="$(PySourcePath)include\*.h">
24+
<InstallFiles Include="$(PySourcePath)include\**\*.h">
2525
<SourceBase>$(PySourcePath)</SourceBase>
2626
<Source>!(bindpath.src)</Source>
2727
<TargetBase>$(PySourcePath)</TargetBase>
2828
<Target_></Target_>
2929
<Group>dev_include</Group>
3030
</InstallFiles>
3131
</ItemGroup>
32-
32+
3333
<Target Name="BuildMinGWLib"
3434
Inputs="$(BuildPath)$(PyDllName).dll"
3535
Outputs="$(BuildPath)lib$(PyDllName).a"
@@ -46,4 +46,4 @@
4646
</Target>
4747

4848
<Import Project="..\msi.targets" />
49-
</Project>
49+
</Project>

0 commit comments

Comments
 (0)