Compare commits

...

32 Commits

Author SHA1 Message Date
Ralph Lange
8fd36d8eef AppVeyor: whitelist 7.0 branch
The AppVeyor epics-base-7 project is supposed to pull the .appveyor.yml from this branch to only build commits and pull requests from/for 7.0.
2020-11-03 10:02:34 +01:00
Andrew Johnson
baced535e3 Add -v (verbose) flag to softIoc
Only display the startup steps taken if -v was given.
Show each step *before* running it, so error messages follow it.
2020-10-28 23:55:24 -05:00
Andrew Johnson
be7c6a0a0a Build: Do clean before uninstall actions (if requested) 2020-10-28 23:26:25 -05:00
Andrew Johnson
14476391c0 Warn about NULL dbevEventUserFreeList 2020-10-28 23:25:02 -05:00
Andrew Johnson
223b292c33 Merge fix-wrong-order-phas fixes from 3.15 branch 2020-10-22 10:31:52 -05:00
Andrew Johnson
68121ec907 Merged Dirk's fix_one_element_input_link_arrays branch 2020-10-22 10:14:10 -05:00
Martin Konrad
228ad79b7a Simplify addToList() function 2020-10-13 18:38:17 -04:00
Martin Konrad
bbc0a56d2b Fix wrong PHAS order
Records with lower PHAS value than any previously loaded records
were inserted at the end of the list rather than at the beginning.
This fixes lp: #1899697. Also fixes a proto-bug in that the second
argument to the previously used ellAdd() call assumed that
offsetof(scan_element, node)==0.

Thanks to Bruno Martins for providing this patch.
2020-10-13 18:34:39 -04:00
Andrew Johnson
9726b9efc9 aSubRecord: Fix OVLA..OVLU POD field list 2020-10-12 15:34:43 -05:00
Gabriel Fedel
3e891a12ff Fix asub documentation: alarm happens when retunr status is < 0 2020-09-23 09:36:36 +02:00
Andrew Johnson
22ee229aca Add support for linux-aarch64 native builds 2020-09-16 00:45:19 -05:00
Andrew Johnson
1ae3bd6c70 Add warnings to CONFIG_SITE files that can't override gnuCommon
Move the clang and '-g' suggestions to the right places
2020-09-08 16:57:48 -05:00
Ralph Lange
cbba08b1ef Merge pull request #88 from HiteshDhola/patch-1
Update README.md
2020-08-26 10:17:42 +02:00
Hitesh Dhola
53044571fb Update README.md
Pointing out few err in the release version. As this is the first document anyone would Read. 

-Corrected released version. Removed old references.
PS : I also use this file to restore my "base" folder with older original version when new EPICS version is released. This way I can keep all of my compiled version isolated.
2020-08-26 12:47:19 +05:30
Ralph Lange
f8df3473ab Redo d3d40689 that was lost in upmerging 2020-08-25 16:06:39 +02:00
Ralph Lange
e8bee54531 Redo 97b29129/0fbfc741 that was lost in upmerging 2020-08-25 16:04:04 +02:00
Michael Davidsaver
0cae0db98b compat IPPORT_USERRESERVED
musl libc doesn't define IPPORT_USERRESERVED
2020-08-22 07:51:33 -07:00
Michael Davidsaver
df6981ceae doc 2020-08-22 07:51:33 -07:00
Michael Davidsaver
11984633dc conditional test of registerAllRecordDeviceDrivers() 2020-08-22 07:50:40 -07:00
Michael Davidsaver
051ba20fe1 fix registerAllRecordDeviceDrivers() prints 2020-08-22 07:50:40 -07:00
Michael Davidsaver
d6cf29e942 add HAS_registerAllRecordDeviceDrivers 2020-08-22 07:50:40 -07:00
Michael Davidsaver
bdd41cca13 move test of registerAllRecordDeviceDrivers() 2020-08-22 07:50:40 -07:00
Michael Davidsaver
e40970bd5e rename dynamic_registerRecordDeviceDriver -> registerAllRecordDeviceDrivers 2020-08-22 07:50:40 -07:00
Michael Davidsaver
9e3d5d52ab iocshRegisterVariable() avoid spurious redefinition warning
Compare the contents, not the container.
2020-08-22 07:50:40 -07:00
Michael Davidsaver
2c389a90d1 test dynamic_registerRecordDeviceDriver() 2020-08-22 07:50:40 -07:00
Michael Davidsaver
8d98387245 add dynamic_registerRecordDeviceDriver()
Use epicsFindSymbol() to build a dynamic and idempotent equivalent
to the code generated by registerRecordDeviceDriver.pl

Also add runRegistrarOnce() to prevent registrars
from running multiple times, except from unittest code.
2020-08-22 07:50:40 -07:00
Andrew Johnson
b36e5262c7 const init a char array from a string value 2020-08-21 17:59:46 -05:00
Andrew Johnson
79d7ac9315 Support undefine in RELEASE files 2020-08-21 16:30:06 -05:00
Andrew Johnson
03c4fe8a8d Merge Record ref updates from 3.15 into 7.0 2020-08-21 15:47:53 -05:00
Andrew Johnson
ad3728d00d Edits to the Record Ref index page 2020-08-21 15:43:48 -05:00
Michael Davidsaver
c465354c67 Set next development version 2020-08-14 13:25:40 -07:00
cc616371b1 allow constant links with numeric 1 element arrays like [42] 2020-06-08 15:05:22 +02:00
45 changed files with 639 additions and 94 deletions

View File

@@ -1,6 +1,12 @@
# .appveyor.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# branches to build
branches:
# whitelist
only:
- 7.0
# Version format
version: base-{branch}-{build}

102
.tools/adjustver.py Executable file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
import logging
import sys
import re
from io import StringIO
_log = logging.getLogger(__name__)
def main(args):
logging.basicConfig(level=args.level)
if args.dev is True:
actions=[
('DEVELOPMENT_FLAG', '1'),
('DEV_SNAPSHOT', '-DEV'),
]
elif args.dev is False:
actions=[
('DEVELOPMENT_FLAG', '0'),
('DEV_SNAPSHOT', ''),
]
elif args.version:
M=re.match(r'R?(\d+).(\d+).(\d+)(?:.(\d+))?(-.*)?', args.version)
actions=[
('SITE_VERSION', None),
('SHORT_VERSION', None),
('MINOR_VERSION', M[2]),
('REVISION', M[2]),
('MODIFICATION', M[3]),
('MAINTENANCE_VERSION', M[3]),
('PATCH_LEVEL', M[4] or '0'),
('DEVELOPMENT_FLAG', '1' if (M[5] or '').upper().endswith('-DEV') else '0'),
('DEV_SNAPSHOT', M[5] or ''),
('MAJOR_VERSION', M[1]),
('VERSION', M[1]), # plain _VERSION must be last to resolve ambiguity
]
elif args.dry_run:
_log.debug('Print existing')
for fname in args.conf:
print('# ', fname)
with open(fname, 'r') as F:
sys.stdout.write(F.read())
return
else:
print('One of --version, --release, --dev, or --dry-run is required')
sys.exit(1)
for name, val in actions:
_log.debug('Pattern "%s" -> "%s"', name, val)
for fname in args.conf:
OUT=StringIO()
with open(fname, 'r') as F:
for line in F:
_log.debug('Line: %s', repr(line))
for name, val in actions:
M = re.match(r'(\s*[A-Z_]+' + name + r'\s*=[\t ]*)(\S*)(\s*)', line)
if M and val is None:
_log.debug('Ignore')
OUT.write(line)
break
elif M:
_log.debug(' Match %s -> %s', M.re.pattern, M.groups())
OUT.write(M[1]+val+M[3])
break
else:
_log.debug('No match')
OUT.write(line)
if args.dry_run:
print('# ', fname)
print(OUT.getvalue())
else:
with open(fname, 'w') as F:
F.write(OUT.getvalue())
def getargs():
from argparse import ArgumentParser
P = ArgumentParser()
P.add_argument('-n','--dry-run', action='store_true', default=False)
P.add_argument('-d','--debug', dest='level', action='store_const',
const=logging.DEBUG, default=logging.INFO)
P.add_argument('-V', '--version', help='A version in R1.2.3-xyz or 1.2.3 form')
P.add_argument('-D', '--dev', action='store_true', default=None)
P.add_argument('-R', '--release', dest='dev', action='store_false')
P.add_argument('conf', nargs='+',
help='A configure/CONFIG_*_VERSION file name')
return P
if __name__=='__main__':
main(getargs().parse_args())

View File

@@ -52,11 +52,11 @@ EPICS_MODIFICATION = 4
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
# Not included in the official EPICS version number if zero
EPICS_PATCH_LEVEL = 1
EPICS_PATCH_LEVEL = 2
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
EPICS_DEV_SNAPSHOT=
EPICS_DEV_SNAPSHOT=-DEV
# No changes should be needed below here

View File

@@ -2,11 +2,11 @@
EPICS_CA_MAJOR_VERSION = 4
EPICS_CA_MINOR_VERSION = 13
EPICS_CA_MAINTENANCE_VERSION = 7
EPICS_CA_MAINTENANCE_VERSION = 8
# Development flag, set to zero for release versions
EPICS_CA_DEVELOPMENT_FLAG = 0
EPICS_CA_DEVELOPMENT_FLAG = 1
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -24,3 +24,5 @@ MSI3_15 = $(EPICS_DATABASE_HOST_BIN)/msi$(HOSTEXE)
# Libraries needed to link a basic IOC
EPICS_BASE_IOC_LIBS = dbRecStd dbCore ca Com
HAS_registerAllRecordDeviceDrivers=YES

View File

@@ -2,11 +2,11 @@
EPICS_DATABASE_MAJOR_VERSION = 3
EPICS_DATABASE_MINOR_VERSION = 18
EPICS_DATABASE_MAINTENANCE_VERSION = 1
EPICS_DATABASE_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions
EPICS_DATABASE_DEVELOPMENT_FLAG = 0
EPICS_DATABASE_DEVELOPMENT_FLAG = 1
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -2,11 +2,11 @@
EPICS_LIBCOM_MAJOR_VERSION = 3
EPICS_LIBCOM_MINOR_VERSION = 18
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
EPICS_LIBCOM_MAINTENANCE_VERSION = 2
# Development flag, set to zero for release versions
EPICS_LIBCOM_DEVELOPMENT_FLAG = 0
EPICS_LIBCOM_DEVELOPMENT_FLAG = 1
# Immediately after a release the MAINTENANCE_VERSION
# will be incremented and the DEVELOPMENT_FLAG set to 1

View File

@@ -22,6 +22,7 @@
# darwin-x86 (Intel based Apple running OSX)
# freebsd-x86 (GNU compiler used for host builds)
# freebsd-x86_64 (GNU compiler used for host builds)
# linux-aarch64 (GNU compiler used for host builds)
# linux-arm (GNU compiler used for host builds)
# linux-ppc (GNU compiler used for host builds)
# linux-ppc64 (GNU compiler used for host builds)
@@ -51,7 +52,6 @@
# windows-x64-debug (MS Visual C++ compiler with debug option for host builds)
# EPICS_HOST_ARCH is a required environment variable
# Do not set EPICS_HOST_ARCH in this file.
# Use base/startup files to set EPICS_HOST_ARCH or
# provide EPICS_HOST_ARCH on the GNU make command line.

