Skip to content

python: switch binding library to nanobind - #948

Closed
Doekin wants to merge 5 commits into
zxing-cpp:masterfrom
Doekin:nanobind
Closed

python: switch binding library to nanobind#948
Doekin wants to merge 5 commits into
zxing-cpp:masterfrom
Doekin:nanobind

Conversation

@Doekin

@Doekin Doekin commented May 8, 2025

Copy link
Copy Markdown
Contributor

This PR migrates the Python bindings for zxingcpp from pybind11 to nanobind.

Key Benefits:

  1. Enhanced IDE Support (Autocompletion & Type Hinting):
    The primary driver for this change is nanobind's straightforward support for generating stub files (.pyi). These stubs enable autocompletion and type hinting in IDEs, significantly improving the development experience when using the zxingcpp library.

    439856664-5b6c6dfc-3e86-450a-b75d-fb6ca92cd863

  2. Smaller Binary Sizes

  3. Faster Compilation Times

Important Structural Change:

  • As a result of this migration and to better accommodate the stub files and nanobind's typical project structure, the zxingcpp Python extension has been refactored from a single-file module (e.g., zxingcpp.pyd or zxingcpp.so) into a Python package (a directory named zxingcpp containing an __init__.py and the compiled extension module).

@axxel

axxel commented May 20, 2025

Copy link
Copy Markdown
Collaborator

Sorry for not reacting to your PR so far. This is definitively interesting, I just don't have the time right now to properly look into this. But I will at some point in time.

@Doekin

Doekin commented May 21, 2025

Copy link
Copy Markdown
Contributor Author

No worries, take your time!

@stefan6419846

Copy link
Copy Markdown

Does nanobind require switching the whole build backend from setuptools to scikit-build? If not, what are the reasons for this change and which benefits and side effects does this have?

@axxel

axxel commented Dec 15, 2025

Copy link
Copy Markdown
Collaborator

@Doekin Sorry for letting this PR wait so long without feedback. I plan to make a 2.4 release soonish, so I'm trying to catch up... Are you still around to discuss details? Would you be willing to fix the conflicts? Do have you have something to say to the question from @stefan6419846 ?

@Doekin

Doekin commented Dec 15, 2025

Copy link
Copy Markdown
Contributor Author

Thanks for checking in. Yes, I'll update the PR and fix the conflicts.

As for the build backend: It's not mandatory, but scikit-build-core is the modern standard for CMake-based Python extensions. It offers better integration than setuptools and simplifies the configuration. It is the primary recommendation in the nanobind documentation.

@stefan6419846

Copy link
Copy Markdown

With this changes, it seems like the build is broken - before, building the source distribution worked fine. Running PIP_INDEX_URL=https://pypi.org/simple python3.11 -m build . yields:

* Creating isolated environment: venv+pip...
* Installing packages in isolated environment:
  - nanobind >=1.3.2
  - scikit-build-core >=0.10
  - typing_extensions >=4.12;python_version<"3.11"
* Getting build dependencies for sdist...
* Building sdist...
*** scikit-build-core 0.11.6 (sdist)

Traceback (most recent call last):
  File "/home/stefan/.local/lib/python3.11/site-packages/build/__main__.py", line 178, in _handle_build_error
    yield
  File "/home/stefan/.local/lib/python3.11/site-packages/build/__main__.py", line 429, in main
    built = build_call(
            ^^^^^^^^^^^
  File "/home/stefan/.local/lib/python3.11/site-packages/build/__main__.py", line 276, in build_package_via_sdist
    t.extractall(sdist_out)
  File "/usr/lib64/python3.11/tarfile.py", line 2305, in extractall
    tarinfo, unfiltered = self._get_extract_tarinfo(
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/tarfile.py", line 2394, in _get_extract_tarinfo
    self._handle_fatal_error(e)
  File "/usr/lib64/python3.11/tarfile.py", line 2392, in _get_extract_tarinfo
    filtered = filter_function(unfiltered, path)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/tarfile.py", line 843, in data_filter
    new_attrs = _get_filtered_attrs(member, dest_path, True)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.11/tarfile.py", line 830, in _get_filtered_attrs
    raise LinkOutsideDestinationError(member, target_path)
tarfile.LinkOutsideDestinationError: 'zxing_cpp-2.3.0/LICENSE' would link to '/tmp/LICENSE', which is outside the destination

ERROR 'zxing_cpp-2.3.0/LICENSE' would link to '/tmp/LICENSE', which is outside the destination

@axxel axxel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for coming back to this after this long delay. As you can see, I have a couple of questions.

I'd need to make sure the whole buffer_protocol + __array_interface__ code still works. I'm not sure all uses cases are covered in the tests...

# Target the stable ABI for Python 3.12+, which reduces
# the number of binary wheels that must be built. This
# does nothing on older Python versions
STABLE_ABI

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds interesting. Do you know how the publish-pyhton.yml file would need to change to benefit from that? I'd also like to point out this commit by @chamalgomes. Which is touching on the same issue, at least in terms of build-times.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, cibuildwheel handles the build process automatically without needing much configuration.

Comment thread wrappers/python/CMakeLists.txt Outdated
set(PYBIND11_FINDPYTHON ON) # see https://github.com/pybind/pybind11/issues/4785
zxing_add_package(pybind11 pybind11 https://github.com/pybind/pybind11.git v3.0.1)
# Try to import all Python components potentially needed by nanobind
find_package(Python 3.8

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exactly 3.8?

set(ZXING_PYTHON_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
if (SKBUILD)
set_target_properties(zxingcpp PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this really need to be an in-source-tree build?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't strictly have to be an in-source build. I currently set it up this way primarily to mimic the output directory structure of setup.py.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would that be a good thing to aim for? (sorry for the potentially stupid question)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was to minimize friction for existing users by keeping the output structure consistent with the old setup.py

Comment thread wrappers/python/CMakeLists.txt
Comment thread wrappers/python/CMakeLists.txt Outdated
LIBRARY DESTINATION "${ZXING_PYTHON_INSTALL_LIBDIR}")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/init.py
COMPONENT python
RENAME __init__.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is generated by nanobind, right? Why would they name it init.py when it has to be renamed anyway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is manually added to support the package structure. Since zxingcpp is installed as a package directory containing the extension module, this init.py (renamed to __init__.py during install) ensures import zxingcpp works correctly and avoids import errors when running Python from the source directory.

Comment thread wrappers/python/pyproject.toml Outdated
Comment thread wrappers/python/pyproject.toml Outdated
"pybind11[global]",
]
build-backend = "setuptools.build_meta"
requires = ["scikit-build-core >=0.10", "nanobind >=1.3.2", "typing_extensions >=4.12;python_version<\"3.11\""]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is typing_extension used for and why does the python_version need to be < 3.11?

Comment thread wrappers/python/zxing.cpp
Comment thread wrappers/python/zxing.cpp
Comment thread wrappers/python/zxing.cpp Outdated
@Doekin

Doekin commented Dec 16, 2025

Copy link
Copy Markdown
Contributor Author

OK, I'll try to address these in the next few days.

@Doekin

Doekin commented Dec 16, 2025

Copy link
Copy Markdown
Contributor Author

Re: @stefan6419846 : Perhaps it is the same issue as scikit-build/scikit-build-core#801 ?

@axxel

axxel commented Jan 24, 2026

Copy link
Copy Markdown
Collaborator

I see you have pushed another changeset 4 weeks ago but have not answered any of my questions. Also, as you can see, there have been changes to the python wrapper code due to the new BarcodeFormats implementation. I'm really late with my 3.0 release schedule. It would be very helpful if you could update your PR and reply to those open questions if that code should make it into the release.

@Doekin

Doekin commented Jan 25, 2026

Copy link
Copy Markdown
Contributor Author

Apologies for the silence and the delay. I've been trying to adapt setuptools to work with nanobind, but it turned out to be more complicated than expected.

I also looked into copying the symlinked folders as an alternative, but that approach has its own issues. I am finalizing my findings and will present two possible solutions shortly (later today/tomorrow) for you to decide which is best.

@Doekin
Doekin force-pushed the nanobind branch 4 times, most recently from 1256f0c to 76a8a91 Compare January 25, 2026 18:08
@axxel

axxel commented Jan 25, 2026

Copy link
Copy Markdown
Collaborator

sorry for introducing more conflicts while you are working on it (:/) and thanks for keeping this moving forward.

@Doekin

Doekin commented Jan 25, 2026

Copy link
Copy Markdown
Contributor Author

Strangely, the sdist build now completes without error (I suspect due to updates in the build tools rather than my changes). However, the output still lacks full portability because the symlinks are preserved rather than dereferenced.

@axxel axxel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went through it line by line again and a few new questions came up.

Comment thread wrappers/python/zxing.cpp Outdated
return nb::cast<BarcodeFormats>(formats);
if (nb::isinstance<nb::list>(formats)) {
std::vector<BarcodeFormat> list;
for (auto fmt : nb::cast<nb::list>(formats))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would throw something if the list did actually not contain BarcodeFormat objects, right? Maybe there is an even neater option to directly test if isinstance<nb::vector<BarcodeFormat>> and then cast into it directly?

Comment thread wrappers/python/zxing.cpp Outdated
.returnErrors(return_errors);

if (py::isinstance<ImageView>(_image)) {
if (ImageView _imageview; nb::try_cast(_image, _imageview)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a big deal but I'd find the diff (and the code) more readable if it stayed with the old pattern (isinstance -> cast).

Comment thread wrappers/python/zxing.cpp Outdated
auto adata = ai["data"];

if (py::isinstance<py::buffer>(adata)) {
if (nb::try_cast(ai["data"], arr)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use adata as before? I believe adata is not an unused variable? [here I get the try_cast since you have the arr object already...]

Comment thread wrappers/python/zxing.cpp Outdated
info.strides = py::detail::c_strides(shape, 1);
}
} else if (py::isinstance<py::tuple>(adata)) {
if (arr.ndim() != Size(shape))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since ndim() seems to be size_t, shape.size() is the better call here?

Comment thread wrappers/python/zxing.cpp
} else if (py::isinstance<py::tuple>(adata)) {
if (arr.ndim() != Size(shape))
arr =
nb::ndarray<nb::ro>{arr.data(), shape.size(), shape.data(), nb::find(arr), nullptr, nb::dtype<uint8_t>()};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the full model behind the ownership management of nb::ndarrays but are you sure that tying the lifetime of the newly created object to the one you are destroying with the assignment to 'itself' is doing what you want? I assume there is no option to simply change the shape property of the existing object?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nanobind::ndarray doesn't support in-place shape modification. The key here is the fourth parameter (owner), which is a Python handle. When casting to ndarray, nanobind internally increments the reference counter, ensuring the original object's lifetime is properly managed.

Comment thread wrappers/python/zxing.cpp
true // read-only
};
});
PyType_Slot ImageView_slots[] = {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not mentally fit enough right now to form an opinion on whether or not this is actually a functional replacement of the old code. I guess I need to make sure the unit tests really cover all corner cases...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could add a few tests to convert Image/ImageView to numpy array and OpenCV images and verify the content, basically where the buffer protocol is used.

Comment thread wrappers/python/pyproject.toml Outdated
# "setuptools-scm>=8",
"scikit-build-core >=0.11",
"wheel",
"cmake>=3.18",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is that depencency gone?

Comment thread wrappers/python/CMakeLists.txt Outdated
OPTIONAL_COMPONENTS Development.SABIModule)

# Locate nanobind installed via pip or conda
execute_process(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so find_package(nanobind) does not do this properly?

@stumpylog stumpylog Jan 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my own experiment here, it worked with the Python build jobs, but then failed on the regular build jobs, even with a call to zxing_add_package. I'm not sure why yet. I don't love this either, but that might be the reason for the moment.

In the Python build jobs, the pyproject.toml ensures that nanobind is installed, so find_package just works. It's when the -DZXING_PYTHON_MODULE=ON is set, I think

Comment thread wrappers/python/CMakeLists.txt Outdated
RUNTIME DESTINATION "${ZXING_PYTHON_INSTALL_BINDIR}"
LIBRARY DESTINATION "${ZXING_PYTHON_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${ZXING_PYTHON_INSTALL_LIBDIR}")
COMPONENT python

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert the indentation changes

Comment thread wrappers/python/init.py
@axxel

axxel commented Jan 25, 2026

Copy link
Copy Markdown
Collaborator

Strangely, the sdist build now completes without error (I suspect due to updates in the build tools rather than my changes). However, the output still lacks full portability because the symlinks are preserved rather than dereferenced.

You mean the sdist contains dangling symlinks instead of the sources themselves (and hence is not useful to build the package?) That is an scikit-build issue?

[yes, the broken kn ci-build has nothing to do with your code]

@stumpylog

Copy link
Copy Markdown
Contributor

Regarding the init.py file, I think a better solution would be a file structure like

wrappers/python/zxingcpp/__init__.py
wrappers/python/zxingcpp/py.typed

The built module then becomes _zxingcpp (or any name) and __init__.py merely imports and re-exports from _zxingcpp, such as from zxingcpp._zxingcpp import BarcodeReader. It's much cleaner and more Pythonic, not to mention less brittle than renaming a file, etc.

wrappers/python/zxingcpp/ is also where the generated stub file would be produced

Comment thread wrappers/python/zxing.cpp Outdated
{Py_bf_releasebuffer, (void*)releasebuffer},
{0, nullptr}};

nb::class_<ImageView>(m, "ImageView", nb::type_slots(Image_slots), nb::is_weak_referenceable())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is using Image_slots on ImageView

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not looked into the nanobind doc for how to most naturally manage to return a 'buffer'. From the outside, it looks like this Py_type_slot approach is way below the abstraction level otherwise provided by the library. If you have knowledge on how to improve the situation. Please let us know.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Fixed. It should indeed be ImageView_slots.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link you mentioned describes returning arrays from C++ to Python, which is a different use case. Here, we need to implement the buffer protocol so that Python can access the C++ object's memory directly. This is essential for np.array(image) patterns.

nanobind doesn't provide a higher-level abstraction for this specific functionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info, just to add more background to the others after I did some research:

  1. Use type slots to expose the native buffer protocol, or implement __array__ only for numpy: Alternative to buffer protocol wjakob/nanobind#478 (comment). The doc link is stale and the latest is https://nanobind.readthedocs.io/en/latest/lowlevel.html#customizing-type-creation
  2. Examples: replacing def_buffer wjakob/nanobind#699 (comment)

Comment thread wrappers/python/CMakeLists.txt Outdated
Comment thread wrappers/python/pyproject.toml Outdated
"wheel",
"cmake>=3.18",
"pybind11[global]",
"nanobind >=1.3.2",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just set to the latest?

  • nanobind >=2.11.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here this is a hard build requirement, right? So is it really the best option to require the latest version even when older (potentially locally installed) versions are just fine as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we can lower it to v2.2.0? This version is a good baseline because it introduces support for free-threaded Python 3.13.

We will lose some newer quality-of-life improvements (like the better cast error reporting in v2.9.0), but the core functionality will work just fine. Does v2.2.0 sound like a reasonable compromise?

nanobind Changelog

@CHC383 CHC383 Feb 1, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just my 2 cents:

Insteas of hard build requirements, another angle is to treat this as an alignment to the CMakeList/prod build environment, so that local build aligns more with the production artifact, and I don't see the downsides of keeping build dependencies to the latest except for updating local (virtual) Python environments, including cmake. With that being said, using uv with lock file might serve better on version control and reproducibility.

Or if it is indeed intended for minimum build requirements, we could still start with the current latest (the version this project starts to use and tests) and keep it until we have to update it.

@CHC383

CHC383 commented Feb 4, 2026

Copy link
Copy Markdown
Contributor

Hi @axxel, I wonder how to move this PR forward. There were several review comments not marked as resolved but may be outdated, so it is a bit unclear to me whether this is pending from your side or from @Doekin.

Are there any particular concerns? Any replies/changes you are waiting on? Or if you were just busy with other changes and need to revisit this later. Hopefully this could be made into the 3.0 release, thanks!

@axxel

axxel commented Feb 5, 2026

Copy link
Copy Markdown
Collaborator

Are there any particular concerns? Any replies/changes you are waiting on? Or if you were just busy with other changes and need to revisit this later.

I need to go over the comments again and see what is still relevant. I'd also like to get @stumpylog's work on this incorporated to make sure this is as good as it can get under the current constraints.

Hopefully this could be made into the 3.0 release, thanks!

That is unlikely at this point. I am way behind my intended schedule on this and I want to make sure the 3.0 makes it into the next Ubuntu LTS. I consider this PR as non-critical, since the 2 fundamental improvements it brings (compile time reduction and better IDE discoverability) are both cosmetic in nature. While the risk of breaking something is not obviously 0.

That said, since the main distribution channel for the python package (to my knowledge) is pypi.org, I can easily release this any time later.

@stumpylog

Copy link
Copy Markdown
Contributor

I won't have a lot of time to check anything out for a couple weeks. My main idea would be creating the "proper" package with the init.py file and renaming the binding module to be imported to it. Just to avoid cmake file renames

@axxel

axxel commented Feb 9, 2026

Copy link
Copy Markdown
Collaborator

@Doekin sorry for breaking your PR yet again... Would you be willing to have a look at what @stumpylog was suggesting and already implemented in his fork?

@Doekin

Doekin commented Feb 9, 2026

Copy link
Copy Markdown
Contributor Author

I’ve checked @stumpylog's code and it looks solid.

My only hesitation is that the folder naming might be a bit too "clever" for its own good. I actually managed to trip over my own feet for a while, wondering why my tests weren't reflecting my changes, only to find Python was importing old files from the CWD instead.

axxel added a commit to axxel/zxing-cpp that referenced this pull request May 15, 2026
This is mainly based on the work of @Doekin from zxing-cpp#948 with additions from
@raymondqin and some cherry picked improvemtns from @stumpylog's zxing-cpp#1109.

Co-authored-by: Doekin <Leetimemp@gmail.com>
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
axxel added a commit to axxel/zxing-cpp that referenced this pull request May 16, 2026
This is mainly based on the work of @Doekin from zxing-cpp#948 with additions from
@raymondqin and some cherry picked improvemtns from @stumpylog's zxing-cpp#1109.

Co-authored-by: Doekin <Leetimemp@gmail.com>
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
axxel added a commit to axxel/zxing-cpp that referenced this pull request May 16, 2026
This is mainly based on the work of @Doekin from zxing-cpp#948 with additions from
@raymondqin and some cherry picked improvemtns from @stumpylog's zxing-cpp#1109.

Co-authored-by: Doekin <Leetimemp@gmail.com>
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
axxel added a commit to axxel/zxing-cpp that referenced this pull request May 16, 2026
* replace pybind11 with nanobind
 * automatic pyi generation
* replace setuptools with scikit_build_core
* enable stable ABI builds for python 12+ (only one wheel for those)
* drop win32 wheels
* move cibuildwheel config to pyproject.toml

This is mainly based on the work of @Doekin from zxing-cpp#948 with additions from
@raymondqin and some cherry picked improvemtns from @stumpylog's zxing-cpp#1109.

Co-authored-by: Doekin <Leetimemp@gmail.com>
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
axxel added a commit that referenced this pull request May 17, 2026
* replace pybind11 with nanobind
 * automatic pyi generation
* replace setuptools with scikit_build_core
* enable stable ABI builds for python 12+ (only one wheel for those)
* drop win32 wheels
* drop Python 3.9 wheels
* move cibuildwheel config to pyproject.toml

This is mainly based on the work of @Doekin from #948 with additions from
@raymondqin and some cherry picked improvemtns from @stumpylog's #1109.

Co-authored-by: Doekin <Leetimemp@gmail.com>
Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
@axxel

axxel commented May 17, 2026

Copy link
Copy Markdown
Collaborator

After introducing more conflicts again and with the alternative approach in #1109 to look at as well, I spend the last few days looking closely at the different proposals, the nanobind and the scikit_build_core doc and finally merged something that is based on this PR, takes a few niceties from @stumpylog and simplifies/cleans up the scikit_build_core use and fixes the remaining issues discussed over the last year and a few new ones I discovered while going over it again line by line.

I'm really sorry that it took me so long to properly have a go at this. Thanks @Doekin for working on this.

Anyone interested: please pull the resulting wheels for your platform from here: https://github.com/axxel/zxing-cpp/actions/runs/25968882753#artifacts and let me know if you find any issues with it.

@axxel axxel closed this May 17, 2026
@Doekin

Doekin commented May 17, 2026

Copy link
Copy Markdown
Contributor Author

Pulled the wheels and gave them a spin — looks fine here. Good to see this land.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants