Dependency hell: Difference between revisions

From Wikipedia, the free encyclopedia
Jump to navigation Jump to search
imported>Quuxplusone
 
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
{{refimprove|date=August 2024}}
{{More citations needed|date=August 2024}}
 
{{Short description|Colloquial term for software requiring many conflicting dependencies}}
{{Short description|Colloquial term for software requiring many conflicting dependencies}}'''Dependency hell''' is a [[Colloquialism|colloquial term]] for the frustration of some software users who have installed [[Package manager|software packages]] which have [[Coupling (computer programming)|dependencies]] on specific [[Software versioning|version]]s of other software packages.<ref name="Dependency Hell">{{cite book
'''Dependency hell''' is a [[Colloquialism|colloquial term]] for the frustration of some software users who have installed [[Package manager|software packages]] which have [[Coupling (computer programming)|dependencies]] on specific [[Software versioning|versions]] of other software packages.<ref name="Dependency Hell">{{cite book
| title = Linux annoyances for geeks
|title=Linux annoyances for geeks
| author = Michael Jang
|author=Michael Jang
| url = https://archive.org/details/linuxannoyancesf0000jang
|url=https://archive.org/details/linuxannoyancesf0000jang
| url-access = registration
|url-access=registration
| page = [https://archive.org/details/linuxannoyancesf0000jang/page/325 325]
|page=[https://archive.org/details/linuxannoyancesf0000jang/page/325 325]
| publisher = O'Reilly Media
|isbn=9780596552244
| isbn = 9780596552244
|year=2006
| year = 2006
|publisher=O'Reilly Media, Inc.
| accessdate = 2012-02-16}}</ref>
|access-date=2012-02-16}}</ref>


The dependency issue arises when several packages have dependencies on the same ''shared'' packages or libraries, but they depend on different and incompatible versions of the shared packages. If the shared package or library can only be installed in a single version, the user may need to address the problem by obtaining newer or older versions of the dependent packages. This, in turn, may break other dependencies and push the problem to another set of packages.
The dependency issue arises when several packages have dependencies on the same ''shared'' packages or libraries, but they depend on different and incompatible versions of the shared packages. If the shared package or library can only be installed in a single version, the user may need to address the problem by obtaining newer or older versions of the dependent packages. This, in turn, may break other dependencies and push the problem to another set of packages.
Line 17: Line 17:
Dependency hell takes several forms:
Dependency hell takes several forms:


; Many dependencies
=== Many dependencies ===
: An application depends on many [[Library (computing)|libraries]], requiring lengthy downloads, large amounts of disk space, and being very portable (all libraries are already ported enabling the application itself to be ported easily). It can also be difficult to locate all the dependencies, which can be fixed by having a repository (see below). This is partly inevitable; an application built on a given [[computing platform]] (such as [[Java (software platform)|Java]]) requires that platform to be installed, but further applications do not require it. This is a particular problem if an application uses a small part of a big library (which can be solved by [[code refactoring]]), or a simple application relies on many libraries.<ref name="jamesdonald">{{Cite web
: An application depends on many [[Library (computing)|libraries]], requiring long downloads, large amounts of disk space, and being very portable (all libraries are already ported enabling the application itself to be ported easily). It can also be difficult to locate all the dependencies, which can be fixed by having a repository (see below). This is partly inevitable; an application built on a given [[computing platform]] (such as [[Java (software platform)|Java]]) requires that platform to be installed, but further applications do not require it. This is a particular problem if an application uses a small part of a big library (which can be solved by [[code refactoring]]), or a simple application relies on many libraries.<ref name="jamesdonald">{{Cite web
| last = Donald
|last1=Donald
| first = James
|first1=James
| title = Improved Portability of Shared Libraries
|title=Improved Portability of Shared Libraries
| archiveurl=https://web.archive.org/web/20070926130800/http://www.princeton.edu/~jdonald/research/shared_libraries/cs518_report.pdf
|archive-url=https://web.archive.org/web/20070926130800/http://www.princeton.edu/~jdonald/research/shared_libraries/cs518_report.pdf
| archivedate=2007-09-26
|archive-date=2007-09-26
| publisher = Princeton University
|website=Princeton University
| date = 2003-01-25
|date=2003-01-25
| url = http://www.princeton.edu/~jdonald/research/shared_libraries/cs518_report.pdf
|url=http://www.princeton.edu/~jdonald/research/shared_libraries/cs518_report.pdf
| accessdate = 2010-04-09}}</ref>
|access-date=2010-04-09}}</ref>
; Long chains of dependencies
 
: If {{code|app}} depends on {{code|liba}}, which depends on {{code|libb}}, ..., which depends on {{code|libz}}. This is distinct from "many dependencies" if the dependencies must be resolved manually, e.g., on attempting to install {{code|app}}, the user is prompted to install {{code|liba}} first and on attempting to install {{code|liba}}, the user is then prompted to install {{code|libb}}, and so on. Sometimes, however, during this long chain of dependencies, conflicts arise where two different versions of the same package are required<ref name="Dependency-Carousel">{{cite journal
=== Long chains of dependencies ===
| title = It's Good Work When You Can Find It; The Dependency Carousel
: If {{mono|app}} depends on {{mono|liba}}, which depends on {{mono|libb}}, ..., which depends on {{mono|libz}}. This is distinct from "many dependencies" if the dependencies must be resolved manually, e.g., on attempting to install {{mono|app}}, the user is prompted to install {{mono|liba}} first and on attempting to install {{mono|liba}}, the user is then prompted to install {{mono|libb}}, and so on. Sometimes, however, during this long chain of dependencies, conflicts arise where two different versions of the same package are required<ref name="Dependency-Carousel">{{cite journal
| last = Stevens
|title=It's Good Work When You Can Find It; The Dependency Carousel
| first = Al
|last1=Stevens
| journal = J-DDJ
|first1=Al
| volume = 26
|journal=J-DDJ
| issue = 5
|volume=26
| pages = 121–124
|issue=5
| issn = 1044-789X
|pages=121–124
| url = http://www.drdobbs.com/blog/archives/2008/12/its_good_work_w.html
|issn=1044-789X
| archiveurl=https://web.archive.org/web/20110811080730/http://drdobbs.com/blogs/architecture-and-design/228700267
|url=http://www.drdobbs.com/blog/archives/2008/12/its_good_work_w.html
| archivedate=2011-08-11
|archive-url=https://web.archive.org/web/20110811080730/http://drdobbs.com/blogs/architecture-and-design/228700267
| publisher = www.drdobbs.com/blog
|archive-date=2011-08-11
| date = 2001-05-01
|via=drdobbs.com/blog
| accessdate = 2010-04-10}}</ref> (see '''conflicting dependencies''' below). These long chains of dependencies can be solved by having a package manager that resolves all dependencies automatically. Other than being a hassle (to resolve all the dependencies manually), manual resolution can mask dependency cycles or conflicts.
|date=2001-05-01
; Conflicting dependencies
|access-date=2010-04-10}}</ref> (see '''conflicting dependencies''' below). These long chains of dependencies can be solved by having a [[package manager]] that resolves all dependencies automatically. Other than being a hassle (to resolve all the dependencies manually), manual resolution can mask dependency cycles or conflicts.
: Solving the dependencies for one software may break the compatibility of another in a similar fashion to [[whack-a-mole]]. If {{code|app1}} depends on {{code|libfoo 1.2}}, and {{code|app2}} depends on {{code|libfoo 2.0}}, and different versions of {{code|libfoo}} cannot be simultaneously installed, then {{code|app1}} and {{code|app2}} cannot simultaneously be used (or installed, if the installer checks dependencies). When possible, this is solved by allowing simultaneous installations of the different dependencies. Alternatively, the existing dependency, along with all software that depends on it, must be uninstalled in order to install the new dependency. A problem on Linux systems with installing packages from a different distributor is that the resulting long chain of dependencies may lead to a conflicting version of the [[C standard library]] (e.g. the [[GNU C Library]]), on which thousands of packages depend. If this happens, the user will be prompted to uninstall all of those packages.
 
; [[Circular dependencies]]
=== Conflicting dependencies ===
: If {{code|application A}} depends upon and can't run without a specific version of {{code|application B}}, but {{code|application B}}, in turn, depends upon and can't run without a specific version of {{code|application A}}, then upgrading any application will break another. This scheme can be deeper in branching. Its impact can be quite heavy if it affects core systems or update software itself: a package manager (A), which requires specific run-time library (B) to function, may break itself (A) in the middle of the process when upgrading this library (B) to next version. Due to incorrect library (B) version, the package manager (A) is now broken, thus no rollback or downgrade of library (B) is possible. The usual solution is to download and deploy both applications, sometimes from within a temporary environment.
: Solving the dependencies for one software may break the compatibility of another in a similar fashion to [[whack-a-mole]]. If {{mono|app1}} depends on {{mono|libfoo}} 1.2, and {{mono|app2}} depends on {{mono|libfoo}} 2.0, and different versions of {{mono|libfoo}} cannot be simultaneously installed, then {{mono|app1}} and {{mono|app2}} cannot simultaneously be used (or installed, if the installer checks dependencies). When possible, this is solved by allowing simultaneous installations of the different dependencies. Alternatively, the existing dependency, along with all software that depends on it, must be uninstalled in order to install the new dependency. A problem on Linux systems with installing packages from a different distributor is that the resulting long chain of dependencies may lead to a conflicting version of the [[C standard library]] (e.g., the [[GNU C Library]]), on which thousands of packages depend. If this happens, the user will be prompted to uninstall all of those packages.
; Package manager dependencies
 
: It is possible<ref name="linuxdependencyhell"/> for dependency hell to result from installing a prepared package via a package manager (e.g. [[APT (Debian)|APT]]), but this is unlikely since major package managers have matured and official repositories are well maintained. This is the case with current releases of [[Debian]] and major derivatives such as [[Ubuntu (operating system)|Ubuntu]]. Dependency hell, however, can result from installing a package directly via a package installer (e.g. [[RPM Package Manager|RPM]] or [[dpkg]]).
=== Circular dependencies ===
;Diamond dependency
: {{Further|Circular dependency}}
:When a library A depends on libraries B and C, both B and C depend on library D, but B requires version D.1 and C requires version D.2. The build fails because only one version of D can exist in the final executable.  
: If application {{mono|A}} depends upon and can't run without a specific version of application {{mono|B}}, but application {{mono|B}} in turn depends upon and can't run without a specific version of application {{mono|A}}, then upgrading any application will break another. This scheme can be deeper in branching. Its impact can be quite heavy if it affects core systems or update software itself: a package manager ({{mono|A}}), which requires specific run-time library ({{mono|B}}) to function, may break itself ({{mono|A}}) in the middle of the process when upgrading this library ({{mono|B}}) to next version. Due to incorrect library ({{mono|B}}) version, the package manager ({{mono|A}}) is now broken, thus no rollback or downgrade of library ({{mono|B}}) is possible. The usual solution is to download and deploy both applications, sometimes from within a temporary environment.
 
=== Package manager dependencies ===
: It is possible<ref name="linuxdependencyhell" /> for dependency hell to result from installing a prepared package via a package manager (e.g., [[APT (Debian)|APT]]), but this is unlikely since major package managers have matured and official repositories are well maintained. This is the case with current releases of [[Debian]] and major derivatives such as [[Ubuntu]]. Dependency hell, however, can result from installing a package directly via a package installer (e.g., [[RPM Package Manager]] (RPM) or [[dpkg]]).
 
=== Diamond dependency ===
:When a library {{mono|A}} depends on libraries {{mono|B}} and {{mono|C}}, both {{mono|B}} and {{mono|C}} depend on library {{mono|D}}, but {{mono|B}} requires version {{mono|D.1}} and {{mono|C}} requires version {{mono|D.2}}. The build fails because only one version of {{mono|D}} can exist in the final executable.
: Package managers like [[yum (software)|yum]]<ref>{{Cite web |url=http://www.techbrown.com/fix-centos-rhel-fedora-yum-dependencies-hell-problem.shtml |title=Yum Dependency Hell |access-date=2015-12-28 |archive-url=https://web.archive.org/web/20161219072303/http://www.techbrown.com/fix-centos-rhel-fedora-yum-dependencies-hell-problem.shtml |archive-date=2016-12-19 |url-status=dead }}</ref> are prone to have conflicts between packages of their repositories, causing dependency hell in Linux distributions such as [[CentOS]] and [[Red Hat Enterprise Linux]].
: Package managers like [[yum (software)|yum]]<ref>{{Cite web |url=http://www.techbrown.com/fix-centos-rhel-fedora-yum-dependencies-hell-problem.shtml |title=Yum Dependency Hell |access-date=2015-12-28 |archive-url=https://web.archive.org/web/20161219072303/http://www.techbrown.com/fix-centos-rhel-fedora-yum-dependencies-hell-problem.shtml |archive-date=2016-12-19 |url-status=dead }}</ref> are prone to have conflicts between packages of their repositories, causing dependency hell in Linux distributions such as [[CentOS]] and [[Red Hat Enterprise Linux]].


== Solutions ==
== Solutions ==


; Removing dependencies
=== Removing dependencies ===
: Many software libraries are written in a generous way, in an attempt to fulfill most users' needs, but sometimes only a small portion of functions are required in the host code. By examining the source, the functionality can be rewritten in a much more compact way (with respect to the license). In general, this can significantly reduce the application code, reduce later maintenance costs, and  improve the software writing skills of programmers.
: Many software libraries are written in a generous way, in an attempt to fulfill most users' needs, but sometimes only a small portion of functions are required in the host code. By examining the source, the functionality can be rewritten in a much more compact way (with respect to the license). In general, this can significantly reduce the application code, reduce later maintenance costs, and  improve the software writing skills of programmers.


; Version numbering
=== Version numbering ===
: A very common solution to this problem is to have a standardized numbering system, wherein software uses a specific number for each version (aka ''[[Software versioning|major version]]''), and also a subnumber for each revision (aka ''[[Maintenance release|minor version]]''), e.g.: '''10'''.1, or 5.'''7'''. The major version only changes when programs that used that version will no longer be compatible. The minor version might change with even a simple revision that does not prevent other software from working with it. In cases like this, software packages can then simply request a component that has a particular major version, and ''any'' minor version (greater than or equal to a particular minor version). As such, they will continue to work, and dependencies will be resolved successfully, even if the minor version changes. Semantic Versioning (aka "SemVer"<ref>{{cite web|url=https://semver.org|title=Project website: semver.org}}</ref>) is one example of an effort to generate a technical specification that employs specifically formatted numbers to create a software versioning scheme.
: A very common solution to this problem is to have a standardized numbering system, wherein software uses a specific number for each version (aka ''[[Software versioning|major version]]''), and also a subnumber for each revision (aka ''[[Maintenance release|minor version]]''), e.g.: '''10'''.1, or 5.'''7'''. The major version only changes when programs that used that version will no longer be compatible. The minor version might change with even a simple revision that does not prevent other software from working with it. In cases like this, software packages can then simply request a component that has a particular major version, and ''any'' minor version (greater than or equal to a particular minor version). As such, they will continue to work, and dependencies will be resolved successfully, even if the minor version changes. Semantic Versioning (aka "SemVer"<ref>{{cite web|url=https://semver.org|title=Project website: semver.org}}</ref>) is one example of an effort to generate a technical specification that employs specifically formatted numbers to create a software versioning scheme.
;Private per application versions
 
: [[Windows File Protection]] introduced in [[Windows 2000]] prevented applications from overwriting system DLLs. Developers were instead encouraged to use "Private DLLs", copies of libraries per application in the directory of the application. This uses the Windows search path characteristic that the local path is always prioritized before the system directory with the system wide libraries. This allows easy and effective shadowing of library versions by specific application ones, therefore preventing dependency hell.<ref name="endofdllhell">{{cite web
=== Private per application versions ===
| url=http://msdn.microsoft.com/library/techart/dlldanger1.htm
: [[Windows File Protection]], introduced in [[Windows 2000]], prevented applications from overwriting system [[dynamic-link library|dynamic-link libraries]] (DLLs). Developers were instead encouraged to use ''Private DLLs,'' which were duplicates of system DLLs stored in the program's folder. This requires custom dependencies to be packaged with a program, therefore preventing dependency hell.<ref name="endofdllhell">{{cite news
| title=The End of DLL Hell
|last1=Anderson
| date=2000-01-11
|first1=Rick
| archiveurl=https://web.archive.org/web/20010605023737/http://msdn.microsoft.com/library/techart/dlldanger1.htm
|date=2000-01-11
| archivedate=2001-06-05
|url=http://msdn.microsoft.com/library/techart/dlldanger1.htm
| last=Anderson
|title=The End of DLL Hell
| first=Rick
|archive-url=https://web.archive.org/web/20010605023737/http://msdn.microsoft.com/library/techart/dlldanger1.htm
| publisher=microsoft.com
|archive-date=2001-06-05
| accessdate=2010-07-07
|website=Microsoft.com
|access-date=2010-07-07
}}</ref>
}}</ref>
: PC-BSD, up to and including version 8.2, a predecessor of [[TrueOS]] (an operating system based on [[FreeBSD]]) places packages and dependencies into self-contained directories in ''/Programs'', which avoids breakage if system libraries are upgraded or changed. It uses its own "PBI" (Push Button Installer) for package management.<ref>{{Webarchive|url=https://web.archive.org/web/20130327233344/http://www.pbidir.com/|date=2013-03-27|title=pbi Directory}}</ref>
: PC-BSD, up to and including version 8.2, a predecessor of [[TrueOS]] (an [[operating system]] based on [[FreeBSD]]) places packages and dependencies into self-contained directories in ''/Programs'', which avoids breakage if system libraries are upgraded or changed. It uses its own ''push button installer'' (PBI) for package management.<ref>{{cite web |url=http://www.pbidir.com/ |title=pbi Directory |archive-url=https://web.archive.org/web/20130327233344/http://www.pbidir.com/ |archive-date=2013-03-27}}</ref>
; Side-by-side installation of multiple versions
 
: The version numbering solution can be improved upon by elevating the version numbering to an operating system supported feature. This allows an application to request a module/library by a unique name ''and'' version number constraints, effectively transferring the responsibility for brokering library/module versions from the applications to the operating system. A shared module can then be placed in a central repository without the risk of breaking applications which are dependent on previous or later versions of the module. Each version gets its own entry, side by side with other versions of the same module.
=== Side-by-side installation of multiple versions ===
: The version numbering solution can be improved upon by elevating the version numbering to an operating system supported feature. This allows an application to request a module/library by a unique name ''and'' version number constraints, effectively transferring the responsibility for brokering library/module versions from the applications to the operating system. A shared module can then be placed in a central repository without risk of breaking applications which are dependent on prior or later versions of the module. Each version gets its own entry, side by side with other versions of the same module.
: This solution is used in [[Microsoft Windows]] operating systems since Windows Vista, where the [[Global Assembly Cache]] is an implementation of such a central registry with associated services and integrated with the installation system/package manager. [[Gentoo Linux]] solves this problem with a concept called slotting, which allows multiple versions of shared libraries to be installed.<ref>{{Cite web |title=Slotting |url=https://devmanual.gentoo.org/general-concepts/slotting/index.html |access-date=2025-03-10 |website=gentoo.org}}</ref>
: This solution is used in [[Microsoft Windows]] operating systems since Windows Vista, where the [[Global Assembly Cache]] is an implementation of such a central registry with associated services and integrated with the installation system/package manager. [[Gentoo Linux]] solves this problem with a concept called slotting, which allows multiple versions of shared libraries to be installed.<ref>{{Cite web |title=Slotting |url=https://devmanual.gentoo.org/general-concepts/slotting/index.html |access-date=2025-03-10 |website=gentoo.org}}</ref>
; Smart package management
 
=== Smart package management ===
: Some [[package manager]]s can perform smart upgrades, in which interdependent software components are upgraded at the same time, thereby resolving the major number incompatibility issue too.
: Some [[package manager]]s can perform smart upgrades, in which interdependent software components are upgraded at the same time, thereby resolving the major number incompatibility issue too.
: Many current [[Linux]] distributions have also implemented [[Version control|repository]]-based package management systems to try to solve the dependency problem. These systems are a layer on top of the [[RPM Package Manager|RPM]], [[dpkg]], or other packaging systems that are designed to automatically resolve dependencies by searching in predefined [[software repository|software repositories]]. Examples of these systems include [[Advanced Packaging Tool|Apt]], [[yum (software)|Yum]], [[Urpmi]], [[ZYpp]], [[Portage (software)|Portage]], [[Arch Linux#Pacman|Pacman]] and others. Typically, the software repositories are [[File Transfer Protocol|FTP]] sites or websites, [[Directory (computing)|directories]] on the local computer or shared across a [[computer network|network]] or, much less commonly, directories on removable media such as CDs or DVDs. This eliminates dependency hell for software packaged in those repositories, which are typically maintained by the Linux distribution provider and [[Website#mirror site|mirrored]] worldwide. Although these repositories are often huge, it is not possible to have every piece of software in them, so dependency hell can still occur. In all cases, dependency hell is still faced by the repository maintainers.<ref name="linuxdependencyhell">{{cite web |url=http://archive09.linux.com/feature/155922 |title=Nix fixes dependency hell on all Linux distributions |author=Pjotr Prins |author2=Jeeva Suresh |author3=Eelco Dolstra |name-list-style=amp |date=2008-12-22 |accessdate=2013-05-22 |publisher=linux.com |quote=''All popular package managers, including APT, RPM and the FreeBSD Ports Collection, suffer from the problem of destructive upgrades. When you perform an upgrade -- whether for a single application or your entire operating system -- the package manager will overwrite the files that are currently on your system with newer versions. As long as packages are always perfectly backward-compatible, this is not a problem, but in the real world, packages are anything but perfectly backward-compatible. Suppose you upgrade Firefox, and your package manager decides that you need a newer version of GTK as well. If the new GTK is not quite backward-compatible, then other applications on your system might suddenly break. In the Windows world a similar problem is known as the DLL hell, but dependency hell is just as much a problem in the Unix world, if not a bigger one, because Unix programs tend to have many external dependencies.'' |archive-url=https://web.archive.org/web/20150708101023/http://archive09.linux.com/feature/155922 |archive-date=2015-07-08 |url-status=dead }}</ref>
: Many current [[Linux]] distributions have also implemented [[Version control|repository]]-based package management systems to try to solve the dependency problem. These systems are a layer on top of the [[RPM Package Manager]] (RPM), [[dpkg]], or other packaging systems that are designed to automatically resolve dependencies by searching in one or more predefined [[software repository]]. Examples of these systems include Advanced Packaging Tool ([[APT (software)|APT]]), [[yum (software)|Yum]], [[Urpmi]], [[ZYpp]], [[Portage (software)|Portage]], [[Arch Linux#Pacman|Pacman]] and others. Typically, the software repositories are [[File Transfer Protocol]] (FTP) sites or websites, [[Directory (computing)|directories]] on the local computer or shared across a [[computer network|network]] or, much less commonly, directories on removable media such as CDs or DVDs. This eliminates dependency hell for software packaged in those repositories, which are typically maintained by the Linux distribution provider and [[Website#mirror site|mirrored]] worldwide. Although these repositories are often huge, it is not possible to have every piece of software in them, so dependency hell can still occur. In all cases, dependency hell is still faced by the repository maintainers.<ref name="linuxdependencyhell">{{cite web |url=http://archive09.linux.com/feature/155922 |title=Nix fixes dependency hell on all Linux distributions |author=Pjotr Prins |author2=Jeeva Suresh |author3=Eelco Dolstra |name-list-style=amp |date=2008-12-22 |access-date=2013-05-22 |website=linux.com |quote=All popular package managers, including APT, RPM and the FreeBSD Ports Collection, suffer from the problem of destructive upgrades. When you perform an upgrade -- whether for a single application or your entire operating system -- the package manager will overwrite the files that are currently on your system with newer versions. As long as packages are always perfectly backward-compatible, this is not a problem, but in the real world, packages are anything but perfectly backward-compatible. Suppose you upgrade Firefox, and your package manager decides that you need a newer version of GTK as well. If the new GTK is not quite backward-compatible, then other applications on your system might suddenly break. In the Windows world a similar problem is known as the DLL hell, but dependency hell is just as much a problem in the Unix world, if not a bigger one, because Unix programs tend to have many external dependencies. |archive-url=https://web.archive.org/web/20150708101023/http://archive09.linux.com/feature/155922 |archive-date=2015-07-08 |url-status=dead}}</ref>
; Installer options
 
: Because different pieces of software have different dependencies, it is possible to get into a [[Virtuous circle and vicious circle|vicious circle]] of dependency [[requirement]]s, or an ever-expanding [[Tree structure|tree]] of requirements, as each new package demands several more be installed. Systems such as Debian's [[Advanced Packaging Tool]] can resolve this by presenting the user with a range of solutions, and allowing the user to accept or reject the solutions, as desired.
=== Installer options ===
; Easy adaptability in programming
: Because different pieces of software have different dependencies, it is possible to get into a [[Virtuous circle and vicious circle|vicious circle]] of dependency [[requirement]]s, or an ever-expanding [[Tree structure|tree]] of requirements, as each new package demands several more be installed. Systems such as Debian's Advanced Packaging Tool ([[APT (software)|APT]]) can resolve this by presenting a user with a range of solutions, and allowing the user to accept or reject the solutions, as desired.
 
=== Easy adaptability in programming ===
: If application software is designed in such a way that its programmers are able to easily adapt the interface layer that deals with the OS, window manager or desktop environment to new or changing standards, then the programmers would only have to monitor notifications from the environment creators or component library designers and quickly adjust their software with updates for their users, all with minimal effort and a lack of costly and time-consuming redesign. This method would encourage programmers to pressure those upon whom they depend to maintain a reasonable notification process that is not onerous to anyone involved.
: If application software is designed in such a way that its programmers are able to easily adapt the interface layer that deals with the OS, window manager or desktop environment to new or changing standards, then the programmers would only have to monitor notifications from the environment creators or component library designers and quickly adjust their software with updates for their users, all with minimal effort and a lack of costly and time-consuming redesign. This method would encourage programmers to pressure those upon whom they depend to maintain a reasonable notification process that is not onerous to anyone involved.
; Strict compatibility requirement in code development and maintenance
 
=== Strict compatibility requirement in code development and maintenance ===
: If the applications and libraries are developed and maintained with guaranteed downward compatibility in mind, any application or library can be replaced with a newer version at any time without breaking anything. While this does not alleviate the multitude of dependency, it does make the jobs of package managers or installers much easier.
: If the applications and libraries are developed and maintained with guaranteed downward compatibility in mind, any application or library can be replaced with a newer version at any time without breaking anything. While this does not alleviate the multitude of dependency, it does make the jobs of package managers or installers much easier.
; [[Software appliance]]s
 
=== Software appliances ===
{{Further|Software appliance}}
: Another approach to avoiding dependency issues is to deploy applications as a [[software appliance]]. A software appliance encapsulates dependencies in a pre-integrated self-contained unit such that users no longer have to worry about resolving software dependencies. Instead the burden is shifted to developers of the software appliance. [[Container (virtualization)|Containers]] and their images (such as those provided by [[Docker (software)|Docker]] and Docker Hub) can be seen as an implementation of software appliances.
: Another approach to avoiding dependency issues is to deploy applications as a [[software appliance]]. A software appliance encapsulates dependencies in a pre-integrated self-contained unit such that users no longer have to worry about resolving software dependencies. Instead the burden is shifted to developers of the software appliance. [[Container (virtualization)|Containers]] and their images (such as those provided by [[Docker (software)|Docker]] and Docker Hub) can be seen as an implementation of software appliances.
; [[Portable application]]s
 
=== Portable applications ===
{{Main article|Portable application}}
: An application (or version of an existing conventional application) that is completely self-contained and requires nothing to be already installed. It is coded to have all necessary components included, or is designed to keep all necessary files within its own directory, and will not create a dependency problem. These are often able to run independently of the system to which they are connected. Applications in [[RISC OS]] and the [[ROX Desktop]] for Linux use [[application directory|application directories]], which work in much the same way: programs and their dependencies are self-contained in their own directories (folders).<ref>{{cite web
: An application (or version of an existing conventional application) that is completely self-contained and requires nothing to be already installed. It is coded to have all necessary components included, or is designed to keep all necessary files within its own directory, and will not create a dependency problem. These are often able to run independently of the system to which they are connected. Applications in [[RISC OS]] and the [[ROX Desktop]] for Linux use [[application directory|application directories]], which work in much the same way: programs and their dependencies are self-contained in their own directories (folders).<ref>{{cite web
| url=http://rox.sourceforge.net/desktop/AppDirs.html
|url=https://rox.sourceforge.net/desktop/AppDirs.html
| title=Application directories
|title=Application directories
| accessdate=7 September 2013
|access-date=7 September 2013
}}</ref>
}}</ref>
: This method of distribution has also proven useful when porting applications designed for Unix-like platforms to Windows, the most noticeable drawback being multiple installations of the same [[Library (computing)#Shared libraries|shared libraries]]. For example, Windows installers for [[gedit]], [[GIMP]], and [[HexChat]] all include identical copies of the [[GTK]] toolkit, which these programs use to render widgets. On the other hand, if different versions of GTK are required by each application, then this is the correct behavior and successfully avoids dependency hell.
: This method of distribution has also proven useful when porting applications designed for [[Unix-like]] platforms to Windows, the most noticeable drawback being multiple installations of the same [[Library (computing)#Shared libraries|shared libraries]]. For example, Windows installers for [[gedit]], [[GIMP]], and [[HexChat]] all include identical copies of the [[GTK]] toolkit, which these programs use to render widgets. On the other hand, if different versions of GTK are required by each application, then this is the correct behavior and successfully avoids dependency hell.


==Platform-specific==
==Platform-specific==
On specific [[computing platform]]s, "dependency hell" often goes by a local specific name, generally the name of components.
On specific [[computing platform]]s, ''dependency hell'' often goes by a local specific name, generally the name of components.


* [[DLL Hell]]{{snd}} a form of dependency hell occurring on 16-bit [[Microsoft Windows]].
* [[DLL Hell]] a form of dependency hell occurring on [[16-bit computing|16-bit]] [[Microsoft Windows]].
* [[Extension conflict]]{{snd}} a form of dependency hell occurring on the [[classic Mac OS]].
* [[Extension conflict]] a form of dependency hell occurring on the [[classic Mac OS]].
* [[Java class loader#JAR hell|JAR hell]]{{snd}} a form of dependency hell occurring in the [[Java virtual machine|Java Runtime Environment]] before build tools like [[Apache Maven]] solved this problem in 2004.{{citation needed|date=March 2017}}
* [[Java class loader#JAR hell|JAR hell]] a form of dependency hell occurring in the [[Java virtual machine|Java Runtime Environment]] before build tools like [[Apache Maven]] solved this problem in 2004.{{citation needed|date=March 2017}}
* RPM hell{{snd}} a form of dependency hell occurring in the [[Red Hat]] distribution of [[Linux]] and other distributions that use [[rpm (software)|RPM]] as a package manager.<ref name="linuxcompa">{{cite web
* RPM hell a form of dependency hell occurring in the [[Red Hat]] distribution of [[Linux]] and other distributions that use [[rpm (software)|RPM]] as a package manager.<ref name="linuxcompa">{{cite web
| title = Is Linux Annoying?
|title=Is Linux Annoying?
| last = Weinstein
|last1=Weinstein
| first = Paul
|first1=Paul
| url = http://linuxdevcenter.com/pub/a/linux/2003/09/11/linux_annoyances.html
|url=http://linuxdevcenter.com/pub/a/linux/2003/09/11/linux_annoyances.html
| publisher = linuxdevcenter.com
|website=linuxdevcenter.com
| date = 2003-09-11
|date=2003-09-11
| accessdate = 2010-04-10}}</ref>
|access-date=2010-04-10}}</ref>


== See also ==
== See also ==
* [[Catch-22 (logic) | Catch-22]] – a situation in which solving a problem depends on contradictory circumstances, named after a concept described in a 1961 novel
* [[Catch-22 (logic)|Catch-22]] – a situation in which solving a problem depends on contradictory circumstances, named after a concept described in a 1961 novel
* [[Configuration management]]{{snd}} techniques and tools for managing software versions
* [[Configuration management]] techniques and tools for managing software versions
* [[Coupling (computer programming)|Coupling]]{{snd}} forms of dependency among software artifacts
* [[Coupling (computer programming)|Coupling]] forms of dependency among software artifacts
* [[Dynamic dead code elimination]]
* [[Dynamic dead code elimination]]
* [[Package manager]]
* [[Package manager]]
Line 121: Line 137:
* [[Static library]]
* [[Static library]]
* [[Supply chain attack]]
* [[Supply chain attack]]
* [[Nix package manager]]
* [[Nix (package manager)]]
* [[npm left-pad incident]]
* [[npm left-pad incident]]


== References ==
== References ==
{{reflist|30em}}
{{Reflist}}


[[Category:Package management systems]]
[[Category:Package management systems]]

Latest revision as of 18:26, 21 November 2025

Script error: No such module "Unsubst". Template:Short description Dependency hell is a colloquial term for the frustration of some software users who have installed software packages which have dependencies on specific versions of other software packages.[1]

The dependency issue arises when several packages have dependencies on the same shared packages or libraries, but they depend on different and incompatible versions of the shared packages. If the shared package or library can only be installed in a single version, the user may need to address the problem by obtaining newer or older versions of the dependent packages. This, in turn, may break other dependencies and push the problem to another set of packages.

Problems

Dependency hell takes several forms:

Many dependencies

An application depends on many libraries, requiring long downloads, large amounts of disk space, and being very portable (all libraries are already ported enabling the application itself to be ported easily). It can also be difficult to locate all the dependencies, which can be fixed by having a repository (see below). This is partly inevitable; an application built on a given computing platform (such as Java) requires that platform to be installed, but further applications do not require it. This is a particular problem if an application uses a small part of a big library (which can be solved by code refactoring), or a simple application relies on many libraries.[2]

Long chains of dependencies

If <templatestyles src="Mono/styles.css" />app depends on <templatestyles src="Mono/styles.css" />liba, which depends on <templatestyles src="Mono/styles.css" />libb, ..., which depends on <templatestyles src="Mono/styles.css" />libz. This is distinct from "many dependencies" if the dependencies must be resolved manually, e.g., on attempting to install <templatestyles src="Mono/styles.css" />app, the user is prompted to install <templatestyles src="Mono/styles.css" />liba first and on attempting to install <templatestyles src="Mono/styles.css" />liba, the user is then prompted to install <templatestyles src="Mono/styles.css" />libb, and so on. Sometimes, however, during this long chain of dependencies, conflicts arise where two different versions of the same package are required[3] (see conflicting dependencies below). These long chains of dependencies can be solved by having a package manager that resolves all dependencies automatically. Other than being a hassle (to resolve all the dependencies manually), manual resolution can mask dependency cycles or conflicts.

Conflicting dependencies

Solving the dependencies for one software may break the compatibility of another in a similar fashion to whack-a-mole. If <templatestyles src="Mono/styles.css" />app1 depends on <templatestyles src="Mono/styles.css" />libfoo 1.2, and <templatestyles src="Mono/styles.css" />app2 depends on <templatestyles src="Mono/styles.css" />libfoo 2.0, and different versions of <templatestyles src="Mono/styles.css" />libfoo cannot be simultaneously installed, then <templatestyles src="Mono/styles.css" />app1 and <templatestyles src="Mono/styles.css" />app2 cannot simultaneously be used (or installed, if the installer checks dependencies). When possible, this is solved by allowing simultaneous installations of the different dependencies. Alternatively, the existing dependency, along with all software that depends on it, must be uninstalled in order to install the new dependency. A problem on Linux systems with installing packages from a different distributor is that the resulting long chain of dependencies may lead to a conflicting version of the C standard library (e.g., the GNU C Library), on which thousands of packages depend. If this happens, the user will be prompted to uninstall all of those packages.

Circular dependencies

Script error: No such module "labelled list hatnote".
If application <templatestyles src="Mono/styles.css" />A depends upon and can't run without a specific version of application <templatestyles src="Mono/styles.css" />B, but application <templatestyles src="Mono/styles.css" />B in turn depends upon and can't run without a specific version of application <templatestyles src="Mono/styles.css" />A, then upgrading any application will break another. This scheme can be deeper in branching. Its impact can be quite heavy if it affects core systems or update software itself: a package manager (<templatestyles src="Mono/styles.css" />A), which requires specific run-time library (<templatestyles src="Mono/styles.css" />B) to function, may break itself (<templatestyles src="Mono/styles.css" />A) in the middle of the process when upgrading this library (<templatestyles src="Mono/styles.css" />B) to next version. Due to incorrect library (<templatestyles src="Mono/styles.css" />B) version, the package manager (<templatestyles src="Mono/styles.css" />A) is now broken, thus no rollback or downgrade of library (<templatestyles src="Mono/styles.css" />B) is possible. The usual solution is to download and deploy both applications, sometimes from within a temporary environment.

Package manager dependencies

It is possible[4] for dependency hell to result from installing a prepared package via a package manager (e.g., APT), but this is unlikely since major package managers have matured and official repositories are well maintained. This is the case with current releases of Debian and major derivatives such as Ubuntu. Dependency hell, however, can result from installing a package directly via a package installer (e.g., RPM Package Manager (RPM) or dpkg).

Diamond dependency

When a library <templatestyles src="Mono/styles.css" />A depends on libraries <templatestyles src="Mono/styles.css" />B and <templatestyles src="Mono/styles.css" />C, both <templatestyles src="Mono/styles.css" />B and <templatestyles src="Mono/styles.css" />C depend on library <templatestyles src="Mono/styles.css" />D, but <templatestyles src="Mono/styles.css" />B requires version <templatestyles src="Mono/styles.css" />D.1 and <templatestyles src="Mono/styles.css" />C requires version <templatestyles src="Mono/styles.css" />D.2. The build fails because only one version of <templatestyles src="Mono/styles.css" />D can exist in the final executable.
Package managers like yum[5] are prone to have conflicts between packages of their repositories, causing dependency hell in Linux distributions such as CentOS and Red Hat Enterprise Linux.

Solutions

Removing dependencies

Many software libraries are written in a generous way, in an attempt to fulfill most users' needs, but sometimes only a small portion of functions are required in the host code. By examining the source, the functionality can be rewritten in a much more compact way (with respect to the license). In general, this can significantly reduce the application code, reduce later maintenance costs, and improve the software writing skills of programmers.

Version numbering

A very common solution to this problem is to have a standardized numbering system, wherein software uses a specific number for each version (aka major version), and also a subnumber for each revision (aka minor version), e.g.: 10.1, or 5.7. The major version only changes when programs that used that version will no longer be compatible. The minor version might change with even a simple revision that does not prevent other software from working with it. In cases like this, software packages can then simply request a component that has a particular major version, and any minor version (greater than or equal to a particular minor version). As such, they will continue to work, and dependencies will be resolved successfully, even if the minor version changes. Semantic Versioning (aka "SemVer"[6]) is one example of an effort to generate a technical specification that employs specifically formatted numbers to create a software versioning scheme.

Private per application versions

Windows File Protection, introduced in Windows 2000, prevented applications from overwriting system dynamic-link libraries (DLLs). Developers were instead encouraged to use Private DLLs, which were duplicates of system DLLs stored in the program's folder. This requires custom dependencies to be packaged with a program, therefore preventing dependency hell.[7]
PC-BSD, up to and including version 8.2, a predecessor of TrueOS (an operating system based on FreeBSD) places packages and dependencies into self-contained directories in /Programs, which avoids breakage if system libraries are upgraded or changed. It uses its own push button installer (PBI) for package management.[8]

Side-by-side installation of multiple versions

The version numbering solution can be improved upon by elevating the version numbering to an operating system supported feature. This allows an application to request a module/library by a unique name and version number constraints, effectively transferring the responsibility for brokering library/module versions from the applications to the operating system. A shared module can then be placed in a central repository without risk of breaking applications which are dependent on prior or later versions of the module. Each version gets its own entry, side by side with other versions of the same module.
This solution is used in Microsoft Windows operating systems since Windows Vista, where the Global Assembly Cache is an implementation of such a central registry with associated services and integrated with the installation system/package manager. Gentoo Linux solves this problem with a concept called slotting, which allows multiple versions of shared libraries to be installed.[9]

Smart package management

Some package managers can perform smart upgrades, in which interdependent software components are upgraded at the same time, thereby resolving the major number incompatibility issue too.
Many current Linux distributions have also implemented repository-based package management systems to try to solve the dependency problem. These systems are a layer on top of the RPM Package Manager (RPM), dpkg, or other packaging systems that are designed to automatically resolve dependencies by searching in one or more predefined software repository. Examples of these systems include Advanced Packaging Tool (APT), Yum, Urpmi, ZYpp, Portage, Pacman and others. Typically, the software repositories are File Transfer Protocol (FTP) sites or websites, directories on the local computer or shared across a network or, much less commonly, directories on removable media such as CDs or DVDs. This eliminates dependency hell for software packaged in those repositories, which are typically maintained by the Linux distribution provider and mirrored worldwide. Although these repositories are often huge, it is not possible to have every piece of software in them, so dependency hell can still occur. In all cases, dependency hell is still faced by the repository maintainers.[4]

Installer options

Because different pieces of software have different dependencies, it is possible to get into a vicious circle of dependency requirements, or an ever-expanding tree of requirements, as each new package demands several more be installed. Systems such as Debian's Advanced Packaging Tool (APT) can resolve this by presenting a user with a range of solutions, and allowing the user to accept or reject the solutions, as desired.

Easy adaptability in programming

If application software is designed in such a way that its programmers are able to easily adapt the interface layer that deals with the OS, window manager or desktop environment to new or changing standards, then the programmers would only have to monitor notifications from the environment creators or component library designers and quickly adjust their software with updates for their users, all with minimal effort and a lack of costly and time-consuming redesign. This method would encourage programmers to pressure those upon whom they depend to maintain a reasonable notification process that is not onerous to anyone involved.

Strict compatibility requirement in code development and maintenance

If the applications and libraries are developed and maintained with guaranteed downward compatibility in mind, any application or library can be replaced with a newer version at any time without breaking anything. While this does not alleviate the multitude of dependency, it does make the jobs of package managers or installers much easier.

Software appliances

Script error: No such module "labelled list hatnote".

Another approach to avoiding dependency issues is to deploy applications as a software appliance. A software appliance encapsulates dependencies in a pre-integrated self-contained unit such that users no longer have to worry about resolving software dependencies. Instead the burden is shifted to developers of the software appliance. Containers and their images (such as those provided by Docker and Docker Hub) can be seen as an implementation of software appliances.

Portable applications

Template:Main article

An application (or version of an existing conventional application) that is completely self-contained and requires nothing to be already installed. It is coded to have all necessary components included, or is designed to keep all necessary files within its own directory, and will not create a dependency problem. These are often able to run independently of the system to which they are connected. Applications in RISC OS and the ROX Desktop for Linux use application directories, which work in much the same way: programs and their dependencies are self-contained in their own directories (folders).[10]
This method of distribution has also proven useful when porting applications designed for Unix-like platforms to Windows, the most noticeable drawback being multiple installations of the same shared libraries. For example, Windows installers for gedit, GIMP, and HexChat all include identical copies of the GTK toolkit, which these programs use to render widgets. On the other hand, if different versions of GTK are required by each application, then this is the correct behavior and successfully avoids dependency hell.

Platform-specific

On specific computing platforms, dependency hell often goes by a local specific name, generally the name of components.

See also

References

<templatestyles src="Reflist/styles.css" />

  1. Script error: No such module "citation/CS1".
  2. Script error: No such module "citation/CS1".
  3. a b Script error: No such module "citation/CS1".
  4. Script error: No such module "citation/CS1".
  5. Script error: No such module "citation/CS1".
  6. Script error: No such module "citation/CS1".
  7. Script error: No such module "citation/CS1".
  8. Script error: No such module "citation/CS1".
  9. Script error: No such module "citation/CS1".
  10. Script error: No such module "citation/CS1".

Script error: No such module "Check for unknown parameters".