diff options
author | Maxim Cournoyer <maxim.cournoyer@gmail.com> | 2023-09-10 23:26:03 -0400 |
---|---|---|
committer | Maxim Cournoyer <maxim.cournoyer@gmail.com> | 2023-09-25 10:33:04 -0400 |
commit | c428246bcdf847ce3a7f48e6cbed3d64bc53da15 (patch) | |
tree | 7c8294c95c70a169670fa28877724357f4e4a2fe /doc | |
parent | 35c1df5bd6317b1cd038c1a4aca1c7e4a52d4d93 (diff) |
doc: Add new 'Circular Module Dependencies' section.
* doc/contributing.texi (Circular Module Dependencies): New subsection.
Series-version: 2
Series-to: 65860@debbugs.gnu.org
Patch-cc: mhw@netris.org
Cover-letter:
Resolve a circular module dependencies in embedded modules
This series is the culmination of at least a day of effort tracking down the
source of a module dependency cycle (!). The last commit adds some guidelines
in the hope to avoid a repeat (perhaps 'lint' could be taught to
automate these checks).
END
Diffstat (limited to 'doc')
-rw-r--r-- | doc/contributing.texi | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/doc/contributing.texi b/doc/contributing.texi index ce4b9db366..11fd7c3778 100644 --- a/doc/contributing.texi +++ b/doc/contributing.texi @@ -518,6 +518,7 @@ needed is to review and apply the patch. * Version Numbers:: When the name is not enough. * Synopses and Descriptions:: Helping users find the right package. * Snippets versus Phases:: Whether to use a snippet, or a build phase. +* Cyclic Module Dependencies:: Going full circle. * Emacs Packages:: Your Elisp fix. * Python Modules:: A touch of British comedy. * Perl Modules:: Little pearls. @@ -789,6 +790,61 @@ embed store items in the sources; such patching should rather be done using build phases. Refer to the @code{origin} record documentation for more information (@pxref{origin Reference}). +@node Cyclic Module Dependencies +@subsection Cyclic Module Dependencies + +While there cannot be circular dependencies between packages, Guile's +lax module loading mechanism allows circular dependencies between Guile +modules, which doesn't cause problems as long as the following +conditions are followed for two modules part of a dependency cycle: + +@cindex rules to cope with circular module dependencies +@enumerate +@item +Macros are not shared between the co-dependent modules +@item +Top-level variables are only referenced in delayed (@i{thunked}) package +fields: @code{arguments}, @code{native-inputs}, @code{inputs}, +@code{propagated-inputs} or @code{replacement} +@item +Procedures referencing top-level variables from another module are not +called at the top level of a module themselves. +@end enumerate + +Straying away from the above rules may work while there are no +dependency cycles between modules, but given such cycles are confusing +and difficult to troubleshoot, it is best to follow the rules to avoid +introducing problems down the line. + +@noindent +Here is a common trap to avoid: + +@lisp +(define-public avr-binutils + (package + (inherit (cross-binutils "avr")) + (name "avr-binutils"))) +@end lisp + +In the above example, the @code{avr-binutils} package was defined in the +module @code{(gnu packages avr)}, and the @code{cross-binutils} +procedure in @code{(gnu packages cross-base)}. Because the +@code{inherit} field is not delayed (thunked), it is evaluated at the +top level at load time, which is problematic in the presence of module +dependency cycles. This could be resolved by turning the package into a +procedure instead, like: + +@lisp +(define (make-avr-binutils) + (package + (inherit (cross-binutils "avr")) + (name "avr-binutils"))) +@end lisp + +Care would need to be taken to ensure the above procedure is only ever +used in a package delayed fields or within another procedure also not +called at the top level. + @node Emacs Packages @subsection Emacs Packages |