View File

@@ -33,7 +33,7 @@ UNINSTALL_DIRS += $(INSTALL_INCLUDE) $(INSTALL_TEMPLATES) $(DIRECTORY_TARGETS)
ifneq ($(INSTALL_LOCATION),$(TOP))
UNINSTALL_DIRS += $(INSTALL_CONFIG)
endif
uninstallDirs:
uninstallDirs: | clean
$(RMDIR) $(UNINSTALL_DIRS)
# Remove the bin and lib directories if they have no sub-directories
@@ -41,12 +41,12 @@ uninstallDirs:
EMPTY_INSTALL_DIRS = \
$(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \
$(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB))
uninstall: archuninstall uninstallDirs
uninstall: archuninstall uninstallDirs | clean
$(RMDIR) $(EMPTY_INSTALL_DIRS)
archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS))
uninstall$(DIVIDER)%:
uninstall$(DIVIDER)%: | clean
$(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \
$(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB))

View File

@@ -0,0 +1,8 @@
# CONFIG.linux-aarch64.Common
#
# Definitions for linux-aarch64 host builds
# Sites may override these definitions in CONFIG_SITE.linux-aarch64.Common
#-------------------------------------------------------
#Include definitions common to unix hosts
include $(CONFIG)/os/CONFIG.UnixCommon.Common

View File

@@ -0,0 +1,8 @@
# CONFIG.linux-aarch64.linux-aarch64
#
# Definitions for native linux-aarch64 builds
# Override these definitions in CONFIG_SITE.linux-aarch64.linux-aarch64
#-------------------------------------------------------
# Include common gnu compiler definitions
include $(CONFIG)/CONFIG.gnuCommon

View File

@@ -16,3 +16,9 @@ COMMANDLINE_LIBRARY = READLINE_NCURSESW
# No other libraries needed
#COMMANDLINE_LIBRARY = READLINE
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.cygwin-x86.cygwin-x86 instead.

View File

@@ -11,10 +11,8 @@
#LDLIBS_READLINE = -lreadline -lcurses
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.cygwin-x86_64.cygwin-x86_64 instead.

View File

@@ -30,3 +30,9 @@
# Needs -lcurses (older versions)
#COMMANDLINE_LIBRARY = READLINE_CURSES
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-aarch64.linux-aarch64 instead.

View File

@@ -33,3 +33,12 @@ COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
# Readline is broken or you don't want use it:
#COMMANDLINE_LIBRARY = EPICS
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-arm.linux-arm instead.
# Permit access to 64-bit file-systems
OP_SYS_CFLAGS += -D_FILE_OFFSET_BITS=64

View File

@@ -34,22 +34,17 @@ COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
#COMMANDLINE_LIBRARY = EPICS
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-x86.linux-x86 instead.
# Permit access to 64-bit file-systems
OP_SYS_CFLAGS += -D_FILE_OFFSET_BITS=64
# Uncomment the followings lines to build with CLANG instead of GCC.
#
#GNU = NO
#CMPLR_CLASS = clang
#CC = clang
#CCC = clang++
# Tune GNU compiler output for a specific 32-bit cpu-type
# (e.g. generic, native, i386, i686, pentium2/3/4, prescott, k6, athlon etc.)
GNU_TUNE_CFLAGS = -mtune=generic
# Developers using a suitable compiler may enable its address sanitizer:
#ENABLE_ASAN = YES

View File

@@ -34,18 +34,14 @@ COMMANDLINE_LIBRARY = $(strip $(if $(wildcard \
#COMMANDLINE_LIBRARY = EPICS
# Uncomment the followings lines to build with CLANG instead of GCC.
#
#GNU = NO
#CMPLR_CLASS = clang
#CC = clang
#CCC = clang++
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in CONFIG_SITE.linux-x86_64.linux-x86_64 instead.
# Tune GNU compiler output for a specific 64-bit cpu-type
# (e.g. generic, native, core2, nocona, k8, opteron, athlon64, barcelona etc.)
GNU_TUNE_CFLAGS = -mtune=generic
# Developers using a suitable compiler may enable its address sanitizer:
#ENABLE_ASAN = YES

View File

@@ -2,10 +2,9 @@
#
# Site-specific settings for all linux targets
# WARNING: Variables that are set in $(CONFIG)/CONFIG.gnuCommon cannot be
# overridden in this file for native builds, e.g. variables such as
# OPT_CFLAGS_YES, WARN_CFLAGS, SHRLIB_LDFLAGS
# They must be set in the host+target specific file instead:
# CONFIG_SITE.<linux-arch>.<linux-arch>
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -6,3 +6,11 @@
# GNU_DIR used when COMMANDLINE_LIBRARY is READLINE
#GNU_DIR=C:/cygwin
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -0,0 +1,12 @@
# CONFIG_SITE.linux-aarch64.linux-aarch64
#
# Site specific definitions for native linux-aarch64 builds
#-------------------------------------------------------
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g

View File

@@ -3,3 +3,17 @@
# Site specific definitions for linux-x86 host - linux-x86 target builds
#-------------------------------------------------------
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# Uncomment the followings lines to build with CLANG instead of GCC.
#
#GNU = NO
#CMPLR_CLASS = clang
#CC = clang
#CCC = clang++

View File

@@ -3,4 +3,17 @@
# Site specific definitions for linux-x86_64 host - linux-x86_64 target builds
#-------------------------------------------------------
# It makes sense to include debugging symbols even in optimized builds
# in case you want to attach gdb to the process or examine a core-dump.
# This does cost disk space, but not memory as debug symbols are not
# loaded into RAM when the binary is loaded.
OPT_CFLAGS_YES += -g
OPT_CXXFLAGS_YES += -g
# Uncomment the followings lines to build with CLANG instead of GCC.
#
#GNU = NO
#CMPLR_CLASS = clang
#CC = clang
#CCC = clang++

View File

@@ -1,6 +1,6 @@
# Installation Instructions {#install}
## EPICS Base Release 7.0.3.1
## EPICS Base Release 7.0.4.1
-----
@@ -237,7 +237,7 @@ Files in the base/startup directory have been provided to help set
required path and other environment variables.
* `EPICS_HOST_ARCH`
Before you can build or use EPICS R3.15, the environment variable
Before you can build or use this EPICS base, the environment variable
`EPICS_HOST_ARCH` must be defined. A perl script EpicsHostArch.pl in
the base/startup directory has been provided to help set
`EPICS_HOST_ARCH.` You should have `EPICS_HOST_ARCH` set to your
@@ -263,7 +263,7 @@ ranlib in your path, and the C compiler may require as and ld in
your path. On solaris systems you need uname in your path.
* `LD_LIBRARY_PATH`
R3.15 shared libraries and executables normally contain the full
EPICS shared libraries and executables normally contain the full
path to any libraries they require. However, if you move the EPICS
files or directories from their build-time location then in order
for the shared libraries to be found at runtime `LD_LIBRARY_PATH`
@@ -336,10 +336,10 @@ A perl tool, makeBaseApp.pl is included in the distribution file. This
script will create a sample application that can be built and then
executed to try out this release of base.
Instructions for building and executing the 3.15 example application
Instructions for building and executing the EPICS example application
can be found in the section "Example Application" of Chapter 2,
"Getting Started", in the "IOC Application Developer's Guide" for this
release. The "Example IOC Application" section briefly explains how to
"Getting Started", in the "EPICS Application Developer's Guide".
The "Example IOC Application" section briefly explains how to
create and build an example application in a user created &lt;top>
directory. It also explains how to run the example application on a
vxWorks ioc or as a process on the host system. By running the example

View File

@@ -17,6 +17,40 @@ should also be read to understand what has changed since earlier releases.
<!-- Insert new items immediately below here ... -->
### Add registerAllRecordDeviceDrivers()
Addition of registerAllRecordDeviceDrivers() as an iocsh function
and in iocshRegisterCommon.h. This function uses dynamic lookup with epicsFindSymbol()
to perform the same function as a generated \*_registerRecordDeviceDriver() function.
This allows dynamic loading/linking of support modules without code generation.
This feature is not intended for use by IOCs constructed using the standard EPICS application
build process and booted from a startup script in an iocBoot subdirectory, although it might
work in some of those cases (the IOC's registerRecordDeviceDriver.cpp file is still required
to link everything into the executable). It also won't work with some static build
configurations or where the symbol table has been stripped from the executable.
### Using a `{const:"string"}` to initialize an array of `DBF_CHAR`
It is now possible to use a JSON Const link with a string value to initialize
an aai or waveform record that has `FTVL` set to `CHAR` through the INP link.
The string length is not limited to 40 characters. This should also work for
aSub record inputs similarly configured as long strings.
```
record(waveform, "wf") {
field(NELM, 100)
field(FTVL, CHAR)
field(INP, {const:"This is a waveform and more than 40 characters"})
}
```
### RELEASE files may use `undefine`
GNUmake added the directive `undefine` in version 3.82 to allow variables to
be undefined. Support for this has been added to the EPICS Release file parser,
so `undefine` can now be used in configure/RELEASE files to unset variables.
## EPICS Release 7.0.4.1
### ARM Architecture Changes

View File

@@ -1,9 +1,12 @@
# Record Reference Documentation {#recordrefmanual}
The following documentation for the record types and menus include with Base was
The documentation below for the record types and menus included with Base was
converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base.
record types supplied with Base. The first two links below are to an external
website where these original reference chapters are now being published.
* [Introduction to EPICS](https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html)
* [Process Database Concepts](https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html)
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInput.html)
* [Fields Common to Output Record Types](dbCommonOutput.html)
@@ -35,7 +38,7 @@ record types supplied with Base.
* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html)
* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html)
* [Permissive Record (permissive)](permissiveRecord.html)
* [Printf Record (prinf)](printfRecord.html)
* [Printf Record (printf)](printfRecord.html)
* [Select Record (sel)](selRecord.html)
* [Sequence Record (seq)](seqRecord.html)
* [State Record (state)](stateRecord.html)

View File

@@ -1048,7 +1048,11 @@ static void event_task (void *pParm)
epicsEventDestroy(evUser->pflush_sem);
epicsMutexDestroy(evUser->lock);
freeListFree(dbevEventUserFreeList, evUser);
if (dbevEventUserFreeList)
freeListFree(dbevEventUserFreeList, evUser);
else
fprintf(stderr, "%s exiting but dbevEventUserFreeList already NULL\n",
__FUNCTION__);
taskwdRemove(epicsThreadGetIdSelf());

View File

@@ -1076,13 +1076,10 @@ static void addToList(struct dbCommon *precord, scan_list *psl)
pse->pscan_list = psl;
ptemp = (scan_element *)ellLast(&psl->list);
while (ptemp) {
if (ptemp->precord->phas <= precord->phas) {
ellInsert(&psl->list, &ptemp->node, &pse->node);
break;
}
if (ptemp->precord->phas <= precord->phas) break;
ptemp = (scan_element *)ellPrevious(&ptemp->node);
}
if (ptemp == NULL) ellAdd(&psl->list, (void *)pse);
ellInsert(&psl->list, (ptemp ? &ptemp->node : NULL), &pse->node);
psl->modified = TRUE;
epicsMutexUnlock(psl->lock);
}
@@ -1108,7 +1105,7 @@ static void deleteFromList(struct dbCommon *precord, scan_list *psl)
return;
}
pse->pscan_list = NULL;
ellDelete(&psl->list, (void *)pse);
ellDelete(&psl->list, &pse->node);
psl->modified = TRUE;
epicsMutexUnlock(psl->lock);
}

View File

@@ -33,6 +33,7 @@
#include "initHooks.h"
#include "iocInit.h"
#include "errSymTbl.h"
#include "iocshRegisterCommon.h"
static dbEventCtx testEvtCtx;
static epicsMutexId testEvtLock;
@@ -98,6 +99,7 @@ void testdbCleanup(void)
db_cleanup_events();
initHookFree();
registryFree();
clearRegistrarOnce();
pdbbase = NULL;
dbmfFreeChunks();
}

View File

@@ -2331,8 +2331,7 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
}
/* Link may be an array constant */
if (pstr[0] == '[' && pstr[len-1] == ']' &&
(strchr(pstr, ',') || strchr(pstr, '"'))) {
if (pstr[0] == '[' && pstr[len-1] == ']') {
pinfo->ltype = CONSTANT;
return 0;
}

View File

@@ -25,5 +25,6 @@ dbCore_SRCS += iocInit.c
dbCore_SRCS += miscIocRegister.c
dbCore_SRCS += dlload.c
dbCore_SRCS += iocshRegisterCommon.c
dbCore_SRCS += registerAllRecordDeviceDrivers.cpp
miscIocRegister_CFLAGS_iOS = -DSYSTEM_UNAVAILABLE

View File

@@ -26,6 +26,16 @@
#define quote(v) #v
#define str(v) quote(v)
/* registerAllRecordDeviceDrivers */
static const iocshArg rrddArg0 = {"pdbbase", iocshArgPdbbase};
static const iocshArg *rrddArgs[] = {&rrddArg0};
static const iocshFuncDef rrddFuncDef =
{"registerAllRecordDeviceDrivers", 1, rrddArgs};
static void rrddCallFunc(const iocshArgBuf *args)
{
iocshSetError(registerAllRecordDeviceDrivers(*iocshPpdbbase));
}
void iocshRegisterCommon(void)
{
const char *targetArch = envGetConfigParamPtr(&EPICS_BUILD_TARGET_ARCH);
@@ -53,4 +63,5 @@ void iocshRegisterCommon(void)
asIocRegister();
miscIocRegister();
libComRegister();
iocshRegister(&rrddFuncDef, rrddCallFunc);
}

View File

@@ -19,9 +19,25 @@
extern "C" {
#endif
struct dbBase;
/* register many useful commands */
epicsShareFunc void iocshRegisterCommon(void);
#define HAS_registerAllRecordDeviceDrivers
epicsShareFunc
long
registerAllRecordDeviceDrivers(struct dbBase *pdbbase);
epicsShareFunc
void runRegistrarOnce(void (*reg_func)(void));
#ifdef EPICS_PRIVATE_API
epicsShareFunc
void clearRegistrarOnce(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,240 @@
/*************************************************************************\
* Copyright (c) 2020 Michael Davidsaver
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <exception>
#include <string>
#include <set>
#include <map>
#include <string.h>
#define EPICS_PRIVATE_API
#include <iocsh.h>
#include <epicsStdio.h>
#include <epicsFindSymbol.h>
#define epicsExportSharedSymbols
#include <registryRecordType.h>
#include <registryDeviceSupport.h>
#include <registryDriverSupport.h>
#include <iocshRegisterCommon.h>
#include <registryCommon.h>
#include <dbAccess.h>
#include <dbBase.h>
#include <dbStaticLib.h>
namespace {
struct compareLoc {
bool operator()(const recordTypeLocation& lhs, const recordTypeLocation& rhs) const
{
if(lhs.prset<rhs.prset)
return true;
else if(lhs.prset>rhs.prset)
return false;
return lhs.sizeOffset<rhs.sizeOffset;
}
};
// storage which will be referenced by pdbbase. Must never be free'd
std::set<std::string> names;
std::set<recordTypeLocation, compareLoc> reclocs;
template<typename T, typename Y>
const T& intern(std::set<T,Y>& coll, const T& val)
{
return *coll.insert(val).first;
}
std::set<void*> registrarsRun;
// gcc circa 4.4 doesn't like iocshVarDef[2] as mapped_type
struct varDef {
iocshVarDef def[2];
};
typedef std::map<std::string, varDef> vardefs_t;
vardefs_t vardefs;
template<typename T>
T lookupAs(const char* a, const char* b =0, const char* c =0, const char* d =0)
{
std::string name(a);
if(b)
name += b;
if(c)
name += c;
if(d)
name += d;
T ret = (T)epicsFindSymbol(name.c_str());
if(!ret) {
fprintf(stderr, "Unable to find symbol '%s' : %s\n", name.c_str(), epicsLoadError());
// all pvar_* are pointers to the exported object
} else if(ret && !*ret) {
fprintf(stderr, "symbol '%s' holds NULL\n", name.c_str());
}
return ret;
}
} // namespace
void runRegistrarOnce(void (*reg_func)(void))
{
if(registrarsRun.find((void*)reg_func)!=registrarsRun.end())
return;
registrarsRun.insert((void*)reg_func);
reg_func();
}
void clearRegistrarOnce()
{
registrarsRun.clear();
}
long
registerAllRecordDeviceDrivers(DBBASE *pdbbase)
{
DBENTRY entry;
if(!pdbbase) {
fprintf(stderr, "Must call dbLoadRecords() before registerAllRecordDeviceDrivers(pdbbase)\n");
return 1;
}
dbInitEntry(pdbbase, &entry);
try {
// for each recordType
for(long status=dbFirstRecordType(&entry); !status; status=dbNextRecordType(&entry)) {
dbRecordType *rtype = entry.precordType;
if(!registryRecordTypeFind(rtype->name)) {
rset** prset = lookupAs<rset**>("pvar_rset_", rtype->name, "RSET");
computeSizeOffset* sizeOffset = lookupAs<computeSizeOffset*>("pvar_func_", rtype->name, "RecordSizeOffset");
if(!prset || !*prset || !sizeOffset || !*sizeOffset) {
fprintf(stderr, "Unable to find support for record type '%s' : %s\n",
rtype->name, epicsLoadError());
return 1;
}
recordTypeLocation sup;
sup.prset = *prset;
sup.sizeOffset = *sizeOffset;
const char *cname = intern<std::string>(names, rtype->name).c_str();
const recordTypeLocation* csup = &intern<recordTypeLocation>(reclocs, sup);
registerRecordTypes(pdbbase, 1, &cname, csup);
}
// for each device support for this recordType
for(ELLNODE *cur = ellFirst(&rtype->devList); cur; cur = ellNext(cur)) {
devSup& devsup = *CONTAINER(cur, devSup, node);
if(registryDeviceSupportFind(devsup.name))
continue;
dset** ptr = lookupAs<dset**>("pvar_dset_", devsup.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find dset for record type '%s' support '%s' : %s\n",
rtype->name, devsup.name, epicsLoadError());
return 1;
}
const char *cname = intern<std::string>(names, devsup.name).c_str();
registerDevices(pdbbase, 1, &cname, ptr);
}
}
// for each driver
for(ELLNODE *cur = ellFirst(&pdbbase->drvList); cur; cur = ellNext(cur)) {
drvSup& drv = *CONTAINER(cur, drvSup, node);
if(registryDriverSupportFind(drv.name))
continue;
drvet** ptr = lookupAs<drvet**>("pvar_drvet_", drv.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find drvet '%s' : %s\n", drv.name, epicsLoadError());
return 1;
}
const char *cname = intern<std::string>(names, drv.name).c_str();
registerDrivers(pdbbase, 1, &cname, ptr);
}
// for each link support
for(ELLNODE *cur = ellFirst(&pdbbase->linkList); cur; cur = ellNext(cur)) {
linkSup& lnk = *CONTAINER(cur, linkSup, node);
jlif** ptr = lookupAs<jlif**>("pvar_jlif_", lnk.jlif_name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find link support '%s' : %s\n", lnk.jlif_name, epicsLoadError());
return 1;
}
registerJLinks(pdbbase, 1, ptr);
}
// for each registrar()
for(ELLNODE *cur = ellFirst(&pdbbase->registrarList); cur; cur = ellNext(cur)) {
dbText& reg = *CONTAINER(cur, dbText, node);
typedef void(*registrar)(void);
registrar* ptr = lookupAs<registrar*>("pvar_func_", reg.text);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find registar '%s' : %s\n", reg.text, epicsLoadError());
return 1;
}
runRegistrarOnce(*ptr);
}
// for each iocsh variable
for(ELLNODE *cur = ellFirst(&pdbbase->variableList); cur; cur = ellNext(cur)) {
dbVariableDef& var = *CONTAINER(cur, dbVariableDef, node);
if(iocshFindVariable(var.name))
continue;
void** ptr = lookupAs<void**>("pvar_", var.type, "_", var.name);
if(!ptr || !*ptr) {
fprintf(stderr, "Unable to find variable '%s' : %s\n", var.name, epicsLoadError());
return 1;
}
vardefs_t::mapped_type& vdef = vardefs[var.name];
vdef.def[0].name = intern<std::string>(names, var.name).c_str();
vdef.def[0].pval = *ptr;
if(strcmp(var.type, "double")==0) {
vdef.def[0].type = iocshArgDouble;
} else if(strcmp(var.type, "int")==0) {
vdef.def[0].type = iocshArgInt;
} else {
fprintf(stderr, "Unsupported type %s of variable '%s' : %s\n", var.type, var.name, epicsLoadError());
return 1;
}
vdef.def[1].name = 0;
iocshRegisterVariable(vdef.def);
}
dbFinishEntry(&entry);
return 0;
} catch(std::exception& e) {
dbFinishEntry(&entry);
fprintf(stderr, "Error: %s\n", e.what());
return 2;
}
}

View File

@@ -489,8 +489,17 @@ static long lnkConst_loadArray(struct link *plink, short dbrType, void *pbuffer,
case sc40:
if (clink->jlink.debug)
printf(" sc40 '%s'\n", clink->value.scalar_string);
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
if (dbrType != DBF_CHAR) {
status = dbFastPutConvertRoutine[DBF_STRING][dbrType]
(clink->value.scalar_string, pbuffer, NULL);
}
else {
/* Long string conversion */
strncpy(pbuffer, clink->value.scalar_string, *pnReq);
((char *)pbuffer)[*pnReq] = 0;
nElems = strlen(pbuffer) + 1;
status = 0;
}
break;
case ai64:

View File

@@ -90,7 +90,7 @@ The VAL field is set to the value returned by the user subroutine.
The value is treated as an error status value where zero mean success.
The output links OUTA ... OUTU will only be used to forward the associated
output value fields when the subroutine has returned a zero status.
If the return status was non-zero, the record will be put into C<SOFT_ALARM>
If the return status was less than zero, the record will be put into C<SOFT_ALARM>
state with severity given by the BRSV field.
The INAM field may be used to name a subroutine that will be called once at
@@ -1363,7 +1363,7 @@ be sent through the OUTA ... OUTU links during record processing.
The previous values of the output fields.
These are used to determine when to post events if EFLG is set to C<ON CHANGE>.
=fields VALA, VALB, VALC, VALD, VALE, VALF, VALG, VALH, VALI, VALJ, VALK, VALL, VALM, VALN, VALO, VALP, VALQ, VALR, VALS, VALT, VALU
=fields OVLA, OVLB, OVLC, OVLD, OVLE, OVLF, OVLG, OVLH, OVLI, OVLJ, OVLK, OVLL, OVLM, OVLN, OVLO, OVLP, OVLQ, OVLR, OVLS, OVLT, OVLU
=cut

View File

@@ -47,13 +47,15 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase);
namespace {
bool verbose = false;
static void exitSubroutine(subRecord *precord) {
epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE);
}
void usage(const char *arg0, const std::string& base_dbd) {
std::cout<<"Usage: "<<arg0<<
" [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf]\n"
" [-D softIoc.dbd] [-h] [-S] [-s] [-v] [-a ascf]\n"
"[-m macro=value,macro2=value2] [-d file.db]\n"
"[-x prefix] [st.cmd]\n"
"\n"
@@ -66,6 +68,8 @@ void usage(const char *arg0, const std::string& base_dbd) {
"\n"
" -s Previously caused a shell to be started. Now accepted and ignored.\n"
"\n"
" -v Verbose, display steps taken during startup.\n"
"\n"
" -a <acf> Access Security configuration file. Macro substitution is\n"
" performed.\n"
"\n"
@@ -103,12 +107,14 @@ void lazy_dbd(const std::string& dbd_file) {
if(lazy_dbd_loaded) return;
lazy_dbd_loaded = true;
if (verbose)
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL),
std::string("Failed to load DBD file: ")+dbd_file);
std::cout<<"dbLoadDatabase(\""<<dbd_file<<"\")\n";
if (verbose)
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
softIoc_registerRecordDeviceDriver(pdbbase);
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
}
@@ -144,7 +150,7 @@ int main(int argc, char *argv[])
int opt;
while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:")) != -1) {
while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:v")) != -1) {
switch (opt) {
case 'h': /* Print usage */
usage(argv[0], dbd_file);
@@ -158,13 +164,15 @@ int main(int argc, char *argv[])
case 'a':
lazy_dbd(dbd_file);
if (!macros.empty()) {
if (verbose)
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
if(asSetSubstitutions(macros.c_str()))
throw std::bad_alloc();
std::cout<<"asSetSubstitutions(\""<<macros<<"\")\n";
}
if (verbose)
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
if(asSetFilename(optarg))
throw std::bad_alloc();
std::cout<<"asSetFilename(\""<<optarg<<"\")\n";
break;
case 'D':
if(lazy_dbd_loaded) {
@@ -174,12 +182,14 @@ int main(int argc, char *argv[])
break;
case 'd':
lazy_dbd(dbd_file);
if (verbose) {
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
if(!macros.empty())
std::cout<<", \""<<macros<<"\"";
std::cout<<")\n";
}
errIf(dbLoadRecords(optarg, macros.c_str()),
std::string("Failed to load: ")+optarg);
std::cout<<"dbLoadRecords(\""<<optarg<<"\"";
if(!macros.empty())
std::cout<<", \""<<macros<<"\"";
std::cout<<")\n";
loadedDb = true;
break;
case 'm':
@@ -190,6 +200,9 @@ int main(int argc, char *argv[])
break;
case 's':
break; // historical
case 'v':
verbose = true;
break;
case 'x':
lazy_dbd(dbd_file);
xmacro = "IOC=";
@@ -207,17 +220,20 @@ int main(int argc, char *argv[])
// run script
// ignore any extra positional args (historical)
std::cout<<"# Begin "<<argv[optind]<<"\n";
if (verbose)
std::cout<<"# Begin "<<argv[optind]<<"\n";
errIf(iocsh(argv[optind]),
std::string("Error in ")+argv[optind]);
std::cout<<"# End "<<argv[optind]<<"\n";
if (verbose)
std::cout<<"# End "<<argv[optind]<<"\n";
epicsThreadSleep(0.2);
loadedDb = true; /* Give it the benefit of the doubt... */
}
if (loadedDb) {
std::cout<<"iocInit()\n";
if (verbose)
std::cout<<"iocInit()\n";
iocInit();
epicsThreadSleep(0.2);
}

View File

@@ -258,7 +258,7 @@ print $out (<< 'END') if %links;
END
print $out (<< "END") for @registrars;
pvar_func_$_();
runRegistrarOnce(pvar_func_$_);
END
print $out (<< 'END') if %variables;

View File

@@ -37,6 +37,9 @@ TESTS += arrayOpTest
TESTPROD_HOST += recMiscTest
recMiscTest_SRCS += recMiscTest.c
ifeq (NO,$(STATIC_BUILD))
recMiscTest_CFLAGS += -DLINK_DYNAMIC
endif
recMiscTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp
testHarness_SRCS += recMiscTest.c
TESTFILES += ../recMiscTest.db

View File

@@ -10,6 +10,7 @@
#include "dbAccess.h"
#include "errlog.h"
#include "dbStaticLib.h"
#include "iocshRegisterCommon.h"
#include "dbUnitTest.h"
#include "testMain.h"
@@ -63,13 +64,22 @@ void recTestIoc_registerRecordDeviceDriver(struct dbBase *);
MAIN(recMiscTest)
{
testPlan(10);
testPlan(12);
testdbPrepare();
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
#ifdef LINK_DYNAMIC
/* A smoke test of registerAllRecordDeviceDrivers to check for idempotence */
testOk1(registerAllRecordDeviceDrivers(pdbbase)==0);
#else
testSkip(2, "only testing registerAllRecordDeviceDrivers() with dynamic linking");
#endif
recTestIoc_registerRecordDeviceDriver(pdbbase);
#ifdef LINK_DYNAMIC
testOk1(registerAllRecordDeviceDrivers(pdbbase)==0);
#endif
testdbReadDatabase("recMiscTest.db", NULL, NULL);

View File

@@ -46,8 +46,10 @@ int main ()
tsSLIter<fred> iter1 = list.firstIter ();
tsSLIter<fred> iter2 = iter1;
tsSLIter<fred> iter3 = iter1;
assert ( iter1 == iter3++ );
assert ( iter3 == ++iter2 );
tsSLIter<fred> itert = iter3++
assert ( iter1 == itert );
itert = ++iter2;
assert ( iter3 == itert );
list.remove ( *pFredII ); // removes pFred
}
list.add ( *pFred );

View File

@@ -181,7 +181,7 @@ void epicsStdCall iocshRegisterVariable (const iocshVarDef *piocshVarDef)
for (l = NULL, p = iocshVariableHead ; p != NULL ; l = p, p = p->next) {
i = strcmp (piocshVarDef->name, p->pVarDef->name);
if (i == 0) {
if (p->pVarDef != piocshVarDef) {
if ((p->pVarDef->type != piocshVarDef->type) && (p->pVarDef->pval != piocshVarDef->pval)) {
errlogPrintf("Warning: iocshRegisterVariable redefining %s.\n",
piocshVarDef->name);
p->pVarDef = piocshVarDef;

View File

@@ -29,6 +29,9 @@
#include <netdb.h>
#include <unistd.h> /* close() and others */
#ifndef IPPORT_USERRESERVED
#define IPPORT_USERRESERVED 5000
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)

View File

@@ -63,10 +63,10 @@ LIBCOM_API int epicsStdCall osiSockAttach()
DWORD titleLength = GetConsoleTitle(title, sizeof(title));
if (titleLength) {
titleLength = strlen (title);
strncat (title, " " EPICS_VERSION_STRING, sizeof(title));
strncat (title, " " EPICS_VERSION_STRING, sizeof(title)-1);
}
else {
strncpy(title, EPICS_VERSION_STRING, sizeof(title));
strncpy(title, EPICS_VERSION_STRING, sizeof(title)-1);
}
title[sizeof(title)-1]= '\0';
SetConsoleTitle(title);

View File

@@ -58,12 +58,32 @@ sub readRelease {
while (<$IN>) {
chomp;
s/ \r $//x; # Shouldn't need this, but sometimes...
s/^ \s+ //x; # Remove leading whitespace
next if m/^ $/x; # Skip blank lines
s/ # .* $//x; # Remove trailing comments
s/ \s+ $//x; # Remove trailing whitespace
next if m/^ \s* $/x; # Skip blank lines
# Handle "undefine <variable>"
my ($uvar) = m/^ undefine \s+ ($MVAR)/x;
if ($uvar ne '') {
delete $Rmacros->{$uvar};
next;
}
# Handle "include <path>" and "-include <path>" syntax
my ($op, $path) = m/^ (-? include) \s+ (.*)/x;
if ($op ne '') {
$path = expandMacros($path, $Rmacros);
if (-e $path) {
&readRelease($path, $Rmacros, $Rapps, $Ractive);
} elsif ($op eq "include") {
warn "EPICS/Release.pm: Include file '$path' not found\n";
}
next;
}
# Handle "<variable> = <path>" plus the := and ?= variants
my ($var, $op, $val) = m/^ \s* ($MVAR) \s* ([?:]?=) \s* (.*) /x;
my ($var, $op, $val) = m/^ ($MVAR) \s* ([?:]?=) \s* (.*) /x;
if ($var ne '') {
$var = 'TOP' if $var =~ m/^ INSTALL_LOCATION /x;
if (exists $Rmacros->{$var}) {
@@ -75,14 +95,6 @@ sub readRelease {
$Rmacros->{$var} = $val;
next;
}
# Handle "include <path>" and "-include <path>" syntax
my ($op, $path) = m/^ \s* (-? include) \s+ (.*)/x;
$path = expandMacros($path, $Rmacros);
if (-e $path) {
&readRelease($path, $Rmacros, $Rapps, $Ractive);
} elsif ($op eq "include") {
warn "EPICS/Release.pm: Include file '$path' not found\n";
}
}
$Ractive->{$file}--;
close $IN;

View File

@@ -35,6 +35,7 @@ sub HostArch {
return 'linux-x86_64' if m/^x86_64-linux/;
return 'linux-x86' if m/^i[3-6]86-linux/;
return 'linux-arm' if m/^arm-linux/;
return 'linux-aarch64' if m/^aarch64-linux/;
return 'windows-x64' if m/^MSWin32-x64/;
return 'win32-x86' if m/^MSWin32-x86/;
return "cygwin-x86_64" if m/^x86_64-cygwin/;