Skip to content

Support using system llhttp library (#10759) #10760

New issue

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

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

Already on ? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

mgorny
Copy link
Contributor

@mgorny mgorny commented Apr 20, 2025

What do these changes do?

Add a new USE_SYSTEM_DEPS environment variable that can be used to enable building against the system install of llhttp library rather than the vendored one.

This is implemented using the pkgconfig package to query llhttp install via pkg-config. The package is only used when USE_SYSTEM_DEPS is enabled, however due to limitations of pyproject.toml it is listed unconditionally as a build dependency. That said, flake8 claims that the dependency is not listed and I don't really know how to solve that:

setup.py:36:5: I900 'pkgconfig' not listed as a requirement

I have also updated aiohttp/_cparser.pxd to reference the llhttp.h header via its name rather than full path. I have poisoned the system header to confirm that the correct header is used both when building against the system library and the vendored library.

Are there changes in behavior for the user?

  • no changes for users installing from wheels
  • users installing from source will see an additional pkgconfig build requirement
  • users installing from source who enable USE_SYSTEM_DEPS will be using the system llhttp library

Is it a substantial burden for the maintainers to support this?

I don't think so. The code uses pkg-config, so it should be pretty forward-secure to potentially nonstandard llhttp installs. On top of that, presumably the feature will be primarily used by downstreams / expert users, who would rather be willing to submit fixes, should any issues arise (though that implies the burden of reviewing them).

Related issue number

Discussion #10759.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
    • The format is <Name> <Surname>.
    • Please keep alphabetical order, the file is sorted by names.
  • Add a new news fragment into the CHANGES/ folder
    • name it <issue_or_pr_num>.<type>.rst (e.g. 588.bugfix.rst)

    • if you don't have an issue number, change it to the pull request
      number after creating the PR

      • .bugfix: A bug fix for something the maintainers deemed an
        improper undesired behavior that got corrected to match
        pre-agreed expectations.
      • .feature: A new behavior, public APIs. That sort of stuff.
      • .deprecation: A declaration of future API removals and breaking
        changes in behavior.
      • .breaking: When something public is removed in a breaking way.
        Could be deprecated in an earlier release.
      • .doc: Notable updates to the documentation structure or build
        process.
      • .packaging: Notes for downstreams about unobvious side effects
        and tooling. Changes in the test invocation considerations and
        runtime assumptions.
      • .contrib: Stuff that affects the contributor experience. e.g.
        Running tests, building the docs, setting up the development
        environment.
      • .misc: Changes that are hard to assign to any of the above
        categories.
    • Make sure to use full sentences with correct case and punctuation,
      for example:

      Fixed issue with non-ascii contents in doctest text files
      -- by :user:`contributor-gh-handle`.

      Use the past tense or the present tense a non-imperative mood,
      referring to what's changed compared to the last released version
      of this project.

Add a new `USE_SYSTEM_DEPS` environment variable that can be used
to enable building against the system install of llhttp library rather
than the vendored one.

This is implemented using the `pkgconfig` package to query llhttp
install via pkg-config.  The package is only used when `USE_SYSTEM_DEPS`
is enabled, however due to limitations of `pyproject.toml` it is listed
unconditionally as a build dependency.  That said, flake8 claims that
the dependency is not listed and I don't really know how to solve that:

```
setup.py:36:5: I900 'pkgconfig' not listed as a requirement
```

I have also updated `aiohttp/_cparser.pxd` to reference the `llhttp.h`
header via its name rather than full path.  I have poisoned the system
header to confirm that the correct header is used both when building
against the system library and the vendored library.
@psf-chronographerpsf-chronographer bot added the bot:chronographer:providedThere is a change note present in this PRlabel Apr 20, 2025
@@ -17,7 +18,11 @@
NO_EXTENSIONS = True


if IS_GIT_REPO and not (HERE / "vendor/llhttp/README.md").exists():
if (
not USE_SYSTEM_DEPS
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically, I think this block does not need to be executed with NO_EXTENSIONS but I didn't change the existing behavior. Please let me know if you prefer that I changed that.

@@ -26,19 +31,37 @@

# NOTE: makefile cythonizes all Cython modules

if USE_SYSTEM_DEPS:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alternatively, I could also add and not NO_EXTENSIONS here, to avoid calling pkg-config when we're not building extensions (though technically speaking, the other branch is also unnecessary then). That said, I'm not sure if we really need to special-case the case of setting USE_SYSTEM_DEPS when no extensions are built.

@codspeed-hqCodSpeed HQ
Copy link

codspeed-hq bot commented Apr 20, 2025

CodSpeed Performance Report

Merging #10760 will not alter performance

Comparing mgorny:system-llhttp (7ce83ea) with master (f626aeb)

Summary

✅ 58 untouched benchmarks

@codecovCodecov
Copy link

codecov bot commented Apr 20, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.72%. Comparing base (b97d6bf) to head (c9d281c).
Report is 20 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master   #10760   +/-   ##
=======================================
  Coverage   98.72%   98.72%           
=======================================
  Files         125      125           
  Lines       37793    37858   +65     
  Branches     2085     2091    +6     
=======================================
+ Hits        37310    37375   +65     
  Misses        335      335           
  Partials      148      148           
FlagCoverage Δ
CI-GHA98.60% <ø> (+<0.01%)⬆️
OS-Linux98.27% <ø> (+<0.01%)⬆️
OS-Windows96.20% <ø> (-0.04%)⬇️
OS-macOS97.39% <ø> (+<0.01%)⬆️
Py-3.10.1197.31% <ø> (+<0.01%)⬆️
Py-3.10.1797.84% <ø> (-0.01%)⬇️
Py-3.11.1297.91% <ø> (-0.01%)⬇️
Py-3.11.997.39% <ø> (+<0.01%)⬆️
Py-3.12.1098.03% <ø> (-0.01%)⬇️
Py-3.12.997.51% <ø> (-0.01%)⬇️
Py-3.13.297.49% <ø> (+<0.01%)⬆️
Py-3.13.398.03% <ø> (-0.01%)⬇️
Py-3.9.1397.18% <ø> (+<0.01%)⬆️
Py-3.9.2297.70% <ø> (-0.01%)⬇️
Py-pypy7.3.1685.73% <ø> (-8.15%)⬇️
VM-macos97.39% <ø> (+<0.01%)⬆️
VM-ubuntu98.27% <ø> (+<0.01%)⬆️
VM-windows96.20% <ø> (-0.04%)⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@webknjaz webknjaz left a comment

Choose a reason for hiding this comment

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

In general, I'd like this wired via PEP 517 config settings but that's something to implement after redoing packaging similar to yarl. So it's out of the scope.

As for isort, there might be configs you'd need to add the new lib in.

@@ -1,6 +1,7 @@
[build-system]
requires = [
"setuptools >= 46.4.0",
"pkgconfig",
Copy link
Member

Choose a reason for hiding this comment

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

Can we keep this list sorted? Is there a minimum version we'd need?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. My idea was to keep setuptools first since it's the backend (i.e. the primary dependency), but I can change order, no problem.

I don't think we do need a minimal version. The two functions we're using are available since the first release, 0.1.0. I've just tried forcing == 0.1.0 and the build succeeded.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, makes sense. I often make this separation by having an empty line and adding code comments marking essential and plugin sections of the list. But since it wasn't here, I forgot about that habit :)

setup.py Outdated
@@ -8,6 +8,7 @@
raise RuntimeError("aiohttp 4.x requires Python 3.9+")


USE_SYSTEM_DEPS: bool = bool(os.environ.get("USE_SYSTEM_DEPS"))
Copy link
Member

Choose a reason for hiding this comment

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

This should be specific to aiohttp since we don't want generic vars to influence our builds unexpectedly.

Copy link
Contributor Author

@mgorny mgorny Apr 21, 2025

Choose a reason for hiding this comment

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

Well, I can do that. However, what we're trying to do (in general, see the linked doc) is to standardize on a "common" environment variable that distributions can use to disable all vendored libraries altogether — i.e. following the principle "it's better for the build to fail than for us to miss a vendored library". However, if these are eventually going to be replaced by config_settings, I suppose it's a lost cause anyway.

Copy link
Member

Choose a reason for hiding this comment

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

In that case, I'd suggest having two env vars — one scoped and one global.

I might be able to preserve this during refactoring. I don't even have a timeline so let's not worry about it now.

On a side note, I've been meaning to explore better ways of configuring linking in similarly packaged projects. Namely, ansible-pylibssh. There, I have expandvars integrated and a way to have externally set compiler vars like CFLAGS. And so the build automation is able to set those independently.
I feel like it might be a good approach and would be more generic. That project doesn't graft libssh into the source tree, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done (i.e. added fallback to USE_SYSTEM_DEPS when AIOHTTP_USE_SYSTEM_DEPS is not set).

Copy link
Member

Choose a reason for hiding this comment

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

mgorny and others added 3 commits April 22, 2025 03:26
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <[email protected]>
Sign up for free to join this conversation on . Already have an account? Sign in to comment
Labels
bot:chronographer:providedThere is a change note present in this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants