Skip to content

Instantly share code, notes, and snippets.

@ahmetsait
Last active September 30, 2021 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ahmetsait/10925a246b0d412a698e927658f3f363 to your computer and use it in GitHub Desktop.
Save ahmetsait/10925a246b0d412a698e927658f3f363 to your computer and use it in GitHub Desktop.

Improve Dub: Solve Dependency Hell

Research on Alternative Approaches

From what I could find using my google-fu;

Maven selects whichever version is closest to the head in the dependency tree¹. Users can include a specific dependency version in the main application to override any sub-package version choice.

Gradle has so called rich version constraints² that can be used to make dependency resolution more strict or relaxed. If version range is defined to be "strict" than it will halt building in case of a conflict similar to Dub.

CLR (Common Language Runtime) allows two versions of the same assembly to be loaded³. I suspect it is very similar to how Rust works but I did not dive into further details.

I believe Rust's approach to solving dependency hell is by far the best path forward.

Milestone Overview

  1. Implement a DMD switch for mangling and referencing symbols with an additional prefix
    -mangle-prefix=path/to/common/package:v2
    Relevant work for this milestone will be on mangle-prefix branch of my dmd fork.
    How it works: With this switch the compiler will add "v2" as a prefix while mangling and referencing any symbols that originate from path/to/common/package.

  2. Implement a DMD switch for importing a source directory locally
    -import-local=path/to/dependency/that/use/common;path/to/common/package
    Relevant work for this milestone will be on import-local branch of my dmd fork.
    How it works: With this switch the compiler will import files in path/to/common/package only for sources under path/to/dependency/that/use/common. It acts similar to -I=directory except it only affects certain files to make importing multiple versions of the same package possible without clashing each other.

  3. Implement a Dub switch (and package config) that will make use of DMD's newly implemented features and also mention these new features in the dependency conflict error message.
    --resolve=multi-verison
    Relevant work for this milestone will be on multi-version branch of my dub fork.
    How it works: In the first step Dub will compile common package by passing -mangle-prefix to the compiler. After that it will pass both -mangle-prefix and -import-local when compiling dependency that use common.

  4. I'm not entirely sure what exactly I'll be doing but I have few things in my mind depending on how everything goes:

    • Implementing a Dub feature that allow users to declare the exact semantic version multi-mapping in their project config.
    • Extensive testing to see how these changes affect real world projects and packages.
    • Proper documentation of all the newly implemented DMD & Dub features.
    • Research on how to allow multiple library subconfigurations to co-exist.
    • Continuing any unfinished work from previous milestones if something goes terribly wrong.

I will be maintaining a repository with example dependency hell scenarios and docs on how to test them.

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