Package management is a hard problem. It relates to Reuse which we also haven’t solved. Package management software assists with handling Dependencies. Versioning is important to get right and is also very hard.
API Design for Humans is also a very important consideration here.
-
https://blog.mgattozzi.dev/package-managers-for-programmers/
- theory design tradeoffs
-
https://medium.com/@sdboyer/so-you-want-to-write-a-package-manager-4ae9c17d9527
- OS/system package manager (SPM): for users
-
Language package manager (LPM): “for both”.
go get
,cabal v1-install
. LPMs without PDMs introduce chaos. -
Project/application dependency manager (PDM): for developers.
cabal build
. Produce self-contained and reproducible source trees.
- https://nvie.com/posts/better-package-management/
- https://en.wikipedia.org/wiki/List_of_software_package_management_systems#Application-level_Dependency_managers
- https://michael.stapelberg.ch/posts/2019-08-17-linux-package-managers-are-slow/
- https://michael.stapelberg.ch/posts/2020-05-09-distri-hermetic-packages/
- https://michael.stapelberg.ch/posts/2019-07-20-hooks-and-triggers/
-
https://michael.stapelberg.ch/posts/2019-05-23-optional-dependencies/
-
If you do decide to make dependencies optional, please:
- Set up automated testing for all code path combinations.
- Fail the build until packagers explicitly pass a –disable flag.
- Tell users their version is missing a dependency at runtime, e.g. in –version.
-
If you do decide to make dependencies optional, please:
-
https://vector-of-bool.github.io/2020/01/06/new-decade.html
- In between the library developers and the library consumers we find the packagers and distributors, and they face issues of their own.
- All three groups have their own subset of issues, and they are all closely related, but no tool that I could find tried to address all three of them in a single swift blow.
- https://vector-of-bool.github.io/docs/dds/design.html
-
https://github.com/vector-of-bool/libman
- Indirection between package manager and build system
-
I consulted with several build system and package manager developers in what they would like to see for the specifics, but there are a few over-arching things to understand about how libman understands libraries:
- A library is the smallest unit of code that can be “used.”
- A library or application may use any number of other libraries.
- Library usage is transitive. If A uses B and B uses C, then A uses C.
- When a library or application is built, the usage requirements of each library that it uses are applied to the invocation of the underlying toolchain.
- How to Herd 1000 Libraries
There’s also toolchain management.
See: https://rustup.rs/ and https://volta.sh/
Project Dependency Management. The way cabal does it is wrong. PVP is broken because it makes the wrong tradeoff. No tooling exists to mitigate the issue.
Public vs Private dependencies (npm calls this peer dependencies).
- https://github.com/rust-lang/cargo/issues/2064
- https://github.com/rust-lang/rust/issues/44663
- https://github.com/rust-lang/rfcs/pull/1977
- https://nodejs.org/en/blog/npm/peer-dependencies/
-
https://stephencoakley.com/2019/04/24/how-rust-solved-dependency-hell
-
what makes it work:
- semver
-
name mangling: name + type + crate + pkg-name + pkg-source + pkg-version + compile time versions + …
- eg., same fn in different versions of the crate are named differently inside the compiler
- Can’t pass objects between different versions of a library
- static variables and global state is duplicated for each library instance; can’t communicate without hacks
- larger binary size
-
https://github.com/dtolnay/semver-trick
-
useful only when:
- a crate needs to break a rarely used API while leaving widely used APIs unchanged
- a crate wants to shuffle types around in its module hierarchy.
- after making a breaking change, release new version of old point release that exports type from new library.
- gracefully handles declaring sameness across multiple major versions of a library
- works because rust allows multiple versions of a package in a dependency tree.
-
useful only when:
-
what makes it work: