diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE
index ab30d7f8b..08515ac02 100644
--- a/configure/CONFIG_BASE
+++ b/configure/CONFIG_BASE
@@ -87,9 +87,9 @@ YACC = $(EYACC)
LEX = $(ELEX)
#---------------------------------------------------------------
-# msi used to be an external tool
+# Our use of msi is incompatible with older versions
-MSI ?= $(EPICS_BASE_HOST_BIN)/msi
+MSI3_15 = $(EPICS_BASE_HOST_BIN)/msi
#---------------------------------------------------------------
# External tools and tool flags - must be in path or defined in application
diff --git a/configure/RULES.Db b/configure/RULES.Db
index ecb3e7181..dd3ab9c0d 100644
--- a/configure/RULES.Db
+++ b/configure/RULES.Db
@@ -259,23 +259,19 @@ menu%.h$(DEP): ../menu%.dbd
%.db$(RAW)$(DEP): %$(SUBST_SUFFIX)
@$(RM) $@
- $(MKMF) -m$@ $(DBFLAGS) $(COMMONDEP_TARGET) $< $(TEMPLATE_FILENAME)
- @echo "$(COMMONDEP_TARGET): $(TEMPLATE_FILENAME)" >> $@
- @echo "$@: $(TEMPLATE_FILENAME)" >> $@
+ $(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) -S$< $(TEMPLATE_FILENAME) > $@
%.db$(RAW)$(DEP): ../%$(SUBST_SUFFIX)
@$(RM) $@
- $(MKMF) -m$@ $(DBFLAGS) $(COMMONDEP_TARGET) $< $(TEMPLATE_FILENAME)
- @echo "$(COMMONDEP_TARGET): $(TEMPLATE_FILENAME)" >> $@
- @echo "$@: $(TEMPLATE_FILENAME)" >> $@
+ $(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) -S$< $(TEMPLATE_FILENAME) > $@
%.db$(RAW)$(DEP): %.template
@$(RM) $@
- $(MKMF) -m$@ $(DBFLAGS) $(COMMONDEP_TARGET) $<
+ $(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) $< > $@
%.db$(RAW)$(DEP): ../%.template
@$(RM) $@
- $(MKMF) -m$@ $(DBFLAGS) $(COMMONDEP_TARGET) $<
+ $(MSI3_15) -D $(DBFLAGS) -o $(COMMONDEP_TARGET) $< > $@
%.acf$(DEP): %.acs
@$(RM) $@
@@ -461,27 +457,27 @@ $(COMMON_DIR)/%.db$(RAW): $(COMMON_DIR)/%.edf
$(COMMON_DIR)/%.db$(RAW): %$(SUBST_SUFFIX)
$(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
- @$(RM) $@ $*.tmp
- $(MSI) $(DBFLAGS) -S$< $(TEMPLATE_FILENAME) > $*.tmp
- $(MV) $*.tmp $@
+ @$(RM) $(notdir $@)
+ $(MSI3_15) $(DBFLAGS) -o $(notdir $@) -S$< $(TEMPLATE_FILENAME)
+ @$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.db$(RAW): ../%$(SUBST_SUFFIX)
$(ECHO) "Inflating database from $< $(TEMPLATE_FILENAME)"
- @$(RM) $@ $*.tmp
- $(MSI) $(DBFLAGS) -S$< $(TEMPLATE_FILENAME) > $*.tmp
- $(MV) $*.tmp $@
+ @$(RM) $(notdir $@)
+ $(MSI3_15) $(DBFLAGS) -o $(notdir $@) -S$< $(TEMPLATE_FILENAME)
+ @$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.db$(RAW): %.template
$(ECHO) "Inflating database from $<"
- @$(RM) $@ $*.tmp
- $(MSI) $(DBFLAGS) $< > $*.tmp
- $(MV) $*.tmp $@
+ @$(RM) $(notdir $@)
+ $(MSI3_15) $(DBFLAGS) -o $(notdir $@) $<
+ @$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.db$(RAW): ../%.template
$(ECHO) "Inflating database from $<"
- @$(RM) $@ $*.tmp
- $(MSI) $(DBFLAGS) $< > $*.tmp
- $(MV) $*.tmp $@
+ @$(RM) $(notdir $@)
+ $(MSI3_15) $(DBFLAGS) -o $(notdir $@) $<
+ @$(MV) $(notdir $@) $@
$(COMMON_DIR)/%.acf: %.acs
$(ECHO) "Creating acf file $@"
diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index cd2e7f339..aa27e96c5 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -14,6 +14,17 @@
Changes between 3.15.1 and 3.15.2
+Using msi for dependencies
+
+To reduce confusion the msi program has been modified to allow the generation
+of dependency rules by adding support for a -D option, and changing the
+commands in RULES.Db to use this option instead of the mkmf.pl script. The new
+build rules will not work with old versions of the msi program, so the command
+variable name used in the rules has been changed from MSI to MSI3_15. Sites that
+use a modified version of msi must provide support for both the -D and
+-o outfile options, and should then point the MSI3_15 variable in
+their applications' CONFIG_SITE files to that updated executable.
+
Changes between 3.15.0.2 and 3.15.1
epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()
diff --git a/src/ioc/dbtemplate/msi.c b/src/ioc/dbtemplate/msi.c
index 782161a7f..5a5023163 100644
--- a/src/ioc/dbtemplate/msi.c
+++ b/src/ioc/dbtemplate/msi.c
@@ -24,6 +24,7 @@
#include
#define MAX_BUFFER_SIZE 4096
+#define MAX_DEPS 1024
/* Module to read the template files */
typedef struct inputData inputData;
@@ -47,12 +48,16 @@ static char *substituteGetReplacements(subInfo *pvt);
static char *substituteGetGlobalReplacements(subInfo *pvt);
/* Forward references to local routines */
-static void usageExit(void);
+static void usageExit(int status);
static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval);
static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName);
/*Global variables */
static int opt_V = 0;
+static int opt_D = 0;
+
+static char *outFile = 0;
+static int numDeps = 0, depHashes[MAX_DEPS];
int main(int argc,char **argv)
@@ -73,24 +78,26 @@ int main(int argc,char **argv)
pval = (narg==1) ? (argv[1]+2) : argv[2];
if(strncmp(argv[1],"-I",2)==0) {
inputAddPath(inputPvt,pval);
+ } else if (strcmp(argv[1], "-D") == 0) {
+ opt_D = 1;
+ narg = 1; /* no argument for this option */
} else if(strncmp(argv[1],"-o",2)==0) {
- if(freopen(pval,"w",stdout)==NULL) {
- fprintf(stderr,"msi: Can't open %s for writing: %s\n",
- pval, strerror(errno));
- exit(1);
- }
+ outFile = epicsStrDup(pval);
} else if(strncmp(argv[1],"-M",2)==0) {
addMacroReplacements(macPvt,pval);
} else if(strncmp(argv[1],"-S",2)==0) {
substitutionName = epicsStrDup(pval);
- } else if(strncmp(argv[1],"-V",2)==0) {
+ } else if (strcmp(argv[1], "-V") == 0) {
opt_V = 1;
narg = 1; /* no argument for this option */
- } else if(strncmp(argv[1],"-g",2)==0) {
+ } else if (strcmp(argv[1], "-g") == 0) {
localScope = 0;
narg = 1; /* no argument for this option */
+ } else if (strcmp(argv[1], "-h") == 0) {
+ usageExit(0);
} else {
- usageExit();
+ fprintf(stderr, "msi: Bad argument \"%s\"\n", argv[1]);
+ usageExit(1);
}
argc -= narg;
for(i=1; i2) {
fprintf(stderr,"msi: Too many arguments\n");
- usageExit();
+ usageExit(1);
+ }
+ if (opt_D) {
+ if (!outFile) {
+ fprintf(stderr, "msi: Option -D requires -o for Makefile target\n");
+ exit(1);
+ }
+ printf("%s:", outFile);
+ }
+ else if (outFile && freopen(outFile, "w", stdout) == NULL) {
+ fprintf(stderr, "msi: Can't open %s for writing: %s\n",
+ outFile, strerror(errno));
+ exit(1);
}
if(argc==2) {
templateName = epicsStrDup(argv[1]);
@@ -122,7 +141,7 @@ int main(int argc,char **argv)
if(templateName) filename = templateName;
if(!filename) {
fprintf(stderr,"msi: No template file\n");
- usageExit();
+ usageExit(1);
}
while((pval = substituteGetReplacements(substitutePvt))){
if (localScope) macPushScope(macPvt);
@@ -137,24 +156,30 @@ int main(int argc,char **argv)
errlogFlush();
macDeleteHandle(macPvt);
inputDestruct(inputPvt);
+ if (opt_D) {
+ printf("\n");
+ }
free(templateName);
free(substitutionName);
return opt_V & 2;
}
-void usageExit(void)
+void usageExit(int status)
{
- fprintf(stderr,"usage: msi [options] [template]\n");
- fprintf(stderr,"stdin is used if neither template nor substitution file is given\n");
- fprintf(stderr,"options:\n");
- fprintf(stderr," -V Undefined macros generate an error\n");
- fprintf(stderr," -g All macros have global scope\n");
- fprintf(stderr," -o Save output to \n");
- fprintf(stderr," -I Add to include file search path\n");
- fprintf(stderr," -M Add to (global) macro definitions\n");
- fprintf(stderr," ( takes the form VAR=VALUE,...)\n");
- fprintf(stderr," -S Expand the substitutions in FILE\n");
- exit(1);
+ fprintf(stderr,
+ "Usage: msi [options] [template]\n"
+ " stdin is used if neither template nor substitution file is given\n"
+ " options:\n"
+ " -h Print this help message\n"
+ " -D Output file dependencies, not substitutions\n"
+ " -V Undefined macros generate an error\n"
+ " -g All macros have global scope\n"
+ " -o Send output to \n"
+ " -I Add to include file search path\n"
+ " -M Add to (global) macro definitions\n"
+ " ( takes the form VAR=VALUE,...)\n"
+ " -S Expand the substitutions in FILE\n");
+ exit(status);
}
static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval)
@@ -165,13 +190,13 @@ static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval)
status = macParseDefns(macPvt,pval,&pairs);
if(status==-1) {
fprintf(stderr,"msi: Error from macParseDefns\n");
- usageExit();
+ usageExit(1);
}
if(status) {
status = macInstallMacros(macPvt,pairs);
if(!status) {
fprintf(stderr,"Error from macInstallMacros\n");
- usageExit();
+ usageExit(1);
}
free(pairs);
}
@@ -249,7 +274,7 @@ static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *tem
expand = 0;
}
endif:
- if (expand) {
+ if (expand && !opt_D) {
n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1);
fputs(buffer,stdout);
if (opt_V == 1 && n < 0) {
@@ -432,6 +457,32 @@ static void inputOpenFile(inputData *pinputData,char *filename)
} else {
pinputFile->filename = epicsStrDup("stdin");
}
+
+ if (opt_D) {
+ int hash = epicsStrHash(pinputFile->filename, 12345);
+ int i = 0;
+ int match = 0;
+
+ while (i < numDeps) {
+ if (hash == depHashes[i++]) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ const char *wrap = numDeps ? " \\\n" : "";
+
+ printf("%s %s", wrap, pinputFile->filename);
+ if (numDeps < MAX_DEPS) {
+ depHashes[numDeps++] = hash;
+ }
+ else {
+ fprintf(stderr, "msi: More than %d dependencies!\n", MAX_DEPS);
+ depHashes[0] = hash;
+ }
+ }
+ }
+
pinputFile->fp = fp;
ellInsert(&pinputData->inputFileList,0,&pinputFile->node);
}
diff --git a/src/ioc/dbtemplate/test/Makefile b/src/ioc/dbtemplate/test/Makefile
index 27bb17ac0..30e748983 100644
--- a/src/ioc/dbtemplate/test/Makefile
+++ b/src/ioc/dbtemplate/test/Makefile
@@ -22,6 +22,6 @@ TARGETS += $(TARGETS_$(BUILD_CLASS))
include $(TOP)/configure/RULES
-msi-copy$(EXE): $(INSTALL_BIN)/msi$(EXE) ../Makefile
+msi-copy$(EXE): $(INSTALL_BIN)/msi$(EXE)
@$(RM) $@
$(CP) $< $@
diff --git a/src/ioc/dbtemplate/test/msi.plt b/src/ioc/dbtemplate/test/msi.plt
index 7d8aab7b2..f584dcf3d 100644
--- a/src/ioc/dbtemplate/test/msi.plt
+++ b/src/ioc/dbtemplate/test/msi.plt
@@ -11,23 +11,40 @@
use strict;
use Test;
-BEGIN {plan tests => 7}
+BEGIN {plan tests => 9}
+# Check include/substitute command model
ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt'));
-ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt'));
-ok(msi('-I. -I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt'));
-ok(msi('-g -I.. -S ../t4-substitution.txt'), slurp('../t4-result.txt'));
-ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt'));
-ok(msi('-S ../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt'));
-# Check -o works
+# Substitution file, dbLoadTemplate format
+ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt'));
+
+# Macro scoping
+ok(msi('-I. -I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt'));
+
+# Global scope (backwards compatibility check)
+ok(msi('-g -I.. -S ../t4-substitution.txt'), slurp('../t4-result.txt'));
+
+# Substitution file, regular format
+ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt'));
+
+# Substitution file, pattern format
+ok(msi('-S../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt'));
+
+# Output option -o
my $out = 't7-output.txt';
unlink $out;
msi("-I.. -o $out ../t1-template.txt");
ok(slurp($out), slurp('../t1-result.txt'));
+# Dependency generation, include/substitute model
+ok(msi('-I.. -D -o t8.txt ../t1-template.txt'), slurp('../t8-result.txt'));
-# Support routines
+# Dependency generation, dbLoadTemplate format
+ok(msi('-I.. -D -ot9.txt -S ../t2-substitution.txt'), slurp('../t9-result.txt'));
+
+
+# Test support routines
sub slurp {
my ($file) = @_;
diff --git a/src/ioc/dbtemplate/test/t8-result.txt b/src/ioc/dbtemplate/test/t8-result.txt
new file mode 100644
index 000000000..478c00614
--- /dev/null
+++ b/src/ioc/dbtemplate/test/t8-result.txt
@@ -0,0 +1,2 @@
+t8.txt: ../t1-template.txt \
+ ../t1-include.txt
diff --git a/src/ioc/dbtemplate/test/t9-result.txt b/src/ioc/dbtemplate/test/t9-result.txt
new file mode 100644
index 000000000..9f122bbcf
--- /dev/null
+++ b/src/ioc/dbtemplate/test/t9-result.txt
@@ -0,0 +1 @@
+t9.txt: ../t2-template.txt