Dependency propagation¶
See also
General concept¶
Consider the case where C depends on A and B,
and D depends on C.
To declare A a “propagated” dependency means
that D automatically depends on A.
Dependency propagation¶
This specificity comes from Nix building dependencies in a sandbox.
During the build of D in this example,
A and C are available in the sandbox,
while B isn’t,
despite being available in the /nix/store.
Here is an example build plan for D:
Fetch or build
Band put it in the/nix/store.Fetch or build
Aand put it in the/nix/store.Fetch or build
Cand put it in the/nix/store.Build
D. OnlyCandAare exposed in the build sandbox.
Important
When packaging an EPICS support module, its EPICS support module dependencies need to be propagated.
For example,
if we were to package epnix.support.StreamDevice,
we would need to specify epnix.support.asyn as a propagated dependency:
an IOC depending on StreamDevice must have access to asyn during its build.
Why EPICS support modules need to be propagated¶
When there’s a transitive EPICS dependency,
these dependencies tend to be “leaky.”
For example,
when developing a StreamDevice IOC,
your IOC needs to manually include bits from asyn.
The asyn library should be an implementation detail of StreamDevice,
but it “leaks” through,
and your IOC needs to know about it.
This is a problem common to many transitive EPICS dependencies, which is why we recommend that packages propagate these dependencies.
In the following sections, we’ll see why this is often the case with concrete examples.
See also
Leaky abstraction on Wikipedia
StreamDevice and asyn example¶
IOC depending on StreamDevice¶
Running a Nix build of the IOC might go like this:
Fetch or build
libpcreand put it in the/nix/store.Fetch or build
asynand put it in the/nix/store.Fetch or build
StreamDeviceand put it in the/nix/store.Build the IOC. Only
StreamDeviceandasynare exposed in the build sandbox.
This transitive dependency on asyn must be propagated
because in your IOC files,
you have to specify that your app links to both the StreamDevice library
and the asyn library.
Your IOC also needs to import the stream.dbd and asyn.dbd files.
In the diagram,
you can see StreamDevice depending on the libpcre system library,
but that dependency isn’t propagated.
Why does StreamDevice need to propagate asyn but not libpcre?
The libpcre project is a library that StreamDevice uses
to implement Regular Expressions.
In a protocol file,
you can specify that you expect a device to send you a message
in the format %.1/<title>(.*)<\/title>/.
The StreamDevice support module parses this regular expression
by using the PCRE library
and will try to match incoming messages.
When your IOC is running,
you have EPICS records with the stream device type,
which will call functions defined in the libstream.so library.
This library will call functions defined in the libpcre.so library,
so your app doesn’t need to know about it.
Using a regular expression with StreamDevice¶
The PCRE library can stay an implementation detail of StreamDevice.
When using StreamDevice in an IOC,
you need to include several bits from asyn.
You’ll often find a yourApp/src/Makefile file
with these lines:
yourApp_DBD += asyn.dbd
yourApp_DBD += calc.dbd
yourApp_DBD += stream.dbd
yourApp_DBD += drvAsynIPPort.dbd
Both asyn.dbd and drvAsynIPPort.dbd are useful
for typical StreamDevice usage:
drvAsynIPPort.dbddefines thedrvAsynIPPortConfigureshell function for configuring TCP/IP communication with the deviceasyn.dbddefines theasynSetOptionshell function and theasynrecord type
These functions and record types are implemented in libasyn.so,
which is why you also need to link directly to this library:
yourApp_LIBS += asyn
yourApp_LIBS += calc
yourApp_LIBS += stream
Build-time dependencies to StreamDevice and asyn¶
autosave and busy example¶
Another example is how using the epnix.support.autosave support module
might lead you to manually load the epnix.support.busy support module.
When using autosave,
you have the option to use the “config menu” feature.
To use this feature,
you need to load the configMenu.db
from the autosave package.
This database file has a busy record type,
which means your app must now know about the busy module.
Dependencies to autosave and busy¶
This means that apps that use the autosave module
might automatically need to link to the busy module.
Note
In EPNix’s autosave packaging,
busy isn’t included in the dependencies,
because busy depends on autosave.
Adding busy to the dependencies of autosave would lead to an infinite loop.
Users of the autosave module’s “config menu” feature
must manually depend on busy.
General rule¶
In the EPICS support module world,
if C depends on A
and an IOC D uses C,
then there are many cases where D needs to import A.dbd.
This might happen if C uses a record type defined in A
or if D needs to use IOC shell functions from A.
In those cases,
in C’s packaging,
it’s best to propagate A.