# managing dependencies in software development # structural realities that shape dependency strategy ## relinking requirements - c requires every library that uses another library to relink against all transitive dependencies. - a library linked against one version of another library cannot be safely combined with a library linked against a different version of that dependency. - these constraints generate linker hell: version divergence forces rebuilds even when the direct interface has not changed. ## incompatible c library ecosystems - for example, glibc and musl cannot depend on each other. binaries linked against one cannot be mixed with components linked against the other. - composition across libc boundaries requires complete recompilation of the entire dependency tree. - similar incompatibilities appear when low level runtimes provide mutually exclusive abis. ## compositional failure modes - deep dependency chains increase rebuild frequency when any upstream segment changes. - copy importers attempting to inline external code may face cascading rewrite requirements if nested dependencies are not flattened. - binary level composition is constrained by abi coupling; source level composition is constrained by symbol layout and internal reference structure. # strategies for managing dependencies ## direct inclusion models - many libraries included anywhere: simple but prone to conflict when intermediate libraries include one another. - importing and localizing libraries: source is copied into the project namespace to avoid external versioning issues. - incorporating code portions: create a thin helper library containing only the subset of another library actually required. the code duplication can increase maintenance burden or require manual copy of the code for bugfix updates ## flattening dependencies - eliminating internal depth simplifies copy import. - function level flattening: extract required functions of another library into a helper artifact so multiple modules share a consistent minimal subset. - file level flattening: include large files even when only one binding is needed; maintenance cost stays limited to the actually used interface. ## automated import and rewrite - scripts can import files and rewrite internal references to local namespace identifiers. - this avoids manual maintenance while allowing version pinning, deterministic builds, and isolation from upstream structural changes. ## version pinning via vcs modules - git submodules: users must run update or sync operations; dependency on repository layout and continued repository existence. - submodules do not ship code by default; distribution requires extra steps or vendor scripts. - hybrid patterns exist: track a pinned commit via submodule, then copy or vendor the corresponding code into the main tree. - manual copying remains a valid choice when maintainers prefer controlled compatibility selection over tracking upstream evolution automatically. # common issues - dependencies that are difficult to acquire or build (for example when any part of the systems becomes incompatible over time). this may fully prevent the usage of a program.