Merged gen-vcs-version branch

This commit is contained in:
Andrew Johnson
2015-07-10 14:02:01 -05:00
15 changed files with 267 additions and 6 deletions

View File

@ -68,11 +68,11 @@ DBTOMENUH = $(PERL) $(TOOLS)/dbdToMenuH.pl
REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl
CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl)
FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl
GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG)
#-------------------------------------------------------
# tools for installing libraries and products
INSTALL_QUIETLY := $(if $(findstring s,$(MAKEFLAGS)),-q,)
INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(INSTALL_QUIETLY)
INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(QUIET_FLAG)
INSTALL_PRODUCT = $(INSTALL)
INSTALL_LIBRARY = $(INSTALL)

View File

@ -85,6 +85,7 @@ IOCS_APPL_TOP = $(shell $(FULLPATHNAME) $(INSTALL_LOCATION))
# Make echo output - suppress echoing if make's '-s' flag is set
NOP = :
ECHO = @$(if $(findstring s,$(patsubst T_A=%,,$(MAKEFLAGS))),$(NOP),echo)
QUIET_FLAG := $(if $(findstring s,$(MAKEFLAGS)),-q,)
#-------------------------------------------------------
ifdef T_A
@ -334,6 +335,14 @@ COMPILE.cpp = $(CCC) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES)
# C preprocessor command
PREPROCESS.cpp = $(CPP) $(CPPFLAGS) $(INCLUDES) $< > $@
#--------------------------------------------------
# genVersion header defaults
# C macro name
GENVERSIONMACRO = VCSVERSION
# C macro default value (empty to use date+time)
GENVERSIONDEFAULT =
#--------------------------------------------------
# Header dependency file generation

View File

@ -346,6 +346,14 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
@$(RM) $@
$(PERL) $(TOOLS)/makeTestfile.pl $@ $<
#---------------------------------------------------------------
# Generate header with version number from VCS
ifneq ($(GENVERSION),)
$(COMMON_DIR)/$(GENVERSION): FORCE
$(GENVERSIONHEADER) -t $(TOP) -N $(GENVERSIONMACRO) -V "$(GENVERSIONDEFAULT)" $@
endif
#---------------------------------------------------------------
# Install rules for BIN_INSTALLS and LIB_INSTALLS
@ -479,7 +487,7 @@ $(INSTALL_TEMPLATES_SUBDIR)/%: %
.PRECIOUS: $(COMMON_INC)
.PHONY: all host inc build install clean rebuild buildInstall build_clean
.PHONY: runtests tapfiles checkRelease warnRelease noCheckRelease
.PHONY: runtests tapfiles checkRelease warnRelease noCheckRelease FORCE
endif # BASE_RULES_BUILD
# EOF RULES_BUILD

View File

@ -20,6 +20,16 @@
-->
<h3>Generate Version Header</h3>
<p>A Perl script and Makefile rules have been added to allow modules to generate
a C header file with a macro defined with an automatically updated identifier.
This is a VCS revision ID (Darcs, Git, Mercurial Subversion and Bazaar are all
supported) or the date/time of the build if no VCS system is in use.</p>
<p>The makeBaseApp example template has been updated with a new device support
which makes this identifier visible via a lsi (long string input) record.</p>
<h3>epicsTime API return status</h3>
<p>The epicsTime routines that used to return epicsTimeERROR now return a specific

View File

@ -28,9 +28,12 @@ TEMPLATES += top/exampleApp/Makefile
TEMPLATES += top/exampleApp/Db/Makefile
TEMPLATES += top/exampleApp/Db/dbExample1.db
TEMPLATES += top/exampleApp/Db/dbExample2.db
TEMPLATES += top/exampleApp/Db/_APPNAME_Version.db
TEMPLATES += top/exampleApp/Db/dbSubExample.db
TEMPLATES += top/exampleApp/Db/user.substitutions
TEMPLATES += top/exampleApp/src/Makefile
TEMPLATES += top/exampleApp/src/dev_APPNAME_Version.c
TEMPLATES += top/exampleApp/src/dev_APPNAME_Version.dbd
TEMPLATES += top/exampleApp/src/xxxRecord.dbd
TEMPLATES += top/exampleApp/src/xxxRecord.c
TEMPLATES += top/exampleApp/src/devXxxSoft.c

View File

@ -6,6 +6,7 @@ include $(TOP)/configure/CONFIG
# Install databases, templates & substitutions like this
DB += dbExample1.db
DB += dbExample2.db
DB += _APPNAME_Version.db
DB += dbSubExample.db
DB += user.substitutions

View File

@ -0,0 +1,6 @@
record(lsi, "$(user):_APPNAME_:version") {
field(DTYP, "_APPNAME_ version")
field(DESC, "Version string")
field(SIZV, "$(SIZV=200)")
field(PINI, "YES")
}

View File

@ -13,19 +13,26 @@ DBD += xxxSupport.dbd
# Build an IOC support library
LIBRARY_IOC += _APPNAME_Support
# Compile and add the code to the support library
# Compile and add code to the support library
_APPNAME_Support_SRCS += xxxRecord.c
_APPNAME_Support_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.
# rather than directly into the IOC application, that
# causes problems on Windows DLL builds
_APPNAME_Support_SRCS += dbSubExample.c
_APPNAME_Support_SRCS += dev_APPNAME_Version.c
_APPNAME_Support_SRCS += _APPNAME_Hello.c
_APPNAME_Support_SRCS += initTrace.c
_APPNAME_Support_LIBS += $(EPICS_BASE_IOC_LIBS)
# Auto-generate a header file containing a version string.
# Version comes from the VCS if available, else date+time.
GENVERSION = _APPNAME_Version.h
# Macro name
GENVERSIONMACRO = _APPNAME_VERSION
# Build the IOC application
PROD_IOC = _APPNAME_
@ -36,6 +43,7 @@ DBD += _APPNAME_.dbd
_APPNAME__DBD += base.dbd
_APPNAME__DBD += xxxSupport.dbd
_APPNAME__DBD += dbSubExample.dbd
_APPNAME__DBD += dev_APPNAME_Version.dbd
_APPNAME__DBD += _APPNAME_Hello.dbd
_APPNAME__DBD += initTrace.dbd
@ -77,3 +85,5 @@ include $(TOP)/configure/RULES
#----------------------------------------
# ADD EXTRA GNUMAKE RULES BELOW HERE
# Explicit dependency needed for generated header file
dev_APPNAME_Version$(DEP): $(COMMON_DIR)/$(GENVERSION)

View File

@ -0,0 +1,38 @@
/* dev_APPNAME_Version.c */
/* Example device support for the lsi (long string input) record
* providing the module version string as the value
*/
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "devSup.h"
#include "lsiRecord.h"
#include "_APPNAME_Version.h"
/* must be last include */
#include "epicsExport.h"
const char const version[] = _APPNAME_VERSION;
static long read_string(lsiRecord *prec)
{
size_t N = sizeof version;
char *buf = prec->val;
if (N > prec->sizv)
N = prec->sizv;
prec->len = N;
memcpy(buf, version, N);
buf[N - 1] = '\0';
return 0;
}
static lsidset dev_CSAFEAPPNAME_Version = {
5, NULL, NULL, NULL, NULL, read_string
};
epicsExportAddress(dset,dev_CSAFEAPPNAME_Version);

View File

@ -0,0 +1 @@
device(lsi,INST_IO,dev_CSAFEAPPNAME_Version,"_APPNAME_ version")

View File

@ -13,6 +13,7 @@ _CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
dbLoadTemplate "db/user.substitutions"
dbLoadRecords "db/_APPNAME_Version.db", "user=_USER_"
dbLoadRecords "db/dbSubExample.db", "user=_USER_"
## Set this to see messages from mySub

View File

@ -11,6 +11,7 @@ _CSAFEAPPNAME__registerRecordDeviceDriver(pdbbase)
## Load record instances
dbLoadTemplate("db/user.substitutions")
dbLoadRecords("db/_APPNAME_Version.db", "user=_USER_")
dbLoadRecords("db/dbSubExample.db", "user=_USER_")
## Set this to see messages from mySub

View File

@ -20,6 +20,7 @@ _CSAFEAPPNAME__registerRecordDeviceDriver pdbbase
## Load record instances
dbLoadTemplate "db/user.substitutions"
dbLoadRecords "db/_APPNAME_Version.db", "user=_USER_"
dbLoadRecords "db/dbSubExample.db", "user=_USER_"
## Set this to see messages from mySub

View File

@ -46,6 +46,7 @@ PERL_SCRIPTS += mkmf.pl
PERL_SCRIPTS += munch.pl
PERL_SCRIPTS += replaceVAR.pl
PERL_SCRIPTS += useManifestTool.pl
PERL_SCRIPTS += genVersionHeader.pl
PERL_SCRIPTS += dbdToMenuH.pl
PERL_SCRIPTS += dbdToRecordtypeH.pl

View File

