Merged gen-vcs-version branch
This commit is contained in:
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
6
src/template/base/top/exampleApp/Db/_APPNAME_Version.db
Normal file
6
src/template/base/top/exampleApp/Db/_APPNAME_Version.db
Normal 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")
|
||||
}
|
@ -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)
|
||||
|
38
src/template/base/top/exampleApp/src/dev_APPNAME_Version.c
Normal file
38
src/template/base/top/exampleApp/src/dev_APPNAME_Version.c
Normal 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);
|
@ -0,0 +1 @@
|
||||
device(lsi,INST_IO,dev_CSAFEAPPNAME_Version,"_APPNAME_ version")
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
171
src/tools/genVersionHeader.pl
Normal file
171
src/tools/genVersionHeader.pl
Normal 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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user