Skip to content

Move vendored modules into a vendor directory #129222

Open

Description

@picnixz

Feature or enhancement

Proposal:

In CPython, we have some vendored libraries namely libmpdec, hacl, and expat. Those libraries are meant to be clone of their upstream (think of them as git submodules) and many times have I been exluding them from code search as they usually have non-CPython code involved.

We have a plan to remove vendored libmpdec (#115119) and we're almost here. In the long term, we could also try to unvendor expat (probably not hacl as it's used to implement hash functions fallbacks when OpenSSL is not present).

Affected modules:

  • libmpdec
  • expat
  • _hacl

Some advantages:

  • Easy exclusion of vendored modules from code search.
  • Easy addition and deletion of vendored modules.
  • We don't expect redistributors to edit vendored code (especially not hacl).
  • Hopefully less work than the Python/Programs split
  • Could be using git submodules (though this requires an internet connection, so maybe not)

Some inconvenients:

  • Quite painful refactoring since it would affect existing PRs.
  • Quite painful refactoring since it would affect distributors editing those files.

We can start with some modules that should be kept untouched such as HACL* sources and progressively move the others to reduce the work and conflicts. It doesn't need to happen in one go (for instance, we may well ignore the libmpdec case if we manage to make it unvendored before). I don't think we have much open PRs with expat (by the way, we could have a refresh script for expat to ease maintenance like #126623).

Now, the question is how this could affect downstream redistributors. I'm asking first on Github since I don't know whether they are active on Discourse or not. If everyone tells "it's fine", then I'll ask on Discourse to see if there are more redistributors that could be concerned.

cc

I don't know how moving mimalloc related stuff would affect the free-threaded build in particular, so I'm also going to ask @kumaraditya303 and @colesbury about it. EDIT: Turns out it's a no go for mimalloc as there is some CPython dedicated stuff, so we can put it out of the list (see #129222 (comment)).

For the hacl includes, I can take care of it.

Activity

  1. added
    buildThe build process and cross-build
    type-featureA feature request or enhancement
    on Jan 23, 2025
  2. mhsmith commented on Jan 23, 2025

    @mhsmith
    Member

    Android doesn't do anything special with these libraries, so it shouldn't be affected.

  3. mgorny commented on Jan 23, 2025

    @mgorny
    Contributor

    Gentoo used to remove these libraries entirely, but we don't do that anymore. Which reminds me that I was supposed to fix the issue that prevented us from doing so. Also, I was supposed to see if we can remove them. Days are too short.

  4. ned-deily commented on Jan 23, 2025

    @ned-deily
    Member

    s/nedbat/ned-deily/
    s/universal macOS builds/relocatable build/

    Such a change should have no impact on macOS builds, macOS installer builds, or iOS builds.

  5. picnixz commented on Jan 23, 2025

    @picnixz
    MemberAuthor

    Oups, sorry for mistagging you and for the miswording (forgive my lack of macOS knowledge).

  6. picnixz commented on Jan 23, 2025

    @picnixz
    MemberAuthor

    Er... this is funny but... who should I ask for Ubuntu actually?

  7. hugovk commented on Jan 23, 2025

    @hugovk
    Member

    Bikeshedding: call it _vendor instead of vendor?

    For example, pip and setuptools have _vendor directories.

  8. colesbury commented on Jan 23, 2025

    @colesbury
    Contributor

    Mimalloc has substantial modifications from upstream. Daan Leijen was working on changes to mimalloc to support the features needed by free-threaded CPython upstream, but it's probably going to take a while. Even then, it will require CPython specific build configuration -- it's never going to be something where you can just drop in a shared library provided by the OS.

  9. ned-deily commented on Jan 23, 2025

    @ned-deily
    Member

    @doko42 had/has been the Debian/Ubuntu contact

  10. mgorny commented on Jan 23, 2025

    @mgorny
    Contributor

    Bikeshedding: call it _vendor instead of vendor?

    For example, pip and setuptools have _vendor directories.

    I think the point of _vendor is that it's installed as a Python package but not meant as a public API, so it's not really applicable here.

  11. picnixz commented on Jan 23, 2025

    @picnixz
    MemberAuthor

    Mimalloc has substantial modifications from upstream. Daan Leijen was working on changes to mimalloc to support the features needed by free-threaded CPython upstream, but it's probably going to take a while. Even then, it will require CPython specific build configuration -- it's never going to be something where you can just drop in a shared library provided by the OS.

    Thank you, I wasn't aware of it! I've removed from the list of possible vendored modules.

    Bikeshedding: call it _vendor instead of vendor?

    I don't mind. At least, vendoring modules could be included last (or first) and be well-separated from other includes thanks to their name starting with _. Note that we might have some additional files next to the vendored modules to ease our life (e.g., for HACL, we redefine some names to avoid name clashes, I don't know how it is for other modules).

  12. colesbury commented on Jan 23, 2025

    @colesbury
    Contributor

    Thank you, I wasn't aware of it! I've removed from the list of possible vendored modules.

    It may still make sense to include it in the vendored modules directory. I don't have a strong opinion one way or the other. It depends on what you are primarily trying to communicate with the vendored directory. For example, it's third-party code in terms of license, attribution, and code style. But Linux distributions should probably treat it more like internal CPython code. For example, they should not substitute their own mimalloc package.

  13. zanieb commented on Jan 23, 2025

    @zanieb
    Contributor

    Thanks for the ping!

    I think there would be some minor pain downstream because we have a weird custom build system for the extension modules, but it's fine.

    What about changes like #127932?

  14. picnixz commented on Jan 23, 2025

    @picnixz
    MemberAuthor

    It depends on what you are primarily trying to communicate with the vendored directory

    For me vendored was in the sense of something that is not ours but just a bundled copy of a project to avoid installing separate packages. If it's internal CPython code, even if it heavily relies on an upstream package, I think we can keep it where it is now. Since mimalloc is primarily for free-threading-related stuff, I think it's fine to keep it where it is (it would also avoid the needs of changing the configure script I think, so I don't mind leaving mimalloc alone).

    What about changes like #127932?

    I'm not sure I understand your question but I'll try to reply with what I understood. If the upstream has issues, we can't really change the vendored copy even if we want to because we have some SBOM checks. So we can't just "hotfix" HACL* when we want to (we need to wait for upstream updates). So whether we move it to vendor or not, we would have the same issues.

  15. 4 remaining items

  16. eli-schwartz commented on Jan 23, 2025

    @eli-schwartz
    Contributor

    Could be using git submodules (though this requires an internet connection, so maybe not)

    Cloning the cpython git repo already requires an internet connection. Doing a recursive clone doesn't require more of one.

    The release tarballs should absolutely include the contents of a submodule as well -- in fact you have to since you can't later clone the submodules, Internet connection or not, since there is no submodule metadata.

    The advantage of using submodules is that it becomes very very very clear what is vendored versus what is patched.

    The Meson build system does something similar using "wrap files" built into the core build system, that contain an URL download location for the upstream release tarballs and a checksum, which works even without git metadata. This also means that Meson can distribute your choice of "fat" release tarballs with vendored dependency fallbacks, or "thin" release tarballs with just the wrap definition, and at build time it will download and checksum the vendored dependency only if you don't have a system copy, or conditional on configure options such as "force vendor dependencies for standalone builds" or "forbid vendor dependencies for distro policy". The code to handle this robustly is not trivial, which is why we built it into the core so that it only has to be maintained in a single place. You probably want to stick with submodules.

  17. hroncok commented on Jan 23, 2025

    @hroncok
    Contributor

    Moving the vendored projects to an explicit directory would not impact Fedora/RHEL. We would need to change the paths for those that we rm, but that should be it.

  18. gpshead commented on Jan 23, 2025

    @gpshead
    Member

    If you're bikeshedding the name, github code search already excludes directorys named third_party/ as that is a common industry norm place to put... third party software that you've vendored.

    HACL* belongs specifically with hashlib extension modules so colocating it in a sub-tree under that could would make sense to me, but I'm not picky, it's just a matter of updating include paths and our script that updates the specific version we use.

    Ideal: We'd make a top level third_party/ tree to contain all of these vendored bits in their own subdirectories.

    Doing that would be good for project health IMNSHO rather than scattering stuff around as we do today. re-packagers should appreciate it as well as they each have their own ideas of what they do and don't want to include vs pull from external sources and it makes it more obvious what we've got that could be considered for that.

    Non-goal 1: Vendored things each need their own management in terms of how we get them, update them, and patch them if necessary for our repo. Don't try for a single approach there, it won't fit everything. There may be some commonalities on how that gets done but that kind of thing can be worked out on a case by case basis later.

    Non-goal 2: Vendored things in our tree do NOT need to match upstream. applying patches is part of vendoring. the important thing is to track those patches and automate recreating such changes when updates are needed rather than expecting the next person doing it to fully understand.

  19. gpshead commented on Jan 23, 2025

    @gpshead
    Member

    BTW, the reason pip and setuptools put a _ prefix on their vendor tree is likely to make it clear that it is private in a Python naming sense. The things we vendor within CPython are not Python code. We shouldn't need to do that.

  20. eli-schwartz commented on Jan 23, 2025

    @eli-schwartz
    Contributor

    If you're bikeshedding the name, github code search already excludes directorys named third_party/ as that is a common industry norm place to put... third party software that you've vendored.

    ... or thirdparty/ or third-party/, the latter of which I personally feel I've seen more often than the version with an underscore. :D I wonder if github excludes those too?

  21. picnixz commented on Jan 23, 2025

    @picnixz
    MemberAuthor

    If you're bikeshedding the name, github code search already excludes directorys named third_party/ as that is a common industry norm place to put... third party software that you've vendored.

    Oh... then maybe we can use that name :') If it's supported by Github, I would vote for 'third-party' because I don't need to press shift for _ (and it reads better than thirdparty).

    Non-goal 1: Vendored things each need their own management in terms of how we get them, update them, and patch them if necessary for our repo. Don't try for a single approach there, it won't fit everything. There may be some commonalities on how that gets done but that kind of thing can be worked out on a case by case basis later.

    Yes, that's what I think as well. I don't think we can have a unified approach.

    Non-goal 2: Vendored things in our tree do NOT need to match upstream. applying patches is part of vendoring. the important thing is to track those patches and automate recreating such changes when updates are needed rather than expecting the next person doing it to fully understand.

    I'm ok with this as well. I don't mind having each vendored module with its own patching system (I mean, we're already doing it somehow).


    Now, AFAICT, there doesn't seem to many issues about just moving files which was my primary concern here. I'm no expert in redistribution but since I raised the issue on Discord, I thought it was also good to actually first ask whether this is something that would be interesting for CPython in the long term. And I'd like to thank everyone involved in this (constructive) discussion.

  22. eli-schwartz commented on Jan 23, 2025

    @eli-schwartz
    Contributor

    Ideal: We'd make a top level third_party/ tree to contain all of these vendored bits in their own subdirectories.

    Doing that would be good for project health IMNSHO rather than scattering stuff around as we do today. re-packagers should appreciate it as well as they each have their own ideas of what they do and don't want to include vs pull from external sources and it makes it more obvious what we've got that could be considered for that.

    By the way, Meson explicitly mandates that all "subprojects" (thirdparty code with their own build system that can be autoconfigured) must exist in a single top-level directory (default: subprojects/ but you can define it in your meson.build file if you use a different directory instead) for precisely this reason. It is extremely nice to be able to tell what code is third-party and what code is first-party.

  23. mcepl commented on Jan 27, 2025

    @mcepl
    Contributor

    If the question is just whether the vendored libraries would be concentrated in the one directory called vendor/, then I am all for it. I could run rm -rf over one directory much more easily.

    If the question is how happy I am with the continuing tendency to vendor many libraries and instead of collaborating with the canonical author of the library, use modified version of the third party library, then I am absolutely against, and I consider such action (except for the very temporary important security fixes or such) always wrong. We have then situations like #92875 where only SUSE and RedHat complain about a bug, and because of local modifications it doesn’t show in CI.

  24. eli-schwartz commented on Jan 27, 2025

    @eli-schwartz
    Contributor

    I don't see how that ticket has anything to do with using modified versions of a library.

  25. mcepl commented on Jan 27, 2025

    @mcepl
    Contributor

    I don't see how that ticket has anything to do with using modified versions of a library.

    Modified libraries were mentioned, and generally this ticket has a lot to do with a bigger acceptance of the practice I strongly oppose.

  26. eli-schwartz commented on Jan 27, 2025

    @eli-schwartz
    Contributor

    Sorry but I don't see how you can possibly compare:

    • "the testsuite tries to build another cpython in test_freeze and that one doesn't use --with-system-expat and unconditionally checks for the bundled copy"
    • "the continuing tendency to vendor many libraries and instead of collaborating with the canonical author of the library, use modified version of the third party library"

    If it were a modified version of the third-party library, then the modifications would make it impossible to have a system copy at all. That's an unrelated topic, and is the case for things like mimalloc -- regardless of what directory it is stored in, you and I don't have the option to --with-system-mimalloc and it cannot be deleted and this ticket won't change that at all.

    What is your objection to expat being moved to a different directory?

  27. mcepl commented on Jan 28, 2025

    @mcepl
    Contributor
  28. picnixz commented on Jan 31, 2025

    @picnixz
    MemberAuthor

    If the question is just whether the vendored libraries would be concentrated in the one directory called vendor/, then I am all for it. I could run rm -rf over one directory much more easily.

    That was my main intent. I knew how it could affect downstream redistributors, so I wanted to first know if just moving stuff around is already a problem or not. By centralising what is vendored (possibly patched, possibly amended for our needs, but essentially something that can be thought as an external dependency that does not need additional installation steps), from "pure" CPython code (namely something written from scratch), it would be easier to manage those dependencies (whatever "manage" means here; it can be "maintained", "removed", "patched" or even "added"!)

    If the question is how happy I am with the continuing tendency to vendor many libraries and instead of collaborating with the canonical author of the library, use modified version of the third party library, then I am absolutely against, and I consider such action (except for the very temporary important security fixes or such) always wrong.

    I am personally not in favor of vendoring stuff as it adds unnecessary files that could be found elsewhere as dependencies but deciding whether we continue vendoring stuff or not should be a separate question IMO.


    Maybe a bit more of a context. I was actually fixing UBSan failures and reviewing files in the project tree, hunting for possible UAFs and I was like "oh but those folders are just unnecessary for me, those are vendored stuff" and I wished I didn't need my IDE to render them (though they should be indexed for autocompletion to work if needed). If everything was in a single folder, it would be easier to just exclude them from code search and to also avoid modifying them by mistake. It also makes the project more structured (for instance, I thought that mimalloc was entirely vendored but that wasn't the case so it's also a good thing to know what's ours and what's not).

  29. eli-schwartz commented on Feb 2, 2025

    @eli-schwartz
    Contributor

    but I wanted to make sure that there is a voice registered protesting the general (perhaps just outside CPython, but I see it everywhere) tendency for vendoring (should I name Rust and Go?).

    Ironically enough, both rust and go do NOT use source vendoring at all. They require rebuilding statically linked dependencies in local build tree scope, which is binary vendoring, but fetch it from the canonical source using a language-specific package manager each time... it is again unlike using a vendor directory (for multiple reasons).

    Also, why don’t we have --with-system-mimalloc?

    Because cpython did not simply vendor mimalloc, cpython forked and patched mimalloc and thus it is impossible to build against it even if you try.

    #113141 is a tracking issue discussing those patches, which proposes to get cpython to align with upstream mimalloc sufficient to use a system mimalloc. Please address your comments there instead. :)

  30. mcepl commented on Feb 2, 2025

    @mcepl
    Contributor

    #113141 is a tracking issue discussing those patches, which proposes to get cpython to align with upstream mimalloc sufficient to use a system mimalloc. Please address your comments there instead. :)

    Thank you, I will.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    buildThe build process and cross-buildtype-featureA feature request or enhancement

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions