Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argument Clinic includes internal headers in generated output unconditionally #107603

Closed
erlend-aasland opened this issue Aug 3, 2023 · 6 comments
Labels
topic-argument-clinic type-bug An unexpected behavior, bug, or error

Comments

@erlend-aasland
Copy link
Contributor

erlend-aasland commented Aug 3, 2023

It seems like Argument Clinic generates code that define Py_BUILD_CORE and includes internal headers unconditionally; for example, a file with a METH_O function will have no need for those:

/*[clinic input]
preserve
[clinic start generated code]*/

#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#  include "pycore_gc.h"            // PyGC_Head
#  include "pycore_runtime.h"       // _Py_ID()
#endif


PyDoc_STRVAR(func__doc__,
"func($module, a, /)\n"
"--\n"
"\n");

#define FUNC_METHODDEF    \
    {"func", (PyCFunction)func, METH_O, func__doc__},
/*[clinic end generated code: output=851b6645c29cfa0d input=a9049054013a1b77]*/

OTOH, a METH_KEYWORDS function needs those:

/*[clinic input]
preserve
[clinic start generated code]*/

#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#  include "pycore_gc.h"            // PyGC_Head
#  include "pycore_runtime.h"       // _Py_ID()
#endif


PyDoc_STRVAR(func__doc__,
"func($module, /, a, b)\n"
"--\n"
"\n");

#define FUNC_METHODDEF    \
    {"func", _PyCFunction_CAST(func), METH_FASTCALL|METH_KEYWORDS, func__doc__},

static PyObject *
func_impl(PyObject *module, PyObject *a, PyObject *b);

static PyObject *
func(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{
    PyObject *return_value = NULL;
    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)

    #define NUM_KEYWORDS 2
    static struct {
        PyGC_Head _this_is_not_used;
        PyObject_VAR_HEAD
        PyObject *ob_item[NUM_KEYWORDS];
    } _kwtuple = {
        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
        .ob_item = { &_Py_ID(a), &_Py_ID(b), },
    };
    #undef NUM_KEYWORDS
    #define KWTUPLE (&_kwtuple.ob_base.ob_base)

    #else  // !Py_BUILD_CORE
    #  define KWTUPLE NULL
    #endif  // !Py_BUILD_CORE

    static const char * const _keywords[] = {"a", "b", NULL};
    static _PyArg_Parser _parser = {
        .keywords = _keywords,
        .fname = "func",
        .kwtuple = KWTUPLE,
    };
    #undef KWTUPLE
    PyObject *argsbuf[2];
    PyObject *a;
    PyObject *b;

    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 2, 0, argsbuf);
    if (!args) {
        goto exit;
    }
    a = args[0];
    b = args[1];
    return_value = func_impl(module, a, b);

exit:
    return return_value;
}
/*[clinic end generated code: output=e790cd95ffc517a0 input=a9049054013a1b77]*/

Argument Clinic should check if those defines/includes are needed before generating the output.

Linked PRs

@erlend-aasland erlend-aasland added type-bug An unexpected behavior, bug, or error topic-argument-clinic labels Aug 3, 2023
@erlend-aasland
Copy link
Contributor Author

'unconditionally' was a bit harsh, but it does generate core includes for some cases where it is not needed.

@kumaraditya303
Copy link
Contributor

I don't think this is an important issue, this is more of a "nice to have" rather than necessary, it will probably add more conditional code. I certainly don't consider this as a bug though.

@erlend-aasland
Copy link
Contributor Author

Yeah, it's not an important issue. But/feature? I'd say it is an undesirable feature, then :)

vstinner added a commit to vstinner/cpython that referenced this issue Aug 25, 2023
Remove _PyLong_UnsignedShort_Converter() from the public C API: move
the function to the internal pycore_long.h header.

* Add Clinic.add_include() method
* Add CConverter.include and CConverter.add_include()
* Printer.print_block() gets a second parameter: clinic.
vstinner added a commit to vstinner/cpython that referenced this issue Aug 25, 2023
* Add Clinic.add_include() method
* Add CConverter.include and CConverter.add_include()
* Printer.print_block() gets a second parameter: clinic.
* Remove duplicated declaration of "clinic" global variable.
@vstinner
Copy link
Member

I don't think this is an important issue, this is more of a "nice to have" rather than necessary, it will probably add more conditional code. I certainly don't consider this as a bug though.

I would like this feature to be able to remove private functions only used by AC from the public C API: issue #106320.

vstinner added a commit to vstinner/cpython that referenced this issue Aug 25, 2023
* Add Clinic.add_include() method
* Add CConverter.include and CConverter.add_include()
* Printer.print_block() gets a second parameter: clinic.
* Remove duplicated declaration of "clinic" global variable.
vstinner added a commit that referenced this issue Aug 25, 2023
* Add Clinic.add_include() method
* Add CConverter.include and CConverter.add_include()
* Printer.print_block() gets a second parameter: clinic.
* Remove duplicated declaration of "clinic" global variable.
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/grpmodule.c
* Modules/syslogmodule.c
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/grpmodule.c
* Modules/syslogmodule.c
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/grpmodule.c
* Modules/syslogmodule.c
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/_testinternalcapi.c
* Modules/grpmodule.c
* Modules/syslogmodule.c