@ -0,0 +1,171 @@
#!/usr/bin/env perl
#*************************************************************************
# Copyright (c) 2014 Brookhaven National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
#
# Generate a C header file which
# defines a macro with a string
# describing the VCS revision
#
use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use EPICS::Getopts;
use POSIX qw(strftime);
use strict;
# RFC 8601 date+time w/ zone (eg "2014-08-29T09:42:47-0700")
my $tfmt = '%Y-%m-%dT%H:%M:%S';
$tfmt .= '%z' unless $^O eq 'MSWin32'; # %z returns zone name on Windows
my $now = strftime($tfmt, localtime);
our ($opt_h, $opt_v, $opt_q);
our $opt_t = '.';
our $opt_N = 'VCSVERSION';
our $opt_V = $now;
my $vcs;
getopts('hvqt:N:V:') && @ARGV == 1
or HELP_MESSAGE();
my ($outfile) = @ARGV;
if (!$vcs && -d "$opt_t/_darcs") { # Darcs
print "== Found <top>/_darcs directory\n" if $opt_v;
# v1-4-dirty
# is tag 'v1' plus 4 patches
# with uncommited modifications
my $result = `cd "$opt_t" && echo "\$(darcs show tags | head -1)-\$((\$(darcs changes --count --from-tag .)-1))"`;
chomp $result;
print "== darcs show tags, changes:\n$result\n==\n" if $opt_v;
if (!$? && $result ne '') {
$opt_V = $result;
$vcs = 'Darcs';
# see if working copy has modifications, additions, removals, or missing files
my $hasmod = `darcs whatsnew --repodir="$opt_t" -l`;
$opt_V .= '-dirty' unless $?;
}
}
if (!$vcs && -d "$opt_t/.hg") { # Mercurial
print "== Found <top>/.hg directory\n" if $opt_v;
# v1-4-abcdef-dirty
# is 4 commits after tag 'v1' with short hash abcdef
# with uncommited modifications
my $result = `hg tip --template '{latesttag}-{latesttagdistance}-{node|short}'`;
print "== hg tip:\n$result\n==\n" if $opt_v;
if (!$? && $result ne '') {
$opt_V = $result;
$vcs = 'Mercurial';
# see if working copy has modifications, additions, removals, or missing files
my $hasmod = `hg status -m -a -r -d`;
chomp $hasmod;
$opt_V .= '-dirty' if $hasmod ne '';
}
}
if (!$vcs && -d "$opt_t/.git") { # Git
print "== Found <top>/.git directory\n" if $opt_v;
# v1-4-abcdef-dirty
# is 4 commits after tag 'v1' with short hash abcdef
# with uncommited modifications
my $result = `git describe --always --tags --dirty --abbrev=20`;
chomp $result;
print "== git describe:\n$result\n==\n" if $opt_v;
if (!$? && $result ne '') {
$opt_V = $result;
$vcs = 'Git';
}
}
if (!$vcs && -d "$opt_t/.svn") { # Subversion
print "== Found <top>/.svn directory\n" if $opt_v;
# 12345-dirty
my $result = `cd "$opt_t" && svn info --non-interactive`;
chomp $result;
print "== svn info:\n$result\n==\n" if $opt_v;
if (!$? && $result =~ /^Revision:\s*(\d+)/m) {
$opt_V = $1;
$vcs = 'Subversion';
# see if working copy has modifications, additions, removals, or missing files
my $hasmod = `cd "$opt_t" && svn status --non-interactive`;
chomp $hasmod;
$opt_V .= '-dirty' if $hasmod ne '';
}
}
if (!$vcs && -d "$opt_t/.bzr") { # Bazaar
print "== Found <top>/.bzr directory\n" if $opt_v;
# 12444-anj@aps.anl.gov-20131003210403-icfd8mc37g8vctpf-dirty
my $result = `bzr version-info -q --custom --template="{revno}-{revision_id}-{clean}"`;
print "== bzr version-info:\n$result\n==\n" if $opt_v;
if (!$? && $result ne '') {
$result =~ s/-([01])$/$1 ? '' : '-dirty'/e;
$opt_V = $result;
$vcs = 'Bazaar';
}
}
if (!$vcs) {
print "== No VCS directories\n" if $opt_v;
if ($opt_V eq '') {
$vcs = 'build date/time';
$opt_V = $now;
}
else {
$vcs = 'Makefile';
}
}
my $output = << "__END";
/* Generated file, do not edit! */
/* Version determined from $vcs */
#ifndef $opt_N
#define $opt_N \"$opt_V\"
#endif
__END
print "== Want:\n$output==\n" if $opt_v;
my $DST;
if (open($DST, '+<', $outfile)) {
my $actual = join('', <$DST>);
print "== Current:\n$actual==\n" if $opt_v;
if ($actual eq $output) {
print "Keeping VCS header $outfile\n $opt_N = \"$opt_V\"\n"
unless $opt_q;
exit 0;
}
print "Updating VCS header $outfile\n $opt_N = \"$opt_V\"\n"
unless $opt_q;
} else {
print "Creating VCS header $outfile\n $opt_N = \"$opt_V\"\n"
unless $opt_q;
open($DST, '>', $outfile)
or die "Can't create $outfile: $!\n";
}
seek $DST, 0, 0;
truncate $DST, 0;
print $DST $output;
close $DST;
sub HELP_MESSAGE {
print STDERR <<EOF;
Usage:
genVersionHeader.pl -h
Display this Usage message
genVersionHeader.pl [-v] [-q] [-t top] [-N NAME] [-V version] output.h";
Generate or update the header file output.h
-v - Verbose (debugging messages)
-q - Quiet
-t top - Path to the module's top (default '$opt_t')
-N NAME - Macro name to be defined (default '$opt_N')
-V version - Version if no VCS (e.g. '$opt_V')
EOF
exit $opt_h ? 0 : 1;
}