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

defaultPkgConfigPackages: init #212282

Merged
merged 18 commits into from
Jan 30, 2023
Merged

Conversation

roberth
Copy link
Member

@roberth roberth commented Jan 23, 2023

Description of changes

This is a mapping from pkg-config identifiers to packages, for anyone to use, but most useful for lang2nix tooling.

The initial list is based on cabal2nix from April 2022. It comes with tests to verify that the package actually exposes the expected pkg-config package. I've only had to update the vte package since then, as shown by the running the tests today.

cc @aakropotkin who also maintains a pkg-config mapping
cc @DavHau because probably dream2nix needs this too

Things done
  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 23.05 Release Notes (or backporting 22.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
    • (Release notes changes) Ran nixos/doc/manual/md-to-db.sh to update generated release notes
  • Fits CONTRIBUTING.md.

@roberth
Copy link
Member Author

roberth commented Jan 23, 2023

@ofborg build tests.defaultPkgConfigPackages


- A [setup hook](#setup-hook-pkg-config) bundled with in the `pkg-config` package, to bring a derivation's declared build inputs into the environment.
- The [`validatePkgConfig` setup hook](https://nixos.org/manual/nixpkgs/stable/#validatepkgconfig), for packages that provide pkg-config modules.
- The `pkg-configPackages` package set: a set of aliases, named after the modules they provide. This is meant to be used by language-to-nix integrations. Hand-written packages should use the normal Nixpkgs attribute name instead.
Copy link
Member

Choose a reason for hiding this comment

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

The policy for hand written packages is of course hard to enforce, so it the question is if we should have a non-enforceable policy?

Copy link
Member

Choose a reason for hiding this comment

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

Hmm? What policy? I just see documentation of Nixpkgs' interfaces.

Copy link
Member

Choose a reason for hiding this comment

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

Hand-written packages should use the normal Nixpkgs attribute name instead

Copy link
Member

Choose a reason for hiding this comment

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

Ah, well I wouldn't sweat it. I think this supposed to be more "we're not changing the norms at this time" than "you must do it this way...".

Copy link
Member Author

Choose a reason for hiding this comment

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

A should, not a must. I prefer breaking rules over making rules anyway. Gee that sounds cheesy.

# in order to filter out the unsupported packages without throwing any errors
# tryEval would be too fragile, masking different problems as if they're
# unsupported platform problems.
allPkgs = import ../top-level {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
allPkgs = import ../top-level {
allPkgs = import pkgs.path {

Copy link
Member Author

Choose a reason for hiding this comment

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

That risks copying a path to the store. pkgs.path is too complicated for me; most imports happen by path expression, which is known to work well.

# Make sure licensing info etc is preserved, as this is a concern for e.g. cache.nixos.org,
# as hydra can't check this meta info in dependencies.
# The test itself is just Nixpkgs, with MIT license.
// builtins.intersectAttrs
Copy link
Member

Choose a reason for hiding this comment

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

I'd just update the meta of the source package instead which seems more comprehensible – hydra will behave the same for both (i.e. pkg.meta // { description = … ; }). The new meta set is run through mkDerivation anyways.

Copy link
Member Author

Choose a reason for hiding this comment

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

It isn't equivalent to the original package though, so I'd rather be conservative in terms of what we inherit. For example, the description would be wrong. For instance, your suggestion would copy the longDescription, which is wrong.

@sternenseemann
Copy link
Member

sternenseemann commented Jan 25, 2023

cc @Ericson2314 who has also been working towards a (different?) solution of this problem.

Edit: See https://github.com/nixpkgs-architecture/issues/issues/14.

@Ericson2314
Copy link
Member

Ericson2314 commented Jan 25, 2023

I didn't work any implementation yet, so this is great!

Can we add tests / meta to the individual packages saying what pkg-config they provide? Then, as a prelude to generating the global mapping, we can at least assert that it matches what the individual packages say.

tests = {
# NB: this may test a different variant of zlib than the package that
# carries this `tests` attribute, due to overriding.
pkg-configPackages = tests.pkg-configPackages.zlib;
Copy link
Member

@Ericson2314 Ericson2314 Jan 25, 2023

Choose a reason for hiding this comment

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

I would rather this call makePkgConfigTest, and then tests.pkg-configPackages gathers these to run all of them. That is I think better layering, but concretely it allows the tests for individual packages to be built regardless of the package set in question.

Copy link
Member Author

Choose a reason for hiding this comment

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

The point is exactly to violate layering, so that ofborg will test the relevant bit of pkg-configPackages when it's time to do so. I think this is the best we can achieve with the tooling we have, if we put in the effort.

Copy link
Member Author

@roberth roberth Jan 25, 2023

Choose a reason for hiding this comment

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

Maybe we should just ignore this idea and rely on asynchronous testing of the whole pkg-configPackages on hydra.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I don't know the details of ofborg, but I thought the overriding was just for the top-level tests? I would think if the individual package is an unsupported systems, then ofborg would just skip the test too, which is fine?

Copy link
Member Author

Choose a reason for hiding this comment

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

I've factored out the tester into a properly tested and documented tester.

@@ -0,0 +1,202 @@
/* A set of aliases to be used in generated expressions.

In case of ambiguity, this will pick a sensible default.
Copy link
Member

Choose a reason for hiding this comment

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

I think we should provide all packages that match, something like one of:

pkgConfigName = [ pkg0 pkg1 ];
pkgConfigName = { inherit pkg0 pkg1; };

A key idea of pkg-config is that it tracks interfaces not implementations.

Copy link
Member Author

Choose a reason for hiding this comment

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

My intent is for this to be a slightly curated set of packages, providing defaults for lang2nix integrations. Adding multiple versions / variants / ... here will add a lot more churn and will confuse lang2nix integrations that don't have a means to pick one. I feel like this would be more suitable for a version 2.

How about I call this package set defaultPkgConfigPackages instead? That will leave room for a fancier implementation with a nice name.

Copy link
Member

@Ericson2314 Ericson2314 Jan 25, 2023

Choose a reason for hiding this comment

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

@roberth sounds good! The complete one can be autogenerated.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

The list data is in a .json now that can be evolved if needed. It's already quite extensible because it uses records wherever it can; top-level and in each module. It also has a top-level version field just in case.

@roberth
Copy link
Member Author

roberth commented Jan 25, 2023

@Ericson2314

Can we add tests / meta to the individual packages saying what pkg-config they provide?

A meta attribute should not be part of the derivation.

Then, as a prelude to generating the global mapping, we can at least assert that it matches what the individual packages say.

So then it should be part of the derivation, or we should generate a tests attribute for it.

Doing this kind of automatic stuff isn't really feasible in the current architecture, as hooks can, by nature, not affect the attribute set. If packages were modules, this would have a fantastic ui:

imports = [ pkgModules.pkg-config ];
pkg-config.export = [ "nix-expr" "nix-store" ];

pkgModules.pkg-config can then touch all the attributes it needs to, whether that's the package meta, tests, or adding an installCheck hook in the derivation.

Alternatively, we'd have to add this logic to mkDerivation itself, which I feel would make things worse.

Doing it in this PR would blow up the scope. It's already tested, just differently, so I don't think it should be a blocker.

@roberth roberth changed the title pkg-configPackages: init defaultPkgConfigPackages: init Jan 25, 2023
@Ericson2314
Copy link
Member

@roberth Maybe I am confused, I thought yes the derivation doesn't get access to meta, but self in tests = ...self... still can via #119942?

@Ericson2314
Copy link
Member

We'd have

meta.pkg-config = [ "nix-store" "nix-expr" ];
tests.pkg-config = makePkgConfigTest self;

and makePkgConfigTest can pull out meta.pkg-config.

@roberth
Copy link
Member Author

roberth commented Jan 25, 2023

#119942

We'd have

meta.pkg-config = [ "nix-store" "nix-expr" ];
tests.pkg-config = makePkgConfigTest self;

and makePkgConfigTest can pull out meta.pkg-config.

That looks like it'd work, yes. It's a bit more manual than I'd like, but it's feasible, at least for the places where self is "available". That's probably most C/C++ packages anyway, because it's only the language-specific mkDerivation wrappers of which some don't support it yet.

Nonetheless, I'd like to leave that as future work. My goal here is really to get the ball rolling. I can't spend a lot of time on this.

@roberth
Copy link
Member Author

roberth commented Jan 25, 2023

Both ways of testing are independent, have different goals despite their similarity, and that we should eventually do both.

  • test the package set pkgs.defaultPkgConfig.nix-expr refers to a package that exposes nix-expr.pc
  • test a package let foolib = zlib.overrideAttrs xyz; in foolib exposes zlib.pc.

There's overlap in part of the implementation, but they are different subjects.

Copy link
Member

@Ericson2314 Ericson2314 left a comment

Choose a reason for hiding this comment

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

I am happy to do that as follow-up then.

@sternenseemann
Copy link
Member

sternenseemann commented Jan 26, 2023

Maybe we should take a step back and deliberate if a package set is the best option? In what situations do we actually need it?

If we have a lookup table lang2nix tools can use, that would work, too, and that generated expressions would be more overrideable. What bugs me right now that cabal2nix would with this solution generate an expression taking defaultPkgConfigPackages as an input for zlib. This is very annoying to override, not easy to introspect and assymetrical, since as soon as pkg-config would not be used (instead, e.g. extra-libraries), zlib would appear in the argument list again.

@roberth
Copy link
Member Author

roberth commented Jan 26, 2023

If you want json, the file can be converted and loaded with some functions. The package set and the generated tests are useful components of the json solution as well.
The tester can be extracted into a pkgs.testers tester if you're concerned about passthru tests. I've already removed the zlib example.

@DavHau
Copy link
Member

DavHau commented Jan 28, 2023

If you want json, the file can be converted and loaded with some functions

I think that would be a good change. Having it as a .nix function restricts usage unnecessarily. Examples:

  • lang2nix pipelines aren't necessarily implemented in pure nix. They might need to access the data from another language, which is hard, if the data can only be accessed by evaluating .nix code.
  • Overridability: Hiding information behind functions seems to be a cause of anit-patterns like override, overrideAttrs. If the information is a simple mapping, let's expose it as such. This can only make it more flexible and doesn't cost us much.

@roberth
Copy link
Member Author

roberth commented Jan 29, 2023

There's overlap in part of the implementation, but they are different subjects.

The overlapped part is now testers.hasPkgConfigModule.

json

Done.

@ofborg build tests.testers.hasPkgConfigModule
@ofborg build tests.pkg-config.defaultPkgConfigPackages.ncurses
@ofborg build defaultPkgConfigPackages.libpng

By allowing null, we allow code to avoid filterAttrs, improving
laziness in real world use cases.
Specifically, this strategy prevents infinite recursion errors,
performance issues and possibly other errors that are unrelated to
the user's code.
@roberth roberth marked this pull request as ready for review January 30, 2023 00:10
@roberth roberth merged commit 663c41a into NixOS:master Jan 30, 2023
@K900
Copy link
Contributor

K900 commented Jan 30, 2023

This broke Hydra: https://hydra.nixos.org/build/207340888/nixlog/114

@vcunat
Copy link
Member

vcunat commented Jan 30, 2023

Yes, f192e96 in particular. Channel blocked again because of that.

@vcunat
Copy link
Member

vcunat commented Jan 30, 2023

Ah, it was reverted already in PR #213615

@Ericson2314
Copy link
Member

#214304

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/adding-pkg-config-metadata-to-nixpkgs-packages/25281/1

r=$?
set -e
if [[ $r = 0 ]]; then
echo "✅ pkg-config module $moduleName exists and has version $version"
Copy link
Member

Choose a reason for hiding this comment

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

First time I see some unicode in setup tooks and I am surprised that no one complained yet.

@infinisil infinisil added the significant Novel ideas, large API changes, notable refactorings, issues with RFC potential, etc. label Apr 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
8.has: documentation 8.has: package (new) 10.rebuild-darwin: 101-500 10.rebuild-linux: 101-500 significant Novel ideas, large API changes, notable refactorings, issues with RFC potential, etc.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants