Installed tree and relocation
The installed tree is the directory that holds one built Experimental Physics and Industrial Control System (EPICS) base, every module in the module set, and the files that set up a shell for them. Its binaries find their shared libraries by position relative to themselves, so the whole directory works after you move or copy it. Choose the install location and release sets where the tree goes, and Set up a shell with the environment uses it.
Directory layout by release, system, and base version
EPICS-env installs each tree at this path:
$(INSTALL_LOCATION)/$(ENV_RELEASE_VERS)/<os_id>-<os_version>/$(SRC_VER_BASE)
<os_id> and <os_version> are the ID and VERSION_ID values from
/etc/os-release. The make variable INSTALL_LOCATION_EPICS holds the whole
path, such as /home/user/epics/1.4.0/debian-13/7.0.10, so trees for several
releases, operating systems, and EPICS base versions can share one
INSTALL_LOCATION.
Install location and release
lists the variables.
One tree has this layout, shown for two of its modules:
<install_location_epics>/
|-- setEpicsEnv.bash
|-- resetEpicsEnv.bash
|-- .versions
|-- base/
| |-- bin/linux-x86_64/
| `-- lib/linux-x86_64/
|-- modules/
| |-- asyn-4.46.0/
| |-- asyn -> ./asyn-4.46.0
| |-- seq-2.2.9/
| |-- seq -> ./seq-2.2.9
| `-- commonIocsh/
| `-- iocsh/
`-- vendor/
`-- lib/
Versioned directories and unversioned links
Each module installs into modules/<name>-<version>, where <version> is the
SRC_VER_<MODULE_KEY> value of the module, such as asyn-4.46.0 or
calc-4217e83. The sequencer installs as seq-<version>.
make symlinks adds an unversioned link for each module, such as
modules/asyn, that points to the versioned directory by a relative path.
The link gives a path that stays the same when a pin changes.
The build itself uses only versioned directories. Every module
RELEASE.local and every library search path in a binary names a versioned
directory, so removing or replacing the links changes no binary.
setEpicsEnv.bash uses the pvxs and pmac links to put their executables
on PATH.
Environment script and version record
install.base copies scripts/setEpicsEnv.bash and
scripts/resetEpicsEnv.bash to the top of the tree with mode 0644. It backs
up files it replaces. You source setup in a Bash shell. The script finds the tree from its own location,
and follows a symbolic link to the script when there is one. It then sets
the shell environment in four ways:
- It sets
EPICS_PATHto the tree,EPICS_BASEto itsbasedirectory, andEPICS_MODULESto itsmodulesdirectory. - It sets
EPICS_HOST_ARCHfrom theEpicsHostArch.plscript of EPICS base, whichperlruns, or else frombase/startup/EpicsHostArch, whichshruns. Whenperlor all three scripts are absent, it uses its own fallback architecture argument. Its interface is[<fallback_arch>] [disable];disablecontrols only the summary. - It adds
base/bin/<arch>,modules/pvxs/bin/<arch>, andmodules/pmac/bin/<arch>to the front ofPATH. - It adds
base/lib/<arch>to the front ofLD_LIBRARY_PATH.
When EPICS_BASE is already set, the script first removes the entries of the
earlier tree from PATH and LD_LIBRARY_PATH after resolving the selected
tree and architecture. Complete-field comparison preserves unrelated entries
and empty fields; repeated setup adds managed directories once. Directly
sourcing another tree’s setup selects that tree. Resolution failure preserves
the existing managed environment.
Reset removes the known executable and base library entries and unsets
EPICS_PATH, EPICS_BASE, EPICS_MODULES, EPICS_HOST_ARCH, and legacy
EPICS_EXTENSIONS, including when base is absent. Both scripts preserve
independently configured CA settings and operate with Bash nounset enabled.
src_version writes .versions at the top of the tree. It records when the
install ran and which EPICS-env commit it used. The .versions file of one
tree reads:
Timestamps : 20260926-225114/YYYYMMDD-HHMMSS
git version :4601e4049ac3f846806ec59a7cf462f4f9459393
Common iocsh fragment directory
install.commoniocsh copies commonIocsh/iocsh/*.iocsh from the repository
to modules/commonIocsh/iocsh. That directory has no version in its name and
no unversioned link. An input/output controller (IOC) sets IOCSH_TOP to
its parent, modules/commonIocsh, and loads each fragment as
$(IOCSH_TOP)/iocsh/<fragment>.iocsh.
Common iocsh fragments explains the fragments,
and Load common iocsh fragments in an IOC
uses them.
Vendor library directory
vendor/ holds third-party libraries that two modules link: uldaq for
measComp and open62541 for opcua. No EPICS-env make target creates it.
The continuous integration (CI) workflows and tools/prep-vendors.bash
install both libraries there, and point VENDOR_ULDAQ_PATH and
OPEN62541_PATH at it in configure/RELEASE.local. With the default value
/usr/local of both variables, the modules link the libraries from that
system location instead.
Vendor library locations
lists the two variables.
vendor/ lies inside the tree, so make uninstall removes it with the rest
of the tree.
Library search paths relative to ORIGIN
A shared library or executable in the Executable and Linkable Format (ELF)
carries a list of directories that the dynamic loader searches for the
libraries it needs. EPICS-env makes every entry for a library inside the tree
relative to $ORIGIN, which the loader replaces with the directory of the
file being loaded.
Two EPICS base build variables produce the relative entries:
LINKER_USE_RPATHisORIGIN.conf.base.sitewrites it to the EPICS base site file, and every build receives it on the make command line.LINKER_ORIGIN_ROOTnames the root of the relocatable tree. Every EPICS base and module build receives it on the make command line, set toINSTALL_LOCATION_EPICS, the top of the tree.
EPICS base records a library directory under that root as a path relative to
$ORIGIN, and a directory outside the root as an absolute path.
The linker option -Wl,--enable-new-dtags stores the list as a RUNPATH
entry, the run-time library search path, rather than an RPATH entry.
check.deps fails on any RPATH entry, and the configuration passes the
option to every kind of link:
| Where the configuration sets it | Variable | Links |
|---|---|---|
EPICS base configure/CONFIG_SITE.local | PROD_LDFLAGS_DEFAULT | Executables of EPICS base and of every module, because EPICS base installs this file and its configure/CONFIG_SITE reads it |
EPICS base configure/os/CONFIG_SITE.linux-x86_64.linux-x86_64 | SHRLIB_LDFLAGS, LOADABLE_SHRLIB_LDFLAGS | Shared libraries of EPICS base and of every module, because EPICS base installs this file |
CONFIG_SITE.local at the repository top | PROD_LDFLAGS | Executables of the modules that read this file |
From the top of an installed tree, this command prints the libraries that the asyn library needs and its search path:
readelf -d modules/asyn-4.46.0/lib/linux-x86_64/libasyn.so | grep -E 'NEEDED|RUNPATH'
The output is:
0x0000000000000001 (NEEDED) Shared library: [libdbCore.so.3.25.0]
0x0000000000000001 (NEEDED) Shared library: [libCom.so.3.25.0]
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [$ORIGIN/../../../../base/lib/linux-x86_64:$ORIGIN/.]
The first entry leads from modules/asyn-4.46.0/lib/linux-x86_64 up four
levels to the top of the tree and down to the EPICS base libraries. No entry
names the directory the tree was built in.
Why the tree can be moved
Two properties make the tree independent of the directory it was built in:
- Every library search path to a library inside the tree is relative to
$ORIGIN, so the loader finds EPICS base, module, and vendor libraries at the same relative positions after a move. setEpicsEnv.bashcomputes every path it sets from its own location.
check.deps guards the first property. It fails when an installed binary
carries an RPATH entry or an absolute path outside the system library
directories. It also fails on a shared library that needs a library of the
tree but has no $ORIGIN entry.
Build and install verification gates describes it.
A search path can also name a system library directory, such as
/usr/lib/x86_64-linux-gnu in the pmac and pyDevSup libraries. Such a
path does not depend on where the tree lies.
Relocation covers the loader and the environment script, not every text file. These installed files keep the absolute path of the original tree:
- The EPICS base
configure/CONFIG_SITE.local. - The
configure/RELEASE.localfile that 16 of the installed modules carry, except the one ofiocStats, which sets onlyMAKE_TEST_IOC_APP=NO. - The
S99caRepeater,S99logServer, andcaRepeater.servicefiles inbase/bin/linux-x86_64. - The
epics-base.pcandepics-base-linux-x86_64.pcfiles inbase/lib/pkgconfig. - The
libuldaq.laandpkgconfig/open62541.pcfiles undervendor/lib.
The tree path names one operating system and version, and the tree links the system libraries of that system. A moved tree therefore belongs on a host that runs the same operating system and version.
make uninstall removes the tree at the path that the current configuration
computes. Uninstall and clean covers
removal.