Instead of cproto
, use clang.cindex
from Python to create prototype declaration files (.pro) from source code.
I'm working on Ubuntu 24.04.
$ sudo apt-get update $ sudo apt-get install -y python3 python3-pip clang libclang-dev python3-clang
https://github.com/vim/vim/pull/18045
(19 files)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
@chrisbra and Vim members,
What do you think of this approach?
Although make proto
depends on python and clang, I think it's better than continuing to use cproto
.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
@h-east pushed 11 commits.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
@h-east pushed 8 commits.
You are receiving this because you are subscribed to this thread.
@yegappan commented on this pull request.
In src/indent.c:
> @@ -474,7 +474,7 @@ get_indent_str( return count; } -#ifdef FEAT_VARTABS +#if defined(FEAT_VARTABS) || defined(PROTO)
One suggestion: it might be easier to track the changes later, if you can separate out the changes related to the "PROTO" checks into one PR and the changes for the new script into another PR.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@h-east commented on this pull request.
In src/indent.c:
> @@ -474,7 +474,7 @@ get_indent_str( return count; } -#ifdef FEAT_VARTABS +#if defined(FEAT_VARTABS) || defined(PROTO)
Around the same time you commented, I submitted a PR implementing your suggestion 👍
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Does this work in all platforms? And does it still require us to do all the typedef's in say os_mswin.c
(e.g. typedef int BOOL;
) or the declarations in struct.h
(e.g. typedef long varnumber_T;
).
If the answer is no, then I wonder what the point of switching to a separate Python script is?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
The answer is “Yes.” I’m still experimenting, but my goal is to get the same output in any environment where Python and Clang are available. It’s impossible to do this with a truly accurate parser, so I’m switching to an approach that detects “something like a function definition” and then generates its prototype declaration as-is.
If this works, we won’t need the PROTO
definitions themselves nor the hacky consistency-forcing code for cproto
that you mentioned.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@h-east pushed 9 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 4 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 2 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 9 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 3 commits.
You are receiving this because you are subscribed to this thread.
I think it's almost finished.
I've confirmed that proto/*.pro
outputs the same thing on Ubuntu 24.04 and Windows 11 (with Git Bash).
ALL>
I have a request for everyone:
Could you please let me know if there are any differences when running make proto
in your environment?
The setup for the execution environment is written in src/Makefile
. (See below)
I would be happy to gather information from various platforms. Thank you.
# Generate function prototypes. Previously, cproto was used, but since there
# was a lot of fiddling to do to generate them correctly, so we switched to a
# Python script using libclang. It has the following features:
# - Only the bare minimum of macro definitions is required.
# - Generates the same .pro file even across different operating systems.
# (maybe)
#
# How to set up environment to run `make proto`
# On Ubuntu 24.04:
# - Install libclang
# Use the package provided by Ubuntu.
# $ sudo apt install python3-clang
# Or, Create venv (if you want to use it freely with pip)
# $ python3 -m venv ~/venv
# $ source ~/venv/bin/activate
# $ pip install --upgrade pip
# $ pip install libclang
# On Windows 11 (using Git Bash):
# - Install GNU Make 3.81 or later.
# - Download and install Python from the Python official website.
# - Install libclang
# $ python -m pip install libclang
# - Change the following lines in this file:
# s/^PYTHON=python3/PYTHON=python/
# s/^tags TAGS: notags/tags: notags/
PYTHON=python3
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
it seems to work better for me, does no longer depend on the current configure options, although the build dependencies are much heavier.
I have 2 questions:
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
although the build dependencies are much heavier.
What part of the behavior does this refer to specifically?
I have 2 questions:
* Can we make it true dependencies? So it only generates the proto files, if there are changes?
Does this mean, for example, that when alloc.c is updated, make
should update proto/alloc.pro?
The original make proto
was separate from make
, so I gave it a similar structure.
The new make proto
depends on Python and libclang. If I implement the above suggestion, even make
will depend on Python and libclang. Is this okay?
Or does it mean that it only updates the .pro files that correspond to the .c files that are updated when make proto
is executed?
Hmm, make proto
isn't something that is executed that often, so I think it's fine to leave it as it is (updating all .pro files).
(It's just that writing the dependencies is a hassle. 😅)
* I think we can get rid of this block here:
Done. Thanks.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Or does it mean that it only updates the .pro files that correspond to the .c files that are updated when make proto is executed?
I'm working on above.
Final confirmation is underway.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
@h-east pushed 5 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 5 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 6 commits.
You are receiving this because you are subscribed to this thread.
Or does it mean that it only updates the .pro files that correspond to the .c files that are updated when make proto is executed?
I'm working on above. Final confirmation is underway.
Done !!
@ychin
Could you please tell me the results of make protoclean; make proto
on macOS using the following as a reference?
#18045 (comment)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
@h-east pushed 5 commits.
You are receiving this because you are subscribed to this thread.
@chrisbra
No one has checked it, but if it works fine in your environment, I think it's fine to merge it in. At least you can run make proto
on major/minor releases.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Thanks, it is quite nice. Can you add something like the following on top of it, so that it runs in CI automatically and verifies the proto files are always up to date?
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 004f4a622..b408d8569 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,7 +84,7 @@ jobs: architecture: arm64 - features: normal compiler: gcc - extra: [vimtags] + extra: [vimtags, proto] - features: huge compiler: gcc extra: [no_x11] @@ -182,6 +182,9 @@ jobs: libattr1-dev ) fi + if ${{ contains(matrix.extra, 'proto') }}; then + PKGS+=( python3-clang ) + fi sudo apt-get update && sudo apt-get upgrade -y --allow-downgrades && sudo apt-get install -y --allow-downgrades "${PKGS[@]}" - name: Install gcc-${{ env.GCC_VER }} @@ -270,6 +273,9 @@ jobs: if ${{ contains(matrix.extra, 'vimtags') }}; then echo "TEST=-C runtime/doc vimtags VIMEXE=../../${SRCDIR}/vim" fi + if ${{ contains(matrix.extra, 'proto') }}; then + echo "TEST=-C src proto" + fi echo "CFLAGS=${CFLAGS}" echo "CONFOPT=${CONFOPT}" # Disables GTK attempt to integrate with the accessibility service that does run in CI. @@ -354,6 +360,15 @@ jobs: true ) + - name: Generate Proto files + if: contains(matrix.extra, 'proto') + run: | + # This will exit with an error code if the generated proto files differ from source + ( + git diff --exit-code -- src/proto/ + true + ) + - name: Generate gcov files if: matrix.coverage run: |
(untested)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
On my machine (macOS 12.7.6) after installing libclang
in a Python virtual environment, make protoclean && make proto
ran from src
(but not the top-level…).
It reran the configure
script, which was unexpected to me as a passive follower of this topic (I'm not sure which configure options were picked up or used).
The resulting working tree was clean (no files were modified according to git status
).
I used commit 3b682f5 (Merge 63f746d into 3495936, 2025-10-02) generated automatically by GitHub as refs/pull/18045/merge
from this PR at 63f746d (Added a mechanism to update only the target .pro by adding a dependency between .pro and .c, 2025-09-29).
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
It reran the
configure
script, which was unexpected to me as a passive follower of this topic (I'm not sure which configure options were picked up or used).I updated the path names for
TCL_PRO
andPERL_PRO
insrc/configure.ac
andsrc/auto/configure
, so it's normal for configure to run on the first attempt. (I'll also review the settings forLUA_PRO
,MZSCHEME_PRO
, andRUBY_PRO
.)
Ah, gotcha, good to know!
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Thanks for confirming.
On my machine (macOS 12.7.6) after installing
libclang
in a Python virtual environment,make protoclean && make proto
ran fromsrc
(but not the top-level…).
It reran the
configure
script, which was unexpected to me as a passive follower of this topic (I'm not sure which configure options were picked up or used).
I updated the path names for TCL_PRO
and PERL_PRO
in src/configure.ac
and src/auto/configure
, so it's normal for configure to run on the first attempt. (I'll also review the settings for LUA_PRO
, MZSCHEME_PRO
, and RUBY_PRO
.)
The resulting working tree was clean (no files were modified according to
git status
).
Since everything worked without issues, I'm relieved.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@chrisbra and Vim members, What do you think of this approach? Although
make proto
depends on python and clang, I think it's better than continuing to usecproto
.
@h-east can you elaborate on why you think this is better than using cproto
? Which cproto
shortcomings are you working to rid us of?
The python program appears to be using regular expressions to parse pre-processor directives, translating them to python code, so that it can eval
the conditions. It is an impressive feat but it requires pretty substantial expertise with both C and python to work on. Also, it seems to me we already have a tool to evaluate those pre-processor conditions: the C pre-processor. Why not run the source files through cpp
and parse that with the clang parser?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Thank you for your question.
The main goal of gen_prototypes.py
is to improve the consistency and maintainability of the generated .pro
files.
There are several long-standing issues with the current cproto
-based approach.
cproto
cproto
has long been discontinued, so no further updates or fixes are expected.-I
, cproto
fails to parse and produces no .pro
files.src/Makefile
to make cproto
work correctly.make proto
currently does not work properly.These issues make maintaining and reproducing consistent results with cproto
increasingly difficult.
By using libclang
, we can parse source code with the same accuracy as a real C compiler.
This allows us to reliably extract return types, argument types, and qualifiers, eliminating discrepancies between Vim's source code and the generated prototypes.
cpp
?gen_prototypes.py
implements its own lightweight handling of preprocessor directives only to keep the generated output consistent across all platforms.
make proto
to be identical regardless of the results of ./configure
.cpp
would require defining all relevant macros for every platform, which is cumbersome.In summary, combining Clang's precise parsing with minimal preprocessing logic in Python allows us to produce reliable, reproducible proto files across all platforms, without depending on cproto
's legacy behavior.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@h-east pushed 3 commits.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
@dvogel commented on this pull request.
Thanks for the full explanation of your motivations here @h-east. I did my best to condense it down into a comment at the top of the program because I think it will be very helpful to maintain momentum here.
I think some minimal level of automated tests will be needed to help others maintain this. cproto
had a collection of tests that allowed it's output to be verified. Perhaps those could be ported over here.
In src/proto/gen_prototypes.py:
> @@ -0,0 +1,462 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import os⬇️ Suggested change
-import os + +# The main goal of gen_prototypes.py is to provide .pro files that are generated consistently +# across platforms, thereby making them easier to maintain. This replaced the cproto project +# because (a) it became unmaintained, (b) had too many system-wide include path +# dependencies, and (c) did not run on macos. +# +# libclang is used to reliably parse the C source code with the same accuracy as the compiler. +# The parsed code is then scanned for pre-processor directives and dynamically translated to +# python code that can be evaluated. This approach allows the translation to be done without +# defining all macros (which would be required for evaluation with cpp) and without concern +# for the developer's most recently generated build configuration. + +import os
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
Thank you.
Automated testing (CI) was also suggested by ChrisBra, so yesterday I committed a trial implementation. It's currently producing duplicate output, but I plan to fix it eventually.
#18045 (comment)
https://github.com/vim/vim/actions/runs/18284424132/job/52055491680?pr=18045#step:21:221
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Confirm that the expected proto error appears. OK
image.png (view on web)—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
@h-east pushed 8 commits.
You are receiving this because you are subscribed to this thread.
@h-east pushed 6 commits.
You are receiving this because you are subscribed to this thread.
@chrisbra Ready to merge 👍
I think it's fine to add various documentation and code comments later.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@h-east pushed 1 commit.
—
View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.
thanks
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Hi, I haven't been keeping up-to-date with this but I just pulled Vim and this doesn't even build…
The error message looks like this:
Traceback (most recent call last):
gcc -c -I. -Ilibvterm/include -Iproto -DHAVE_CONFIG_H -DMACOS_X -DMACOS_X_DARWIN -I/opt/homebrew/Cellar/libsodium/1.0.20/include -g -O2 -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -DINLINE="" -DVSNPRINTF=vim_vsnprintf -DSNPRINTF=vim_snprintf -DIS_COMBINING_FUNCTION=utf_iscomposing_uint -DWCWIDTH_FUNCTION=utf_uint2cells -o objects/vterm_screen.o libvterm/src/screen.c
File "/Users/ychin/Dev/external/vim/src/proto/gen_prototypes.py", line 39, in <module>
from clang.cindex import Index, CursorKind, StorageClass, TokenKind
ModuleNotFoundError: No module named 'clang'
make[1]: *** [proto/gui_beval.pro] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [first] Error 2
For reference the build steps was make distclean && ./configure && make
, the most bog-standard way to build Vim cleanly.
Seems like every single build is now calling gen_prototypes.py
, which uses the clang
dependency. This is a completely new build requirement. Is this intentional? I thought this is just run on CI to make sure the prototypes match? Why are we forcing a new build dependency on everyone who just wants to build Vim without prior notice?
Can we revert this if a fix cannot be found quickly?
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.
@ychin Sorry, see below links.
#18523 (comment)
#18523 (comment)
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.
Thanks for fixing it.
—
Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.