On Windows, the _testinternalcapi extension is built as a shared
extension which cannot use the _Py_ID() API: accessing _PyRuntime
members is not possible in a static _PyArg_Parser variable, it's not
a "constant".
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/_testinternalcapi.c
* Modules/_testmultiphase.c
* Modules/grpmodule.c
* Modules/syslogmodule.c

On Windows, the _testinternalcapi and _testmultiphase extensions are
built as shared extensions which cannot use the _Py_ID() API.
Accessing _PyRuntime members is not possible in a static
_PyArg_Parser variable, it's not a "constant".
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/_testinternalcapi.c
* Modules/_testmultiphase.c
* Modules/grpmodule.c
* Modules/syslogmodule.c
* PC/_testconsole.c

On Windows, the _testinternalcapi, _testmultiphase and _testconsole
extensions are built as shared extensions which cannot use the
_Py_ID() API.  Accessing _PyRuntime members is not possible in a
static _PyArg_Parser variable, it's not a "constant".
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

Add Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI macro to opt-out for the
internal C API in Argument Clinic.

The following extensions avoids the internal C API by defining the
macro Py_ARGUMENT_CLINIC_AVOID_INTERNAL_CAPI:

* Modules/_csv.c
* Modules/_multiprocessing/posixshmem.c
* Modules/_testcapi/exceptions.c
* Modules/grpmodule.c
* Modules/syslogmodule.c
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

* Add 'condition' optional argument to Clinic.add_include().
* deprecate_keyword_use() includes pycore_runtime.h when using
  the _PyID() function.
* Fix rendering of includes: comments start at the column 35.

Effects:

* 42 header files generated by AC no longer include the internal C
  API, instead of 4 header files before. For example,
  Modules/clinic/_abc.c.h no longer includes the internal C API.
* Fix _testclinic_depr.c.h: it now always includes pycore_runtime.h
  to get _Py_ID().
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

* Add 'condition' optional argument to Clinic.add_include().
* deprecate_keyword_use() includes pycore_runtime.h when using
  the _PyID() function.
* Fix rendering of includes: comments start at the column 35.
* Mark PC/clinic/_wmimodule.cpp.h and
  "Objects/stringlib/clinic/*.h.h" header files as generated in
  .gitattributes.

Effects:

* 42 header files generated by AC no longer include the internal C
  API, instead of 4 header files before. For example,
  Modules/clinic/_abc.c.h no longer includes the internal C API.
* Fix _testclinic_depr.c.h: it now always includes pycore_runtime.h
  to get _Py_ID().
vstinner added a commit to vstinner/cpython that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

* Add 'condition' optional argument to Clinic.add_include().
* deprecate_keyword_use() includes pycore_runtime.h when using
  the _PyID() function.
* Fix rendering of includes: comments start at the column 35.
* Mark PC/clinic/_wmimodule.cpp.h and
  "Objects/stringlib/clinic/*.h.h" header files as generated in
  .gitattributes.

Effects:

* 42 header files generated by AC no longer include the internal C
  API, instead of 4 header files before. For example,
  Modules/clinic/_abc.c.h no longer includes the internal C API.
* Fix _testclinic_depr.c.h: it now always includes pycore_runtime.h
  to get _Py_ID().
vstinner added a commit that referenced this issue Aug 31, 2023
Argument Clinic now only includes pycore_gc.h if PyGC_Head is needed,
and only includes pycore_runtime.h if _Py_ID() is needed.

* Add 'condition' optional argument to Clinic.add_include().
* deprecate_keyword_use() includes pycore_runtime.h when using
  the _PyID() function.
* Fix rendering of includes: comments start at the column 35.
* Mark PC/clinic/_wmimodule.cpp.h and
  "Objects/stringlib/clinic/*.h.h" header files as generated in
  .gitattributes.

Effects:

* 42 header files generated by AC no longer include the internal C
  API, instead of 4 header files before. For example,
  Modules/clinic/_abc.c.h no longer includes the internal C API.
* Fix _testclinic_depr.c.h: it now always includes pycore_runtime.h
  to get _Py_ID().
@hugovk
Copy link
Member

hugovk commented Nov 9, 2023

Is there more to do for this, or can the issue be closed?

@vstinner
Copy link
Member

vstinner commented Nov 9, 2023

There might be room for improvement: the #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) code is still generated for C code which doesn't define the Py_LIMITED_API macro.

Argument Clinic now generates #include for needed symbols. IMO the situation is less bad than before. Moreover, Argument Clinic now supports the limited C API: when targeting the limited C API, no pycore_ internal header is included, and so the problem is solved for these extensions.

While there is room for improvement, I close the issue: further changes can be done in a even more specific issue.

@vstinner vstinner closed this as completed Nov 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-argument-clinic type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants