Merge pull request #9 from ralphlange/devel/add-releases-cache-setups

- closes #5, closes #7
This commit is contained in:
Ralph Lange
2019-12-11 15:01:42 +01:00
48 changed files with 2198 additions and 228 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
*.orig
*.log
.*.swp
*.autosave

178
.travis.yml Normal file
View File

@@ -0,0 +1,178 @@
# .travis.yml for testing EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# Note:
# Paths to scripts are different in this test configuration
# (your module has one more directory level: .ci)
language: cpp
compiler: gcc
dist: xenial
cache:
directories:
- $HOME/.cache
env:
global:
- SETUP_PATH=.:.ci
addons:
apt:
packages:
- libreadline6-dev
- libncurses5-dev
- perl
- clang
- g++-mingw-w64-i686
- g++-mingw-w64-x86-64
- qemu-system-x86
install:
- ./travis/prepare.sh
script:
- ./travis-test.sh
# If you need to do more during install and build,
# add a local directory to your module and do e.g.
# - ./.ci-local/travis/install-extras.sh
# Define build jobs
# Well-known variables to use
# SET source setup file
# EXTRA content will be added to make command line
# STATIC set to YES for static build (default: NO)
# TEST set to NO to skip running the tests (default: YES)
# VV set to make build scripts verbose (default: unset)
# Usually from setup files, but may be specified or overridden
# on a job line
# MODULES list of dependency modules
# BASE branch or release tag name of the EPICS Base to use
# <MODULE> branch or release tag for a specific module
# ... see README for setup file syntax description
jobs:
include:
# Run unit tests on Linux and Mac
- env: SET=test00
- env: SET=test00
os: osx
# Compile the example application
# using the build configurations from full makeBaseApp example
- env: SET=test01
- env: SET=test01
compiler: clang
- env: VV="" SET=test01
- env: SET=test01 EXTRA="CMD_CXXFLAGS=-std=c++11"
- env: SET=test01 EXTRA="CMD_CXXFLAGS=-std=c++11"
compiler: clang
# trusty is pretty close to RHEL7
- env: SET=test01
dist: trusty
- env: SET=test01 EXTRA="CMD_CXXFLAGS=-std=c++11"
dist: trusty
# Cross-compilation to Windows using MinGW and WINE
- env: SET=test01 WINE=32 TEST=NO STATIC=YES
compiler: mingw
- env: SET=test01 WINE=64 TEST=NO STATIC=YES
compiler: mingw
# dynamic (DLL) builds are broken on xenial
- env: SET=test01 WINE=32 TEST=NO STATIC=NO
dist: bionic
compiler: mingw
- env: SET=test01 WINE=64 TEST=NO STATIC=NO
dist: bionic
compiler: mingw
# Cross-compilation to RTEMS
# (needs EPICS Base >= 3.16.2)
- env: SET=test01 RTEMS=4.10 TEST=NO
- env: SET=test01 RTEMS=4.9 TEST=NO
# Other gcc versions (adding as an extra package)
- env: SET=test01
compiler: gcc-6
addons: { apt: { packages: ["g++-6"], sources: ["ubuntu-toolchain-r-test"] } }
- env: SET=test01
compiler: gcc-7
addons: { apt: { packages: ["g++-7"], sources: ["ubuntu-toolchain-r-test"] } }
# MacOS build
# SNCSEQ 2.2.7 fails to build on MacOS; currently needs master
- env: SET=test01 SNCSEQ=master
os: osx
compiler: clang
addons: { homebrew: { packages: ["re2c"], update: true } }
# Base 3.15 builds
# ================
- env: BASE=R3.15.7 SET=test01
- env: BASE=R3.15.7 SET=test01 WINE=64 TEST=NO STATIC=YES
dist: bionic
compiler: mingw
# The DLL build for this Base version is known to fail
# - env: BASE=R3.15.7 SET=test01 WINE=64 TEST=NO STATIC=NO
# dist: bionic
# compiler: mingw
# Cross-compilation to RTEMS
# (needs EPICS Base >= 3.16.2)
- env: BASE=R3.16.2 SET=test01 RTEMS=4.10 TEST=NO
dist: trusty
- env: BASE=R3.16.2 SET=test01 RTEMS=4.9 TEST=NO
dist: trusty
# SNCSEQ 2.2.7 fails to build on MacOS; currently needs master
- env: BASE=R3.15.7 SET=test01 SNCSEQ=master
os: osx
compiler: clang
addons: { homebrew: { packages: ["re2c"], update: true } }
# Base 3.14 builds
# ================
- env: BASE=R3.14.12.8 SET=test01
- env: BASE=R3.14.12.8 SET=test01 WINE=64 TEST=NO STATIC=YES
dist: bionic
compiler: mingw
# The DLL build for this Base version is known to fail
# - env: BASE=R3.14.12.8 SET=test01 WINE=64 TEST=NO STATIC=NO
# dist: bionic
# compiler: mingw
# SNCSEQ 2.2.7 fails to build on MacOS; currently needs master
- env: BASE=R3.14.12.8 SET=test01 SNCSEQ=master
os: osx
compiler: clang
addons: { homebrew: { packages: ["re2c"], update: true } }

31
Makefile Normal file
View File

@@ -0,0 +1,31 @@
# Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG
# Directories to build, any order
DIRS += configure
DIRS += $(wildcard *Sup)
DIRS += $(wildcard *App)
DIRS += $(wildcard *Top)
DIRS += $(wildcard iocBoot)
# The build order is controlled by these dependency rules:
# All dirs except configure depend on configure
$(foreach dir, $(filter-out configure, $(DIRS)), \
$(eval $(dir)_DEPEND_DIRS += configure))
# Any *App dirs depend on all *Sup dirs
$(foreach dir, $(filter %App, $(DIRS)), \
$(eval $(dir)_DEPEND_DIRS += $(filter %Sup, $(DIRS))))
# Any *Top dirs depend on all *Sup and *App dirs
$(foreach dir, $(filter %Top, $(DIRS)), \
$(eval $(dir)_DEPEND_DIRS += $(filter %Sup %App, $(DIRS))))
# iocBoot depends on all *App dirs
iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS))
# Add any additional dependency rules here:
include $(TOP)/configure/RULES_TOP

222
README.md
View File

@@ -1,62 +1,198 @@
# Continuous Integration Scripts for EPICS Modules
The scripts in this repository are intended to provide a common,
The scripts inside this repository are intended to provide a common,
easy-to-use and flexible way to add Continuous Integration to EPICS
software modules, e.g. Device Support modules.
software modules, e.g. Device or Driver Support modules.
By including this repository as a Git Submodule, your module will
always use an explicit commit, i.e. a fixed version of the scripts.
That ensures that further development of these scripts cannot break
your setup.
By including this repository as a Git Submodule, you will be able to
use the same flexible, powerful CI setup that EPICS Bases uses,
including a mechanism to specify sets of dependent modules
(with versions) that you want to compile your module against.
## Travis-CI
By using the submodule mechnism, your module will always use an
explicit commit, i.e. a fixed version of the scripts.
This ensures that any further development of the ci-scripts will
never break existing use.
### Features
## This Repository
- Compile against different branches or releases of EPICS Base
- Use different versions of compilers (gcc, clang)
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10
- Compile on MacOS
In addition to the scripts themselves (in the subdirectories),
this repository contains the test suite that is used to verify
functionality and features of the ci-scripts.
You are welcome to use the test suite as a reference, but keep in
mind that in your module the path to the scripts has one level more
(e.g., `./travis/abc` here would be `./.ci/travis/abc` in your
module).
Also, a test suite might not show the same level of quality as an
example.
## Features
- Compile against different branches or releases of EPICS Base and
additional dependencies (modules like asyn, std, etc.).
- Define settings files that declare sets of dependencies
with their versions and locations.
- Define hook scripts for any dependency.
Hooks are run on the dependency module before it is compiled, so
the module can be patched or further configured.
- Define static or shared builds (executables, libraries).
- Run tests (using the EPICS unit test suite).
## Supported CI Services
### Travis-CI
- Use different compilers (gcc, clang)
- Use different gcc versions
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10 (Base >= 3.16.2)
- Compile on MacOS
- Built dependencies are cached (for faster builds)
### How to Use these Scripts
### How to Use the CI-Scripts
1. Get an account on [Travis-CI](https://travis-ci.org/), connect
it to your GitHub account and activate your support module's
repository. For more details, please refer to the
[Travis-CI Tutorial](https://docs.travis-ci.com/user/tutorial/).
Make sure to use `travis-ci.org` and not their `.com` site.
1. Get an account on a supported CI service provider platform.
(e.g. [Travis-CI](https://travis-ci.org/),
Appveyor, Azure Pipelines...)
1. In your Support Module, add this respository as a Git Submodule
(name suggestion: `.ci`).
(More details in the specific README of the subdirectory.)
2. In your Support Module, add this ci-scripts respository
as a Git Submodule (name suggestion: `.ci`).
```
$ git submodule add https://github.com/epics-base/ci-scripts .ci
```
1. Create a Travis configuration by copying one of the examples.
```
$ cp .ci/.travis.yml.example-full .travis.yml
```
1. Edit the `.travis.yml` configuration to include the jobs you want
Travis to run.
1. Push your changes and check
[travis-ci.org](https://travis-ci.org/) for your build results.
3. Create setup files for different sets of dependencies you
want to compile against. (See below.)
## Releases and Numbering
E.g., a setup file `stable.set` specifying
```
MODULES=sncseq asyn
BASE=R3.15.6
ASYN=R4-34
SNCSEQ=R2-2-7
```
will compile against the EPICS Base release 3.15.6, the Sequencer
release 2.2.7 and release 4.34 of asyn.
(Any settings can be overridden from `.travis.yml`.)
4. Create a configuration for the CI service by copying one of
the examples provided in the service specific subdirectory
and editing it to include the jobs you want the service to run.
Use your setup by defining e.g. `SET=stable` in the environment of
a job.
5. Push your changes and check the CI service for your build results.
## Setup Files
Your module might depend on EPICS Base and a few other support modules.
(E.g., a specific driver might need StreamDevice, ASYN and the Sequencer.)
In that case, building against every possible combination of released
versions of those dependencies is not possible:
Base (37) x StreamDevice (50) x ASYN (40) x Sequencer (51) would produce
more than 3.7 million different combinations, i.e. build jobs.
A more reasonable approach is to create a few setups, each being a
combination of dependency releases, that do a few scans of the available
"version space". One for the oldest versions you want to support, one or two
for stable versions that many of your users have in production, one for the
latest released versions and one for the development branches.
## Setup File Syntax
Setup files are loaded by the bash scripts. They are found by searching
the locations in `SETUP_PATH` (space or colon separated list of directories,
relative to your module's root directory).
Setup files can include other setup files by calling `include <setup>`
(omitting the `.set` extension of the setup file). The configured
`SETUP_PATH` is searched for the include.
Any `VAR=value` setting of a variable is only executed if `VAR` is unset or
empty. That way any settings can be overridden by settings in `.travis.yml`.
Empty lines or lines starting with `#` are ignored.
`MODULES="<list of names>"` should list the dependencies (software modules)
by using their well-known slugs, separated by spaces.
EPICS Base (slug: `base`) will always be a dependency and will be added and
compiled first. The other dependencies are added and compiled in the order
they are defined in `MODULES`.
`REPOOWNER=<name>` sets the default GitHub owner (or organization) for all
dependency modules. Useful if you want to compile against a complete set
of dependencies forked into your private GitHub area.
For any module mentioned as `foo` in the `MODULES` setting (and for `BASE`),
the following settings can be configured:
`FOO=<version>` Set version of the module that should be used. Must either
be a *tag* name (in that case the module is checked out into Travis' cache
system) or a *branch* name (in that case the module is always checked out
and recompiled as part of the job). [default: `master`]
`FOO_REPONAME=<name>` Set the name of the remote repository as `<name>.git`.
[default is the slug in lower case: `foo`]
`FOO_REPOOWNER=<name>` Set the name of the GitHub owner (or organization)
that the module repository can be found under.
`FOO_REPOURL="<url>"` Set the complete URL of the remote repository.
The default URL for the repository is pointing to GitHub, under
`$FOO_REPOOWNER` else `$REPOOWNER` else `epics-modules`,
using `$FOO_REPONAME` else `foo` and the extension`.git`.
`FOO_DEPTH=<number>` Set the depth of the git clone operation. Use 0 for a
full clone. [default: 5]
`FOO_RECURSIVE=YES/NO` Set to `NO` (or `0`) for a flat clone without
recursing into submodules. [default is including submodules: `YES`]
`FOO_DIRNAME=<name>` Set the local directory name for the checkout. This will
be always be extended by the release or branch name as `<name>-<version>`.
[default is the slug in lower case: `foo`]
`FOO_HOOK=<script>` Set the name of a script that will be run after cloning
the module, before compiling it. Working directory when running the script
is the root of the targeted module (e.g. `.../.cache/foo-1.2`).
[default: no hooks are run]
`FOO_VARNAME=<name>` Set the name that is used for the module when creating
the `RELEASE.local` files. [default is the slug in upper case: `FOO`]
The ci-scripts module contains default settings for widely used modules, so
that usually it is sufficient to set `FOO=<version>`.
You can find the list of supported (and tested) modules in `defaults.set`.
Feel free to suggest more default settings using a Pull Request.
## Debugging
Setting `VV=1` in your `.travis.yml` configuration for a specific job
will run the job with high verbosity, printing every command as it is being
executed and switching the dependency builds to higher verbosity.
## Release Numbering of this Module
Major release numbers refer to the API, which is more or less defined
by the `.travis.yml.example-full` configuration example.
Changing this file for the existing configuration options or to add
new configurations options will usually cause a new major release.
by the full configuration examples in the service specific
subdirectories.
If one of these files has to be changed for the existing configuration
options or important new options are being added, a new major release
is created.
Minor release numbers refer to bugfixes that should not require a user
module (i.e., its `.travis.yml`) to be changed.
Minor release numbers refer to bugfixes that should not require the
configuration inside a user module to be changed.
Again: using git submodule to include these scripts means that user
modules always work with a fixed, frozen version of these scripts.
I.e., developments in the ci-scripts will never break an existing
application.
Again: using the git submodule mechanism to include these scripts means
that user modules always work with a fixed, frozen version.
I.e., developments in the ci-scripts repository will never break an\
existing application.
These release numbering considerations are just a hint to assess the
risk when updating the submodule.
risks when updating the submodule.

29
configure/CONFIG Normal file
View File

@@ -0,0 +1,29 @@
# CONFIG - Load build configuration data
#
# Do not make changes to this file!
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
include $(TOP)/configure/CONFIG_SITE
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

43
configure/CONFIG_SITE Normal file
View File

@@ -0,0 +1,43 @@
# CONFIG_SITE
# Make any application-specific changes to the EPICS build
# configuration variables in this file.
#
# Host/target specific settings can be specified in files named
# CONFIG_SITE.$(EPICS_HOST_ARCH).Common
# CONFIG_SITE.Common.$(T_A)
# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
# CHECK_RELEASE controls the consistency checking of the support
# applications pointed to by the RELEASE* files.
# Normally CHECK_RELEASE should be set to YES.
# Set CHECK_RELEASE to NO to disable checking completely.
# Set CHECK_RELEASE to WARN to perform consistency checking but
# continue building even if conflicts are found.
CHECK_RELEASE = YES
# Set this when you only want to compile this application
# for a subset of the cross-compiled target architectures
# that Base is built for.
#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32
# To install files into a location other than $(TOP) define
# INSTALL_LOCATION here.
#INSTALL_LOCATION=</absolute/path/to/install/top>
# Set this when the IOC and build host use different paths
# to the install location. This may be needed to boot from
# a Microsoft FTP server say, or on some NFS configurations.
#IOCS_APPL_TOP = </IOC's/absolute/path/to/install/top>
# For application debugging purposes, override the HOST_OPT and/
# or CROSS_OPT settings from base/configure/CONFIG_SITE
#HOST_OPT = NO
#CROSS_OPT = NO
# These allow developers to override the CONFIG_SITE variable
# settings without having to modify the configure/CONFIG_SITE
# file itself.
-include $(TOP)/../CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

8
configure/Makefile Normal file
View File

@@ -0,0 +1,8 @@
TOP=..
include $(TOP)/configure/CONFIG
TARGETS = $(CONFIG_TARGETS)
CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS)))
include $(TOP)/configure/RULES

43
configure/RELEASE Normal file
View File

@@ -0,0 +1,43 @@
# RELEASE - Location of external support modules
#
# IF YOU MAKE ANY CHANGES to this file you must subsequently
# do a "gnumake rebuild" in this application's top level
# directory.
#
# The build process does not check dependencies against files
# that are outside this application, thus you should do a
# "gnumake rebuild" in the top level directory after EPICS_BASE
# or any other external module pointed to below is rebuilt.
#
# Host- or target-specific settings can be given in files named
# RELEASE.$(EPICS_HOST_ARCH).Common
# RELEASE.Common.$(T_A)
# RELEASE.$(EPICS_HOST_ARCH).$(T_A)
#
# This file is parsed by both GNUmake and an EPICS Perl script,
# so it can ONLY contain definititions of paths to other support
# modules, variable definitions that are used in module paths,
# and include statements that pull in other RELEASE files.
# Variables may be used before their values have been set.
# Build variables that are NOT used in paths should be set in
# the CONFIG_SITE file.
# Variables and paths to dependent modules:
#MODULES = /path/to/modules
#MYMODULE = $(MODULES)/my-module
# If using the sequencer, point SNCSEQ at its top directory:
#SNCSEQ = $(MODULES)/seq-ver
# EPICS_BASE should appear last so earlier modules can override stuff:
EPICS_BASE = /home/ralph/work/EPICS/V3/base-3.15.6
# Set RULES here if you want to use build rules from somewhere
# other than EPICS_BASE:
#RULES = $(MODULES)/build-rules
# These allow developers to override the RELEASE variable settings
# without having to modify the configure/RELEASE file itself.
-include $(TOP)/../RELEASE.local
-include $(TOP)/configure/RELEASE.local

6
configure/RULES Normal file
View File

@@ -0,0 +1,6 @@
# RULES
include $(CONFIG)/RULES
# Library should be rebuilt because LIBOBJS may have changed.
$(LIBNAME): ../Makefile

2
configure/RULES.ioc Normal file
View File

@@ -0,0 +1,2 @@
#RULES.ioc
include $(CONFIG)/RULES.ioc

2
configure/RULES_DIRS Normal file
View File

@@ -0,0 +1,2 @@
#RULES_DIRS
include $(CONFIG)/RULES_DIRS

3
configure/RULES_TOP Normal file
View File

@@ -0,0 +1,3 @@
#RULES_TOP
include $(CONFIG)/RULES_TOP

35
defaults.set Normal file
View File

@@ -0,0 +1,35 @@
# EPICS Base
BASE_DIRNAME=base
BASE_REPONAME=epics-base
BASE_REPOOWNER=epics-base
BASE_VARNAME=EPICS_BASE
PVDATA_DIRNAME=pvData
PVDATA_REPONAME=pvDataCPP
PVDATA_REPOOWNER=epics-base
PVACCESS_DIRNAME=pvAccess
PVACCESS_REPONAME=pvAccessCPP
PVACCESS_REPOOWNER=epics-base
NTYPES_DIRNAME=normativeTypes
NTYPES_REPONAME=normativeTypesCPP
NTYPES_REPOOWNER=epics-base
# Sequencer
SNCSEQ_REPOURL=https://www-csr.bessy.de/control/SoftDist/sequencer/repo/branch-2-2.git
SNCSEQ_DEPTH=0
SNCSEQ_DIRNAME=seq
# StreamDevice
STREAM_REPONAME=StreamDevice
STREAM_REPOOWNER=paulscherrerinstitute
# The default settings also work (and are tested) for:
# asyn
# std
# calc
# autosave
# busy
# sscan
# iocStats

18
exampleApp/Db/Makefile Normal file
View File

@@ -0,0 +1,18 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS BELOW HERE
# Install databases, templates & substitutions like this
DB += dbExample1.db
DB += dbExample2.db
DB += dbSubExample.db
DB += user.substitutions
# If <anyname>.db template is not named <anyname>*.template add
# <anyname>_TEMPLATE = <templatename>
include $(TOP)/configure/RULES
#----------------------------------------
# ADD EXTRA GNUMAKE RULES BELOW HERE

View File

@@ -0,0 +1,62 @@
record(ai, "$(user):aiExample")
{
field(DESC, "Analog input")
field(INP, "$(user):calcExample.VAL NPP NMS")
field(EGUF, "10")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(calc, "$(user):calcExample")
{
field(DESC, "Counter")
field(SCAN,"1 second")
field(FLNK, "$(user):aiExample")
field(CALC, "(A<B)?(A+C):D")
field(INPA, "$(user):calcExample.VAL NPP NMS")
field(INPB, "9")
field(INPC, "1")
field(INPD, "0")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(xxx, "$(user):xxxExample")
{
field(DESC, "xxx record")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(compress,"$(user):compressExample")
{
field(DESC, "Circular buffer")
field(INP,"$(user):aiExample.VAL CP NMS")
field(ALG,"Circular Buffer")
field(NSAM,"10")
field(HOPR,"10")
field(EGU,"Counts")
}

View File

@@ -0,0 +1,40 @@
record(calc, "$(user):calcExample$(no)")
{
alias("$(user):calc$(no)")
field(DESC, "Counter No. $(no)")
field(SCAN,"$(scan)")
field(FLNK, "$(user):aiExample$(no)")
field(CALC, "(A<B)?(A+C):D")
field(INPA, "$(user):calcExample$(no).VAL NPP NMS")
field(INPB, "9")
field(INPC, "1")
field(INPD, "0")
field(EGU, "Counts")
field(HOPR, "10")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
record(ai, "$(user):aiExample$(no)")
{
field(DESC, "Analog input No. $(no)")
field(INP, "$(user):calcExample$(no).VAL NPP NMS")
field(EGUF, "10")
field(EGU, "Counts")
field(HOPR, "10")
field(LOPR, "0")
field(HIHI, "8")
field(HIGH, "6")
field(LOW, "4")
field(LOLO, "2")
field(HHSV, "MAJOR")
field(HSV, "MINOR")
field(LSV, "MINOR")
field(LLSV, "MAJOR")
}
alias("$(user):aiExample$(no)","$(user):ai$(no)")

View File

@@ -0,0 +1,13 @@
record(sub,"$(user):subExample")
{
field(INAM,"mySubInit")
field(SNAM,"mySubProcess")
}
record(aSub,"$(user):aSubExample")
{
field(INAM,"myAsubInit")
field(SNAM,"myAsubProcess")
field(FTA,"DOUBLE")
field(NOA,"10")
field(INPA,"$(user):compressExample CPP")
}

View File

@@ -0,0 +1,12 @@
# Example substitutions file
file "db/dbExample1.db" {
{ user = "ralph" }
}
file db/dbExample2.db {
pattern { user, no, scan }
{ "ralph", 1, "1 second" }
{ "ralph", 2, "2 second" }
{ "ralph", 3, "5 second" }
}

8
exampleApp/Makefile Normal file
View File

@@ -0,0 +1,8 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Src*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*))
DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*))
include $(TOP)/configure/RULES_DIRS

79
exampleApp/src/Makefile Normal file
View File

@@ -0,0 +1,79 @@
TOP=../..
include $(TOP)/configure/CONFIG
#----------------------------------------
# ADD MACRO DEFINITIONS BELOW HERE
# xxxRecord.h will be created from xxxRecord.dbd
DBDINC += xxxRecord
# Install xxxSupport.dbd into <top>/dbd
DBD += xxxSupport.dbd
# Build an IOC support library
LIBRARY_IOC += exampleSupport
# Compile and add the code to the support library
exampleSupport_SRCS += xxxRecord.c
exampleSupport_SRCS += devXxxSoft.c
# Link locally-provided code into the support library,
# rather than directly into the IOC application.
# This is required for Windows DLL builds.
exampleSupport_SRCS += dbSubExample.c
exampleSupport_SRCS += exampleHello.c
exampleSupport_SRCS += initTrace.c
exampleSupport_LIBS += $(EPICS_BASE_IOC_LIBS)
# Build the IOC application
PROD_IOC = example
# example.dbd will be created and installed
DBD += example.dbd
# example.dbd will include these files:
example_DBD += base.dbd
example_DBD += xxxSupport.dbd
example_DBD += dbSubExample.dbd
example_DBD += exampleHello.dbd
example_DBD += initTrace.dbd
# example_registerRecordDeviceDriver.cpp derives from example.dbd
example_SRCS += example_registerRecordDeviceDriver.cpp
# Build the main IOC entry point where needed
example_SRCS_DEFAULT += exampleMain.cpp
example_SRCS_vxWorks += -nil-
# Link in the code from our support library
example_LIBS += exampleSupport
# To build SNL programs, SNCSEQ must be defined
# in the <top>/configure/RELEASE file
ifneq ($(SNCSEQ),)
# Build sncExample into exampleSupport
sncExample_SNCFLAGS += +r
example_DBD += sncExample.dbd
# A .stt sequence program is *not* pre-processed:
exampleSupport_SRCS += sncExample.stt
exampleSupport_LIBS += seq pv
example_LIBS += seq pv
# Build sncProgram as a standalone program
PROD_HOST += sncProgram
sncProgram_SNCFLAGS += +m
# A .st sequence program *is* pre-processed:
sncProgram_SRCS += sncProgram.st
sncProgram_LIBS += seq pv
sncProgram_LIBS += $(EPICS_BASE_HOST_LIBS)
endif
# Finally link IOC to the EPICS Base libraries
example_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES
#----------------------------------------
# ADD EXTRA GNUMAKE RULES BELOW HERE

View File

@@ -0,0 +1,49 @@
#include <stdio.h>
#include <dbDefs.h>
#include <registryFunction.h>
#include <subRecord.h>
#include <aSubRecord.h>
#include <epicsExport.h>
int mySubDebug;
static long mySubInit(subRecord *precord)
{
if (mySubDebug)
printf("Record %s called mySubInit(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long mySubProcess(subRecord *precord)
{
if (mySubDebug)
printf("Record %s called mySubProcess(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long myAsubInit(aSubRecord *precord)
{
if (mySubDebug)
printf("Record %s called myAsubInit(%p)\n",
precord->name, (void*) precord);
return 0;
}
static long myAsubProcess(aSubRecord *precord)
{
if (mySubDebug)
printf("Record %s called myAsubProcess(%p)\n",
precord->name, (void*) precord);
return 0;
}
/* Register these symbols for use by IOC code: */
epicsExportAddress(int, mySubDebug);
epicsRegisterFunction(mySubInit);
epicsRegisterFunction(mySubProcess);
epicsRegisterFunction(myAsubInit);
epicsRegisterFunction(myAsubProcess);

View File

@@ -0,0 +1,5 @@
variable(mySubDebug)
function(mySubInit)
function(mySubProcess)
function(myAsubInit)
function(myAsubProcess)

View File

@@ -0,0 +1,58 @@
/* devXxxSoft.c */
/* Example device support module */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "alarm.h"
#include "cvtTable.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "recSup.h"
#include "devSup.h"
#include "link.h"
#include "xxxRecord.h"
#include "epicsExport.h"
/*Create the dset for devXxxSoft */
static long init_record();
static long read_xxx();
struct {
long number;
DEVSUPFUN report;
DEVSUPFUN init;
DEVSUPFUN init_record;
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_xxx;
}devXxxSoft={
5,
NULL,
NULL,
init_record,
NULL,
read_xxx,
};
epicsExportAddress(dset,devXxxSoft);
static long init_record(pxxx)
struct xxxRecord *pxxx;
{
if(recGblInitConstantLink(&pxxx->inp,DBF_DOUBLE,&pxxx->val))
pxxx->udf = FALSE;
return(0);
}
static long read_xxx(pxxx)
struct xxxRecord *pxxx;
{
long status;
status = dbGetLink(&(pxxx->inp),DBF_DOUBLE, &(pxxx->val),0,0);
/*If return was succesful then set undefined false*/
if(!status) pxxx->udf = FALSE;
return(0);
}

View File

@@ -0,0 +1,31 @@
/* Example showing how to register a new command with iocsh */
#include <stdio.h>
#include <epicsExport.h>
#include <iocsh.h>
/* This is the command, which the vxWorks shell will call directly */
void hello(const char *name) {
if (name) {
printf("Hello %s, from example\n", name);
} else {
puts("Hello from example");
}
}
/* Information needed by iocsh */
static const iocshArg helloArg0 = {"name", iocshArgString};
static const iocshArg *helloArgs[] = {&helloArg0};
static const iocshFuncDef helloFuncDef = {"hello", 1, helloArgs};
/* Wrapper called by iocsh, selects the argument types that hello needs */
static void helloCallFunc(const iocshArgBuf *args) {
hello(args[0].sval);
}
/* Registration routine, runs at startup */
static void helloRegister(void) {
iocshRegister(&helloFuncDef, helloCallFunc);
}
epicsExportRegistrar(helloRegister);

View File

@@ -0,0 +1 @@
registrar(helloRegister)

View File

@@ -0,0 +1,23 @@
/* exampleMain.cpp */
/* Author: Marty Kraimer Date: 17MAR2000 */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "epicsExit.h"
#include "epicsThread.h"
#include "iocsh.h"
int main(int argc,char *argv[])
{
if(argc>=2) {
iocsh(argv[1]);
epicsThreadSleep(.2);
}
iocsh(NULL);
epicsExit(0);
return(0);
}

View File

@@ -0,0 +1,39 @@
/* initTrace.c */
/*
* An initHook routine to trace the iocInit() process.
* Prints out the name of each state as it is reached.
*/
#include <stdio.h>
#include "initHooks.h"
#include "epicsExport.h"
#include "iocsh.h"
static void trace(initHookState state) {
printf("iocInit: Reached %s\n", initHookName(state));
}
int traceIocInit(void) {
static int done = 0;
if (done)
return -1;
done = 1;
initHookRegister(trace);
puts("iocInit will be traced");
return 0;
}
static const iocshFuncDef traceInitFuncDef = {"traceIocInit", 0, NULL};
static void traceInitFunc(const iocshArgBuf *args) {
traceIocInit();
}
static void initTraceRegister(void) {
iocshRegister(&traceInitFuncDef, traceInitFunc);
}
epicsExportRegistrar(initTraceRegister);

View File

@@ -0,0 +1 @@
registrar(initTraceRegister)

View File

@@ -0,0 +1 @@
registrar(sncExampleRegistrar)

View File

@@ -0,0 +1,22 @@
program sncExample
double v;
assign v to "{user}:aiExample";
monitor v;
ss ss1 {
state init {
when (delay(10)) {
printf("sncExample: Startup delay over\n");
} state low
}
state low {
when (v > 5.0) {
printf("sncExample: Changing to high\n");
} state high
}
state high {
when (v <= 5.0) {
printf("sncExample: Changing to low\n");
} state low
}
}

View File

@@ -0,0 +1 @@
#include "../sncExample.stt"

273
exampleApp/src/xxxRecord.c Normal file
View File

@@ -0,0 +1,273 @@
/* xxxRecord.c */
/* Example record support module */
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "epicsMath.h"
#include "alarm.h"
#include "dbAccess.h"
#include "recGbl.h"
#include "dbEvent.h"
#include "dbDefs.h"
#include "dbAccess.h"
#include "devSup.h"
#include "errMdef.h"
#include "recSup.h"
#include "special.h"
#define GEN_SIZE_OFFSET
#include "xxxRecord.h"
#undef GEN_SIZE_OFFSET
#include "epicsExport.h"
/* Create RSET - Record Support Entry Table */
#define report NULL
#define initialize NULL
static long init_record();
static long process();
#define special NULL
#define get_value NULL
#define cvt_dbaddr NULL
#define get_array_info NULL
#define put_array_info NULL
static long get_units();
static long get_precision();
#define get_enum_str NULL
#define get_enum_strs NULL
#define put_enum_str NULL
static long get_graphic_double();
static long get_control_double();
static long get_alarm_double();
rset xxxRSET={
RSETNUMBER,
report,
initialize,
init_record,
process,
special,
get_value,
cvt_dbaddr,
get_array_info,
put_array_info,
get_units,
get_precision,
get_enum_str,
get_enum_strs,
put_enum_str,
get_graphic_double,
get_control_double,
get_alarm_double
};
epicsExportAddress(rset,xxxRSET);
typedef struct xxxset { /* xxx input dset */
long number;
DEVSUPFUN dev_report;
DEVSUPFUN init;
DEVSUPFUN init_record; /*returns: (-1,0)=>(failure,success)*/
DEVSUPFUN get_ioint_info;
DEVSUPFUN read_xxx;
}xxxdset;
static void checkAlarms(xxxRecord *prec);
static void monitor(xxxRecord *prec);
static long init_record(void *precord,int pass)
{
xxxRecord *prec = (xxxRecord *)precord;
xxxdset *pdset;
long status;
if (pass==0) return(0);
if(!(pdset = (xxxdset *)(prec->dset))) {
recGblRecordError(S_dev_noDSET,(void *)prec,"xxx: init_record");
return(S_dev_noDSET);
}
/* must have read_xxx function defined */
if( (pdset->number < 5) || (pdset->read_xxx == NULL) ) {
recGblRecordError(S_dev_missingSup,(void *)prec,"xxx: init_record");
return(S_dev_missingSup);
}
if( pdset->init_record ) {
if((status=(*pdset->init_record)(prec))) return(status);
}
return(0);
}
static long process(void *precord)
{
xxxRecord *prec = (xxxRecord *)precord;
xxxdset *pdset = (xxxdset *)(prec->dset);
long status;
unsigned char pact=prec->pact;
if( (pdset==NULL) || (pdset->read_xxx==NULL) ) {
prec->pact=TRUE;
recGblRecordError(S_dev_missingSup,(void *)prec,"read_xxx");
return(S_dev_missingSup);
}
/* pact must not be set until after calling device support */
status=(*pdset->read_xxx)(prec);
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
recGblGetTimeStamp(prec);
/* check for alarms */
checkAlarms(prec);
/* check event list */
monitor(prec);
/* process the forward scan link record */
recGblFwdLink(prec);
prec->pact=FALSE;
return(status);
}
static long get_units(DBADDR *paddr, char *units)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
strncpy(units,prec->egu,DB_UNITS_SIZE);
return(0);
}
static long get_precision(DBADDR *paddr, long *precision)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
*precision = prec->prec;
if(paddr->pfield == (void *)&prec->val) return(0);
recGblGetPrec(paddr,precision);
return(0);
}
static long get_graphic_double(DBADDR *paddr,struct dbr_grDouble *pgd)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL
|| fieldIndex == xxxRecordHIHI
|| fieldIndex == xxxRecordHIGH
|| fieldIndex == xxxRecordLOW
|| fieldIndex == xxxRecordLOLO
|| fieldIndex == xxxRecordHOPR
|| fieldIndex == xxxRecordLOPR) {
pgd->upper_disp_limit = prec->hopr;
pgd->lower_disp_limit = prec->lopr;
} else recGblGetGraphicDouble(paddr,pgd);
return(0);
}
static long get_control_double(DBADDR *paddr,struct dbr_ctrlDouble *pcd)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL
|| fieldIndex == xxxRecordHIHI
|| fieldIndex == xxxRecordHIGH
|| fieldIndex == xxxRecordLOW
|| fieldIndex == xxxRecordLOLO) {
pcd->upper_ctrl_limit = prec->hopr;
pcd->lower_ctrl_limit = prec->lopr;
} else recGblGetControlDouble(paddr,pcd);
return(0);
}
static long get_alarm_double(DBADDR *paddr,struct dbr_alDouble *pad)
{
xxxRecord *prec=(xxxRecord *)paddr->precord;
int fieldIndex = dbGetFieldIndex(paddr);
if(fieldIndex == xxxRecordVAL) {
pad->upper_alarm_limit = prec->hhsv ? prec->hihi : epicsNAN;
pad->upper_warning_limit = prec->hsv ? prec->high : epicsNAN;
pad->lower_warning_limit = prec->lsv ? prec->low : epicsNAN;
pad->lower_alarm_limit = prec->llsv ? prec->lolo : epicsNAN;
} else recGblGetAlarmDouble(paddr,pad);
return(0);
}
static void checkAlarms(xxxRecord *prec)
{
double val, hyst, lalm;
float hihi, high, low, lolo;
unsigned short hhsv, llsv, hsv, lsv;
if(prec->udf == TRUE ){
recGblSetSevr(prec,UDF_ALARM,INVALID_ALARM);
return;
}
hihi = prec->hihi; lolo = prec->lolo; high = prec->high; low = prec->low;
hhsv = prec->hhsv; llsv = prec->llsv; hsv = prec->hsv; lsv = prec->lsv;
val = prec->val; hyst = prec->hyst; lalm = prec->lalm;
/* alarm condition hihi */
if (hhsv && (val >= hihi || ((lalm==hihi) && (val >= hihi-hyst)))){
if (recGblSetSevr(prec,HIHI_ALARM,prec->hhsv)) prec->lalm = hihi;
return;
}
/* alarm condition lolo */
if (llsv && (val <= lolo || ((lalm==lolo) && (val <= lolo+hyst)))){
if (recGblSetSevr(prec,LOLO_ALARM,prec->llsv)) prec->lalm = lolo;
return;
}
/* alarm condition high */
if (hsv && (val >= high || ((lalm==high) && (val >= high-hyst)))){
if (recGblSetSevr(prec,HIGH_ALARM,prec->hsv)) prec->lalm = high;
return;
}
/* alarm condition low */
if (lsv && (val <= low || ((lalm==low) && (val <= low+hyst)))){
if (recGblSetSevr(prec,LOW_ALARM,prec->lsv)) prec->lalm = low;
return;
}
/* we get here only if val is out of alarm by at least hyst */
prec->lalm = val;
return;
}
static void monitor(xxxRecord *prec)
{
unsigned short monitor_mask;
double delta;
monitor_mask = recGblResetAlarms(prec);
/* check for value change */
delta = prec->mlst - prec->val;
if(delta<0.0) delta = -delta;
if (delta > prec->mdel) {
/* post events for value change */
monitor_mask |= DBE_VALUE;
/* update last value monitored */
prec->mlst = prec->val;
}
/* check for archive change */
delta = prec->alst - prec->val;
if(delta<0.0) delta = -delta;
if (delta > prec->adel) {
/* post events on value field for archive change */
monitor_mask |= DBE_LOG;
/* update last archive value monitored */
prec->alst = prec->val;
}
/* send out monitors connected to the value field */
if (monitor_mask){
db_post_events(prec,&prec->val,monitor_mask);
}
return;
}

View File

@@ -0,0 +1,117 @@
recordtype(xxx) {
include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Current EGU Value")
asl(ASL0)
pp(TRUE)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup(GUI_INPUTS)
special(SPC_NOMOD)
interest(1)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup(GUI_DISPLAY)
interest(1)
size(16)
}
field(HOPR,DBF_FLOAT) {
prompt("High Operating Range")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(LOPR,DBF_FLOAT) {
prompt("Low Operating Range")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(HIHI,DBF_FLOAT) {
prompt("Hihi Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(LOLO,DBF_FLOAT) {
prompt("Lolo Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(HIGH,DBF_FLOAT) {
prompt("High Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(LOW,DBF_FLOAT) {
prompt("Low Alarm Limit")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
}
field(HHSV,DBF_MENU) {
prompt("Hihi Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(LLSV,DBF_MENU) {
prompt("Lolo Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(HSV,DBF_MENU) {
prompt("High Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(LSV,DBF_MENU) {
prompt("Low Severity")
promptgroup(GUI_ALARMS)
pp(TRUE)
interest(1)
menu(menuAlarmSevr)
}
field(HYST,DBF_DOUBLE) {
prompt("Alarm Deadband")
promptgroup(GUI_ALARMS)
interest(1)
}
field(ADEL,DBF_DOUBLE) {
prompt("Archive Deadband")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(MDEL,DBF_DOUBLE) {
prompt("Monitor Deadband")
promptgroup(GUI_DISPLAY)
interest(1)
}
field(LALM,DBF_DOUBLE) {
prompt("Last Value Alarmed")
special(SPC_NOMOD)
interest(3)
}
field(ALST,DBF_DOUBLE) {
prompt("Last Value Archived")
special(SPC_NOMOD)
interest(3)
}
field(MLST,DBF_DOUBLE) {
prompt("Last Val Monitored")
special(SPC_NOMOD)
interest(3)
}
}

View File

@@ -0,0 +1,2 @@
include "xxxRecord.dbd"
device(xxx,CONSTANT,devXxxSoft,"SoftChannel")

3
test00.set Normal file
View File

@@ -0,0 +1,3 @@
MODULES=
BASE=R3.15.6

4
test01.set Normal file
View File

@@ -0,0 +1,4 @@
MODULES="sncseq"
BASE=7.0
SNCSEQ=R2-2-7

10
test02.set Normal file
View File

@@ -0,0 +1,10 @@
# a comment, then an empty line
# a comment that is indented
BASE=foo
# include an existing file
include test01
FOO=bar
FOO2=bar bar2
FOO3=bar bar2

4
test03.set Normal file
View File

@@ -0,0 +1,4 @@
# Check for avoiding multiple includions
include test01
include test01

View File

@@ -1,10 +0,0 @@
#!/bin/sh
set -e -x
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make tapfiles
make -s test-results
fi

View File

@@ -1,159 +0,0 @@
#!/bin/sh
set -e -x
CURDIR="$PWD"
# determine if BASE is a release or a branch
git ls-remote --quiet --exit-code --tags https://github.com/${REPOBASE:-epics-base}/epics-base.git "$BASE" && BASE_RELEASE=YES
git ls-remote --quiet --exit-code --heads https://github.com/${REPOBASE:-epics-base}/epics-base.git "$BASE" && BASE_BRANCH=YES
if [ "$BASE_RELEASE" = "YES" ]
then
# TODO: use a cached location
BASE_LOCATION=$HOME/.source/epics-base
else
if [ "$BASE_BRANCH" = "YES" ]
then
BASE_LOCATION=$HOME/.source/epics-base
else
echo $BASE is neither a tag nor a branch name for BASE
exit 1
fi
fi
cat << EOF > $CURDIR/configure/RELEASE.local
EPICS_BASE=$BASE_LOCATION
EOF
install -d "$HOME/.source"
cd "$HOME/.source"
add_gh_flat() {
MODULE=$1
REPOOWNER=$2
REPONAME=$3
BRANCH=$4
MODULE_UC=$5
( git clone --quiet --depth 5 --branch $BRANCH https://github.com/$REPOOWNER/$REPONAME.git $MODULE && \
cd $MODULE && git log -n1 )
cat < $CURDIR/configure/RELEASE.local > $MODULE/configure/RELEASE.local
cat << EOF >> $CURDIR/configure/RELEASE.local
${MODULE_UC}=$HOME/.source/$MODULE
EOF
}
# not recursive
git clone --quiet --depth 5 --branch "$BASE" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base
(cd epics-base && git log -n1 )
for modrepo in ${MODULES}
do
module=${modrepo%CPP}
module_uc=$(echo $module | tr 'a-z' 'A-Z')
eval add_gh_flat $module \${REPO${module_uc}:-epics-base} $modrepo \${BR${module_uc}:-master} $module_uc
done
if [ -e $CURDIR/configure/RELEASE.local ]
then
cat $CURDIR/configure/RELEASE.local
fi
[ "$EPICS_HOST_ARCH" ] || EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch`
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
elif [ "$WINE" = "64" ]
then
echo "Cross mingw64"
sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
CMPLR_PREFIX=x86_64-w64-mingw32-
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=windows-x64-mingw
EOF
fi
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> epics-base/configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
HOST_CCMPLR_NAME=`echo "$TRAVIS_COMPILER" | sed -E 's/^([[:alpha:]][^-]*(-[[:alpha:]][^-]*)*)+(-[0-9\.]+)?$/\1/g'`
HOST_CMPLR_VER_SUFFIX=`echo "$TRAVIS_COMPILER" | sed -E 's/^([[:alpha:]][^-]*(-[[:alpha:]][^-]*)*)+(-[0-9\.]+)?$/\3/g'`
HOST_CMPLR_VER=`echo "$HOST_CMPLR_VER_SUFFIX" | cut -c 2-`
case "$HOST_CCMPLR_NAME" in
clang)
echo "Host compiler is clang"
HOST_CPPCMPLR_NAME=$(echo "$HOST_CCMPLR_NAME" | sed 's/clang/clang++/g')
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = ${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
CCC = ${HOST_CPPCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
EOF
# hack
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon
${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX --version
;;
gcc)
echo "Host compiler is GCC"
HOST_CPPCMPLR_NAME=$(echo "$HOST_CCMPLR_NAME" | sed 's/gcc/g++/g')
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
CC = ${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
CCC = ${HOST_CPPCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
EOF
${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX --version
;;
*)
echo "Host compiler is default"
gcc --version
;;
esac
cat <<EOF >> epics-base/configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
| tar -C / -xmj
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> epics-base/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
fi
for modrepo in epics-base ${MODULES}
do
module=${modrepo%CPP}
make -j2 -C $module $EXTRA
done

175
travis-test.sh Executable file
View File

@@ -0,0 +1,175 @@
#!/bin/bash
# Module ci-scripts unit tests
# SET=test00 in .travis.yml runs the tests in this script
# all other jobs are started as compile jobs
# Set VV empty in .travis.yml to make scripts terse
[ "${VV:-1}" ] && set -x
[ "$SET" != "test00" ] && exec ./travis/build.sh
UTILS_UNITTEST=1
# Perl version of "readlink -f" (which MacOS does not provide)
readlinkf() { perl -MCwd -e 'print Cwd::abs_path shift' "$1"; }
# test utilities
die() {
echo "${ANSI_RED}$1${ANSI_RESET}"
exit 1
}
fn_exists() {
LC_ALL=C type -t $1 | grep -q function
}
repo_exists() {
DEP=$1
dep_lc=$(echo $DEP | tr 'A-Z' 'a-z')
eval dirname=\${${DEP}_DIRNAME:=${dep_lc}}
eval reponame=\${${DEP}_REPONAME:=${dep_lc}}
eval repourl=\${${DEP}_REPOURL:="https://github.com/\${${DEP}_REPOOWNER:=${REPOOWNER:-epics-modules}}/${reponame}.git"}
git ls-remote --quiet --heads --exit-code $repourl > /dev/null 2>&1
}
SETUP_DIRS=$(echo $SETUP_PATH | tr ":" "\n")
SCRIPTDIR=$(dirname $(readlinkf $0))/travis
CURDIR="$PWD"
CACHEDIR="$HOME/.cache"
echo "Testing contents of utils.sh"
[ -d "$SCRIPTDIR" ] || die "SCRIPTDIR does not exist"
[ -e "$SCRIPTDIR/utils.sh" ] || die "SCRIPTDIR/utils.sh does not exist"
# source functions
. $SCRIPTDIR/utils.sh
# check for functions
fn_exists fold_start || die "function fold_start missing from SCRIPTDIR/utils.sh"
fn_exists fold_end || die "function fold_end missing from SCRIPTDIR/utils.sh"
fn_exists source_set || die "function source_set missing from SCRIPTDIR/utils.sh"
fn_exists update_release_local || die "function update_release_local missing from SCRIPTDIR/utils.sh"
fn_exists add_dependency || die "function add_dependency missing from SCRIPTDIR/utils.sh"
# test source_set()
######################################################################
SETUP_DIRS= source_set test01 | grep -q "(SETUP_PATH) is empty" || die "empty search path not detected"
source_set xxdoesnotexistxx | grep -q "does not exist" || die "missing setup file not detected"
source_set test01 | grep -q "Loading setup file" || die "test01 setup file not found"
unset SEEN_SETUPS
export BASE=foo
source_set test01
[ "$BASE" = "foo" ] || die "preset module BASE version does not override test01 setup file (expected foo got $BASE)"
unset SEEN_SETUPS
BASE=
source_set test02
[ "$BASE" = "foo" ] || die "BASE set in test02 does not override included test01 setup file (expected foo got $BASE)"
[ "$FOO" = "bar" ] || die "Setting of single word does not work"
[ "$FOO2" = "bar bar2" ] || die "Setting of multiple words does not work"
[ "$FOO3" = "bar bar2" ] || die "Indented setting of multiple words does not work"
[ "$SNCSEQ" = "R2-2-7" ] || die "Setup test01 was not included"
unset SEEN_SETUPS
source_set test03 | grep -q "Ignoring already included setup file" || die "test01 setup file included twice"
# test default settings file
######################################################################
echo "Testing default settings for completeness and valid git repo settings"
[ -e ./defaults.set ] || die "defaults.set does not exist"
source_set defaults
repo_exists BASE || die "Defaults for BASE do not point to a valid git repository at $repourl"
repo_exists PVDATA || die "Defaults for PVDATA do not point to a valid git repository at $repourl"
repo_exists PVACCESS || die "Defaults for PVACCESS do not point to a valid git repository at $repourl"
repo_exists NTYPES || die "Defaults for NTYPES do not point to a valid git repository at $repourl"
repo_exists SNCSEQ || die "Defaults for SNCSEQ do not point to a valid git repository at $repourl"
repo_exists STREAM || die "Defaults for STREAM do not point to a valid git repository at $repourl"
repo_exists ASYN || die "Defaults for STREAM do not point to a valid git repository at $repourl"
repo_exists STD || die "Defaults for STD do not point to a valid git repository at $repourl"
repo_exists CALC || die "Defaults for CALC do not point to a valid git repository at $repourl"
repo_exists AUTOSAVE || die "Defaults for AUTOSAVE do not point to a valid git repository at $repourl"
repo_exists BUSY || die "Defaults for BUSY do not point to a valid git repository at $repourl"
repo_exists SSCAN || die "Defaults for SSCAN do not point to a valid git repository at $repourl"
repo_exists IOCSTATS || die "Defaults for IOCSTATS do not point to a valid git repository at $repourl"
# test update_release_local()
######################################################################
echo "Testing updating the RELEASE.local file"
release_local=$CACHEDIR/RELEASE.local
rm -f $release_local
# Set a module
update_release_local MOD1 /tmp/mod1
updated_line="MOD1=/tmp/mod1"
grep -q "MOD1=" $release_local || die "Line for MOD1 not added to RELEASE.local"
existing_line=$(grep "MOD1=" $release_local)
[ "${existing_line}" = "${updated_line}" ] || die "Wrong line for MOD1 in RELEASE.local (expected=\"$updated_line\" found=\"$existing_line\")"
# Set base
update_release_local EPICS_BASE /tmp/base
updated_line="EPICS_BASE=/tmp/base"
grep -q "EPICS_BASE=" $release_local || die "Line for EPICS_BASE not added to RELEASE.local"
# Set another module
update_release_local MOD2 /tmp/mod2
updated_line="MOD2=/tmp/mod2"
grep -q "MOD2=" $release_local || die "Line for MOD2 not added to RELEASE.local"
existing_line=$(grep "MOD2=" $release_local)
[ "${existing_line}" = "${updated_line}" ] || die "Wrong line for MOD2 in RELEASE.local (expected=\"$updated_line\" found=\"$existing_line\")"
tail -n 1 $release_local | grep -q "EPICS_BASE=" || die "Line for EPICS_BASE not moved to the end of RELEASE.local"
# Update a module
update_release_local MOD1 /tmp/mod1b
updated_line="MOD1=/tmp/mod1b"
grep -q "MOD1=" $release_local || die "Line for MOD1 not present in RELEASE.local"
existing_line=$(grep "MOD1=" $release_local)
[ "${existing_line}" = "${updated_line}" ] || die "Wrong line for MOD1 in RELEASE.local (expected=\"$updated_line\" found=\"$existing_line\")"
head -n 1 $release_local | grep -q "MOD1=" || die "Line for MOD1 not at the top of RELEASE.local"
tail -n 1 $release_local | grep -q "EPICS_BASE=" || die "Line for EPICS_BASE not moved to the end of RELEASE.local"
# Check that RELEASE.local only contains variable settings
[ $(grep -v -c '[^ =]*=.*' $release_local) -ne 0 ] && die "RELEASE.local contains invalid lines"
rm -f $release_local
# test add_dependency()
######################################################################
echo "Testing adding a specific commit (branch or tag) of a dependency"
hash_3_15_6="ce7943fb44beb22b453ddcc0bda5398fadf72096"
location=$CACHEDIR/base-R3.15.6
# CAREFUL: order of the following check matters (speeds up the test)
# dependency does not exist in the cache
rm -fr $location
add_dependency BASE R3.15.6
[ -e $location/LICENSE ] || die "Missing dependency was not checked out"
BUILT=$(cat "$location/built")
[ "$BUILT" != "$hash_3_15_6" ] && die "Wrong commit of dependency checked out (expected=\"$hash_3_15_6\" found=\"$BUILT\")"
# up-to-date dependency does exist in the cache
( cd $CACHEDIR; git clone --quiet --depth 5 --recursive --branch R3.15.6 https://github.com/epics-base/epics-base.git base-R3.15.6 )
rm -f $location/LICENSE
add_dependency BASE R3.15.6
[ -e $location/LICENSE ] && die "Existing correct dependency was checked out on top"
# dependency in the cache is outdated
echo "nottherighthash" > "$location/built"
add_dependency BASE R3.15.6
[ -e $location/LICENSE ] || die "Outdated dependency was not checked out"
BUILT=$(cat "$location/built")
[ "$BUILT" != "$hash_3_15_6" ] && die "Wrong commit of dependency checked out (expected=\"$hash_3_15_6\" found=\"$BUILT\")"
rm -fr $location

View File

@@ -1,39 +1,62 @@
# .travis.xml for use with EPICS Base ci-scripts
# .travis.yml for use with EPICS Base ci-scripts
# (see: https://github.com/epics-base/ci-scripts)
# This is YAML - indentation levels are crucial
language: cpp
compiler: gcc
dist: xenial
cache:
directories:
- $HOME/.cache
env:
global:
- SETUP_PATH=.ci-local:.ci
addons:
apt:
packages:
# for all EPICS builds
- libreadline6-dev
- libncurses5-dev
- perl
# for clang compiler
- clang
# for mingw builds (32bit and 64bit)
- g++-mingw-w64-i686
- g++-mingw-w64-x86-64
# for RTEMS cross builds
- qemu-system-x86
install:
- ./.ci/travis-prepare.sh
- ./.ci/travis/prepare.sh
script:
- ./.ci/travis-build.sh
- ./.ci/travis/build.sh
# If you need to do more during install and build,
# add a local directory to your module and do e.g.
# - ./.ci-local/travis-install-extras.sh
# - ./.ci-local/travis/install-extras.sh
# Define build jobs
# Well-known variables to use
# BASE branch or release tag name of the EPICS Base to use
# SET source setup file
# EXTRA content will be added to make command line
# STATIC set to YES for static build (default: NO)
# TEST set to NO to skip running the tests (default: YES)
# VV set to make build scripts verbose (default: unset)
matrix:
# Usually from setup files, but may be specified or overridden
# on a job line
# MODULES list of dependency modules
# BASE branch or release tag name of the EPICS Base to use
# <MODULE> branch or release tag for a specific module
# ... see README for setup file syntax description
jobs:
include:
# Different configurations of default gcc and clang
@@ -56,7 +79,7 @@ matrix:
- env: BASE=7.0 EXTRA="CMD_CXXFLAGS=-std=c++11"
dist: trusty
# Cross-compilation to Windows using MinGW and WINE
# Cross-compilations to Windows using MinGW and WINE
- env: BASE=7.0 WINE=32 TEST=NO STATIC=YES
compiler: mingw
@@ -70,7 +93,7 @@ matrix:
- env: BASE=7.0 RTEMS=4.9 TEST=NO
# Other gcc versions (adding as an extra package)
# Other gcc versions (added as an extra package)
- env: BASE=7.0
compiler: gcc-6
@@ -85,8 +108,4 @@ matrix:
- env: BASE=7.0
os: osx
compiler: clang
# All above jobs can be defined for other branches or releases of EPICS Base
# by setting BASE to the branch name or release tag name, e.g.
# BASE=3.15 (to use the 3.15 branch of Base)
# BASE=R7.0.3 (to use the 7.0.3 release of Base)
addons: { homebrew: { packages: ["re2c"], update: true } }

View File

@@ -15,14 +15,14 @@ addons:
- perl
install:
- ./.ci/travis-prepare.sh
- ./.ci/travis/prepare.sh
script:
- ./.ci/travis-build.sh
- ./.ci/travis/build.sh
# Build using default gcc for Base branches 7.0 and 3.15
matrix:
jobs:
include:
- env: BASE=7.0
- env: BASE=3.15

View File

@@ -0,0 +1,77 @@
From 00ee7bf7d3618c748491c88742c011a8353abeba Mon Sep 17 00:00:00 2001
From: Andrew Johnson <anj@anl.gov>
Date: Wed, 24 Oct 2018 14:27:15 -0500
Subject: [PATCH] Add RTEMS-pc368-qemu target, use in Travis-CI builds
---
configure/os/CONFIG.Common.RTEMS-pc386-qemu | 11 +++++++++++
configure/os/CONFIG_SITE.Common.RTEMS-pc386 | 5 -----
configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu | 9 +++++++++
src/libCom/RTEMS/Makefile | 2 +-
src/tools/makeTestfile.pl | 2 +-
6 files changed, 24 insertions(+), 10 deletions(-)
create mode 100644 configure/os/CONFIG.Common.RTEMS-pc386-qemu
delete mode 100644 configure/os/CONFIG_SITE.Common.RTEMS-pc386
create mode 100644 configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
diff --git a/configure/os/CONFIG.Common.RTEMS-pc386-qemu b/configure/os/CONFIG.Common.RTEMS-pc386-qemu
new file mode 100644
index 000000000..684f01a19
--- /dev/null
+++ b/configure/os/CONFIG.Common.RTEMS-pc386-qemu
@@ -0,0 +1,11 @@
+# CONFIG.Common.RTEMS-pc386-qemu
+#
+# Definitions for the RTEMS-pc386-qemu target
+# Site-specific overrides go in CONFIG_SITE.Common.RTEMS-pc386-qemu
+#
+#-------------------------------------------------------
+
+# Include definitions from RTEMS-pc386
+include $(CONFIG)/os/CONFIG.Common.RTEMS-pc386
+
+RTEMS_QEMU_FIXUPS = YES
diff --git a/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu b/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
new file mode 100644
index 000000000..027dcf4ab
--- /dev/null
+++ b/configure/os/CONFIG_SITE.Common.RTEMS-pc386-qemu
@@ -0,0 +1,9 @@
+# CONFIG_SITE.Common.RTEMS-pc386-qemu
+#
+# Site-specific overrides for the RTEMS-pc386-qemu target
+#
+
+# If you're building this architecture you _probably_ want to
+# run the tests for it under QEMU, but if not you can turn
+# them off here by commenting out this line:
+CROSS_COMPILER_RUNTEST_ARCHS += RTEMS-pc386-qemu
diff --git a/src/libCom/RTEMS/Makefile b/src/libCom/RTEMS/Makefile
index 2f12b7bf0..22a92733c 100644
--- a/src/libCom/RTEMS/Makefile
+++ b/src/libCom/RTEMS/Makefile
@@ -24,7 +24,7 @@ rtemsCom_SRCS += epicsRtemsInitHookPre.c
rtemsCom_SRCS += epicsRtemsInitHookPost.c
rtemsCom_SRCS += epicsMemFs.c
-ifeq ($(T_A),RTEMS-pc386)
+ifeq ($(RTEMS_BSP),pc386)
rtemsCom_SRCS += ne2kpci.c
endif
diff --git a/src/tools/makeTestfile.pl b/src/tools/makeTestfile.pl
index 73f522034..fb431fe7a 100644
--- a/src/tools/makeTestfile.pl
+++ b/src/tools/makeTestfile.pl
@@ -37,7 +37,7 @@ if( $TA =~ /^win32-x86/ && $HA !~ /^win/ ) {
$exec = "wine64 $exe";
# Run pc386 test harness w/ QEMU
-} elsif( $TA =~ /^RTEMS-pc386$/ ) {
+} elsif( $TA =~ /^RTEMS-pc386-qemu$/ ) {
$exec = "qemu-system-i386 -m 64 -no-reboot -serial stdio -display none -net nic,model=ne2k_pci -net user,restrict=yes -kernel $exe";
# Explicitly fail for other RTEMS targets
--
2.21.0.windows.1

45
travis/README.md Normal file
View File

@@ -0,0 +1,45 @@
# Travis-CI Scripts for EPICS Modules
## Features
- Use different compilers (gcc, clang)
- Use different gcc versions
- Cross-compile for Windows 32bit and 64bit using MinGW and WINE
- Cross-compile for RTEMS 4.9 and 4.10
- Compile on MacOS
- Released versions of dependencies are cached (for faster builds)
## How to Use these Scripts
1. Get an account on [Travis-CI](https://travis-ci.org/), connect
it to your GitHub account and activate your support module's
repository. For more details, please refer to the
[Travis-CI Tutorial](https://docs.travis-ci.com/user/tutorial/).
Make sure to use `travis-ci.org` and not their `.com` site.
2. Add the ci-scripts respository as a Git Submodule
(see [README](../README.md) one level above).
3. Add settings files defining which dependencies in which versions
you want to build against
(see [README](../README.md) one level above).
4. Create a Travis configuration by copying one of the examples into
the root directory of your module.
```
$ cp .ci/travis/.travis.yml.example-full .travis.yml
```
5. Edit the `.travis.yml` configuration to include the jobs you want
Travis to run.
Build jobs are declared in the list following the `jobs: include:`
declaration. Each element (starting with `-` in column 3) defines the
settings for one build job. `env:` controls the setting of environment
variables,`dist:` specifies the Linux distribution,
`os:` the operating system.
Also see the comments in the examples for more hints, and the Travis-CI
documentation for more options and more details.
6. Push your changes and check
[travis-ci.org](https://travis-ci.org/) for your build results.

22
travis/build.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
set -e
# Set VV in .travis.yml to make scripts verbose
[ "$VV" ] && set -x
CACHEDIR="$HOME/.cache"
eval $(grep "EPICS_BASE=" ${CACHEDIR}/RELEASE.local)
export EPICS_BASE
[ -z "$EPICS_HOST_ARCH" -a -f $EPICS_BASE/src/tools/EpicsHostArch.pl ] && EPICS_HOST_ARCH=$(perl $EPICS_BASE/src/tools/EpicsHostArch.pl)
[ -z "$EPICS_HOST_ARCH" -a -f $EPICS_BASE/startup/EpicsHostArch.pl ] && EPICS_HOST_ARCH=$(perl $EPICS_BASE/startup/EpicsHostArch.pl)
export EPICS_HOST_ARCH
make -j2 $EXTRA
if [ "$TEST" != "NO" ]
then
make tapfiles
make -s test-results
fi

204
travis/prepare.sh Executable file
View File

@@ -0,0 +1,204 @@
#!/bin/bash
set -e
# Set VV in .travis.yml to make scripts verbose
[ "$VV" ] && set -x
# Perl version of "readlink -f" (which MacOS does not provide)
readlinkf() { perl -MCwd -e 'print Cwd::abs_path shift' "$1"; }
SETUP_DIRS=$(echo $SETUP_PATH | tr ":" "\n")
SCRIPTDIR=$(dirname $(readlinkf $0))
CURDIR="$PWD"
CACHEDIR="$HOME/.cache"
# source functions
. $SCRIPTDIR/utils.sh
# Load settings
# -------------
fold_start load.settings "Loading settings"
# load default settings for well-known modules
source_set defaults
# source configured settings
[ -z "${SET+x}" ] || source_set $SET
fold_end load.settings
# Check out dependencies
# ----------------------
fold_start check.out.dependencies "Checking/cloning dependencies"
for mod in BASE $MODULES
do
mod_uc=$(echo $mod | tr 'a-z' 'A-Z')
eval add_dependency $mod_uc \${${mod_uc}:=master}
done
[ -e ./configure ] && cp ${CACHEDIR}/RELEASE.local ./configure/RELEASE.local
fold_end check.out.dependencies
# Set up compiler
# ---------------
fold_start set.up.epics_build "Setting up EPICS build system"
eval $(grep "EPICS_BASE=" ${CACHEDIR}/RELEASE.local)
export EPICS_BASE
echo "EPICS_BASE=$EPICS_BASE"
[ -z "$EPICS_HOST_ARCH" -a -f $EPICS_BASE/src/tools/EpicsHostArch.pl ] && EPICS_HOST_ARCH=$(perl $EPICS_BASE/src/tools/EpicsHostArch.pl)
[ -z "$EPICS_HOST_ARCH" -a -f $EPICS_BASE/startup/EpicsHostArch.pl ] && EPICS_HOST_ARCH=$(perl $EPICS_BASE/startup/EpicsHostArch.pl)
export EPICS_HOST_ARCH
echo "EPICS_HOST_ARCH=$EPICS_HOST_ARCH"
if echo ${modules_to_compile} | grep -q "$EPICS_BASE"
then
# requires wine and g++-mingw-w64-i686
if [ "$WINE" = "32" ]
then
echo "Cross mingw32"
sed -i -e '/CMPLR_PREFIX/d' $EPICS_BASE/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
cat << EOF >> $EPICS_BASE/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw
CMPLR_PREFIX=i686-w64-mingw32-
EOF
cat << EOF >> $EPICS_BASE/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw
EOF
elif [ "$WINE" = "64" ]
then
echo "Cross mingw64"
sed -i -e '/CMPLR_PREFIX/d' $EPICS_BASE/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
cat << EOF >> $EPICS_BASE/configure/os/CONFIG_SITE.linux-x86.windows-x64-mingw
CMPLR_PREFIX=x86_64-w64-mingw32-
EOF
cat << EOF >> $EPICS_BASE/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS+=windows-x64-mingw
EOF
fi
if [ "$STATIC" = "YES" ]
then
echo "Build static libraries/executables"
cat << EOF >> $EPICS_BASE/configure/CONFIG_SITE
SHARED_LIBRARIES=NO
STATIC_BUILD=YES
EOF
fi
HOST_CCMPLR_NAME=`echo "$TRAVIS_COMPILER" | sed -E 's/^([[:alpha:]][^-]*(-[[:alpha:]][^-]*)*)+(-[0-9\.]+)?$/\1/g'`
HOST_CMPLR_VER_SUFFIX=`echo "$TRAVIS_COMPILER" | sed -E 's/^([[:alpha:]][^-]*(-[[:alpha:]][^-]*)*)+(-[0-9\.]+)?$/\3/g'`
HOST_CMPLR_VER=`echo "$HOST_CMPLR_VER_SUFFIX" | cut -c 2-`
case "$HOST_CCMPLR_NAME" in
clang)
echo "Host compiler is clang"
HOST_CPPCMPLR_NAME=$(echo "$HOST_CCMPLR_NAME" | sed 's/clang/clang++/g')
cat << EOF >> $EPICS_BASE/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
GNU = NO
CMPLR_CLASS = clang
CC = ${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
CCC = ${HOST_CPPCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
EOF
# hack
sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' $EPICS_BASE/configure/CONFIG.gnuCommon
${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX --version
;;
gcc)
echo "Host compiler is GCC"
HOST_CPPCMPLR_NAME=$(echo "$HOST_CCMPLR_NAME" | sed 's/gcc/g++/g')
cat << EOF >> $EPICS_BASE/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH
CC = ${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
CCC = ${HOST_CPPCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX
EOF
${HOST_CCMPLR_NAME}$HOST_CMPLR_VER_SUFFIX --version
;;
*)
echo "Host compiler is default"
gcc --version
;;
esac
cat <<EOF >> $EPICS_BASE/configure/CONFIG_SITE
USR_CPPFLAGS += $USR_CPPFLAGS
USR_CFLAGS += $USR_CFLAGS
USR_CXXFLAGS += $USR_CXXFLAGS
EOF
# set RTEMS to eg. "4.9" or "4.10"
# requires qemu, bison, flex, texinfo, install-info
if [ -n "$RTEMS" ]
then
echo "Cross RTEMS${RTEMS} for pc386"
sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' $EPICS_BASE/configure/os/CONFIG_SITE.Common.RTEMS
cat << EOF >> $EPICS_BASE/configure/os/CONFIG_SITE.Common.RTEMS
RTEMS_VERSION=$RTEMS
RTEMS_BASE=$HOME/.rtems
EOF
cat << EOF >> $EPICS_BASE/configure/CONFIG_SITE
CROSS_COMPILER_TARGET_ARCHS += RTEMS-pc386-qemu
EOF
fi
else
echo "${ANSI_GREEN}EPICS build system already set up (Base was loaded from cache)${ANSI_RESET}"
fi
# Download RTEMS cross compiler
if [ -n "$RTEMS" ]
then
echo "Downloading RTEMS${RTEMS} cross compiler for pc386"
curl -L "https://github.com/mdavidsaver/rsb/releases/download/20171203-${RTEMS}/i386-rtems${RTEMS}-trusty-20171203-${RTEMS}.tar.bz2" \
| tar -C / -xmj
fi
fold_end set.up.compiler
echo "\$ make --version"
make --version
# Build required dependencies
# ---------------------------
fold_start build.dependencies "Build missing/outdated dependencies"
[ "$VV" ] && silent="-s" || silent=
[ -z "$modules_to_compile" ] && echo "${ANSI_GREEN}All dependency modules are up-to-date (nothing to do)${ANSI_RESET}"
for module in ${modules_to_compile}
do
eval name=\${module#${CACHEDIR}/}
fold_start build.$name "Build $name"
make -j2 $silent -C $module $EXTRA
fold_end build.$name
done
fold_end build.dependencies
echo "${ANSI_BLUE}Dependency module information${ANSI_RESET}"
echo "Module Tag Binaries Commit"
echo "-----------------------------------------------------------------------------------"
for mod in base $MODULES
do
mod_uc=$(echo $mod | tr 'a-z' 'A-Z')
eval tag=\${${mod_uc}}
eval dir=${CACHEDIR}/\${${mod_uc}_DIRNAME}-$tag
echo "$modules_to_compile" | grep -q "$dir" && stat="rebuilt" || stat="from cache"
commit=$(git -C $dir log -n1 --oneline)
printf "%-10s %-12s %-11s %s\n" "$mod" "$tag" "$stat" "$commit"
done
echo "${ANSI_BLUE}Contents of RELEASE.local${ANSI_RESET}"
cat ${CACHEDIR}/RELEASE.local

204
travis/utils.sh Normal file
View File

@@ -0,0 +1,204 @@
# Utility functions for Travis scripts in ci-scripts
#
# This file is sourced by the executable scripts
# Portable version of 'sed -i' (that MacOS doesn't provide)
# sedi (cmd, file)
# Do the equivalent of "sed -i cmd file"
sedi () {
cat $2 | sed "$1" > $2.tmp$$; mv -f $2.tmp$$ $2
}
# Setup ANSI Colors
export ANSI_RED="\033[31;1m"
export ANSI_GREEN="\033[32;1m"
export ANSI_YELLOW="\033[33;1m"
export ANSI_BLUE="\033[34;1m"
export ANSI_RESET="\033[0m"
export ANSI_CLEAR="\033[0K"
# Travis log fold control
# from https://github.com/travis-ci/travis-rubies/blob/build/build.sh
fold_start() {
echo -en "travis_fold:start:$1\\r${ANSI_YELLOW}$2${ANSI_RESET}"
}
fold_end() {
echo -en "travis_fold:end:$1\\r"
}
# source_set(settings)
#
# Source a settings file (extension .set) found in the SETUP_DIRS path
# May be called recursively (from within a settings file)
declare -a SEEN_SETUPS
source_set() {
local set_file=${1//[$'\r']}
local set_dir
local found=0
if [ -z "${SETUP_DIRS}" ]
then
echo "${ANSI_RED}Search path for setup files (SETUP_PATH) is empty${ANSI_RESET}"
[ "$UTILS_UNITTEST" ] || exit 1
fi
for set_dir in ${SETUP_DIRS}
do
if [ -e $set_dir/$set_file.set ]
then
if [[ " ${SEEN_SETUPS[@]} " =~ " $set_dir/$set_file.set " ]]
then
echo "Ignoring already included setup file $set_dir/$set_file.set"
return
fi
SEEN_SETUPS+=($set_dir/$set_file.set)
echo "Loading setup file $set_dir/$set_file.set"
local line
while read -r line
do
[ -z "$line" ] && continue
echo $line | grep -q "^#" && continue
if echo $line | grep -q "^include\W"
then
source_set $(echo $line | awk '{ print $2 }')
continue
fi
if echo "$line" | grep -q "^\w\+="
then
IFS== read var value <<< "${line//[$'\r']}"
value=$(sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<< "$value") # remove surrounding quotes
eval [ "\${$var}" ] || eval "$var=\$value"
fi
done < $set_dir/$set_file.set
found=1
break
fi
done
if [ $found -eq 0 ]
then
echo "${ANSI_RED}Setup file $set_file.set does not exist in SETUP_DIRS search path ($SETUP_DIRS)${ANSI_RESET}"
[ "$UTILS_UNITTEST" ] || exit 1
fi
}
# update_release_local(varname, place)
# varname name of the variable to set in RELEASE.local
# place place (absolute path) of where variable should point to
#
# Manipulate RELEASE.local in the cache location:
# - replace "$varname=$place" line if it exists and has changed
# - otherwise add "$varname=$place" line and possibly move EPICS_BASE=... line to the end
update_release_local() {
local var=$1
local place=$2
local release_local=${CACHEDIR}/RELEASE.local
local updated_line="${var}=${place}"
local ret=0
[ -e ${release_local} ] && grep -q "${var}=" ${release_local} || ret=$?
if [ $ret -eq 0 ]
then
existing_line=$(grep "${var}=" ${release_local})
if [ "${existing_line}" != "${updated_line}" ]
then
sedi "s|${var}=.*|${var}=${place}|g" ${release_local}
fi
else
echo "$var=$place" >> ${release_local}
ret=0
grep -q "EPICS_BASE=" ${release_local} || ret=$?
if [ $ret -eq 0 ]
then
base_line=$(grep "EPICS_BASE=" ${release_local})
sedi '\|EPICS_BASE=|d' ${release_local}
echo ${base_line} >> ${release_local}
fi
fi
}
# add_dependency(dep, tag)
#
# Add a dependency to the cache area:
# - check out (recursive if configured) in the CACHE area unless it already exists and the
# required commit has been built
# - Defaults:
# $dep_DIRNAME = lower case ($dep)
# $dep_REPONAME = lower case ($dep)
# $dep_REPOURL = GitHub / $dep_REPOOWNER (or $REPOOWNER or epics-modules) / $dep_REPONAME .git
# $dep_VARNAME = $dep
# $dep_DEPTH = 5
# $dep_RECURSIVE = 1/YES (0/NO to for a flat clone)
# - Add $dep_VARNAME line to the RELEASE.local file in the cache area (unless already there)
# - Add full path to $modules_to_compile
add_dependency() {
curdir="$PWD"
DEP=$1
TAG=$2
dep_lc=$(echo $DEP | tr 'A-Z' 'a-z')
eval dirname=\${${DEP}_DIRNAME:=${dep_lc}}
eval reponame=\${${DEP}_REPONAME:=${dep_lc}}
eval repourl=\${${DEP}_REPOURL:="https://github.com/\${${DEP}_REPOOWNER:=${REPOOWNER:-epics-modules}}/${reponame}.git"}
eval varname=\${${DEP}_VARNAME:=${DEP}}
eval recursive=\${${DEP}_RECURSIVE:=1}
recursive=$(echo $recursive | tr 'A-Z' 'a-z')
[ "$recursive" != "0" -a "$recursive" != "no" ] && recurse="--recursive"
# determine if $DEP points to a valid release or branch
if ! git ls-remote --quiet --exit-code --refs $repourl "$TAG" > /dev/null 2>&1
then
echo "${ANSI_RED}$TAG is neither a tag nor a branch name for $DEP ($repourl)${ANSI_RESET}"
[ "$UTILS_UNITTEST" ] || exit 1
fi
if [ -e $CACHEDIR/$dirname-$TAG ]
then
[ -e $CACHEDIR/$dirname-$TAG/built ] && BUILT=$(cat $CACHEDIR/$dirname-$TAG/built) || BUILT="never"
HEAD=$(cd "$CACHEDIR/$dirname-$TAG" && git log -n1 --pretty=format:%H)
if [ "$HEAD" != "$BUILT" ]
then
rm -fr $CACHEDIR/$dirname-$TAG
else
echo "Found $TAG of dependency $DEP in $CACHEDIR/$dirname-$TAG"
fi
fi
if [ ! -e $CACHEDIR/$dirname-$TAG ]
then
cd $CACHEDIR
eval depth=\${${DEP}_DEPTH:-"-1"}
case ${depth} in
-1 )
deptharg="--depth 5"
;;
0 )
deptharg=""
;;
* )
deptharg="--depth $depth"
;;
esac
echo "Cloning $TAG of dependency $DEP into $CACHEDIR/$dirname-$TAG"
git clone --quiet $deptharg $recurse --branch "$TAG" $repourl $dirname-$TAG
( cd $dirname-$TAG && git log -n1 )
modules_to_compile="${modules_to_compile} $CACHEDIR/$dirname-$TAG"
# run hook
eval hook="\${${DEP}_HOOK}"
if [ "$hook" ]
then
if [ -x "$curdir/$hook" ]
then
echo "Running hook $hook in $CACHEDIR/$dirname-$TAG"
( cd $CACHEDIR/$dirname-$TAG; "$curdir/$hook" )
else
echo "${ANSI_RED}Hook script $hook is not executable or does not exist.${ANSI_RESET}"
exit 1
fi
fi
HEAD=$(cd "$CACHEDIR/$dirname-$TAG" && git log -n1 --pretty=format:%H)
echo "$HEAD" > "$CACHEDIR/$dirname-$TAG/built"
cd "$curdir"
fi
update_release_local ${varname} $CACHEDIR/$dirname-$TAG
}