3

I am new to GNU autotools and in my project lex and yacc parsers are used.Including them as source in makefile.am produes following error :

configure.in :

...
AC_CHECK_PROGS(YACC,bison yacc,none)
if test "x$YACC" = "xbison"; then
    YACC="$YACC -y"
fi

AC_CHECK_PROGS(LEX,flex,none)
...

makefile.am :

## $Id
AUTOMAKE_OPTIONS=foreign no-dependencies
include $(srcdir)/Makefile_defs

dynamicpreprocessordir = ${libdir}/snort_dynamicpreprocessor

dynamicpreprocessor_LTLIBRARIES = libsf_appid_preproc.la


libsf_appid_preproc_la_LDFLAGS = -export-dynamic -module @XCCFLAGS@
if SO_WITH_STATIC_LIB
libsf_appid_preproc_la_LIBADD = ../libsf_dynamic_preproc.la 


../libsf_dynamic_utils.la $(LUA_LIBS)
else
nodist_libsf_appid_preproc_la_SOURCES = \
../include/sf_dynamic_preproc_lib.c \
../include/sf_ip.c \
../include/sfPolicyUserData.c \
../include/sfxhash.c \
../include/sfghash.c \
../include/sflsq.c \
../include/sfhashfcn.c \
../include/sfmemcap.c \
../include/sfprimetable.c

libsf_appid_preproc_la_LIBADD = $(LUA_LIBS)
endif

libsf_appid_preproc_la_CFLAGS = -DDYNAMIC_PREPROC_CONTEXT -DSTATIC=static $(LUA_CFLAGS)

libsf_appid_preproc_la_SOURCES = $(APPID_SOURCES)

all-local: $(LTLIBRARIES)
    $(MAKE) DESTDIR=`pwd`/../build install-dynamicpreprocessorLTLIBRARIES

In Makefile_defs :

APPID_SRC_DIR = ${top_srcdir}/src/dynamic-preprocessors/appid
...
APPID_SOURCES =  \
$(APPID_SRC_DIR)/vfml/fc45.lex  \
$(APPID_SRC_DIR)/vfml/fc45.y \
...

when i run the program i get following error :

libsf_appid_preproc.so: undefined symbol: FC45SetFile

While FC45SetFile() is already defined in fc45.lex file.

fc45.lex :

%{
#include "fc45.tab.h"
//#include "vfml.h"
#include <string.h>
#include <stdlib.h>

  /* HERE  doesn't match strings starting with numbers other than 0 right */

char string_buf[4000]; /* BUG - maybe check for strings that are too long? */
char *string_buf_ptr;

void FC45FinishString(void);

extern int gLineNumber;
%}

%x str_rule

%%
<str_rule,INITIAL>\|[^\n]* ;

[\ \t\r]+ ;
\n      gLineNumber++;

\. { return '.';}
, { return ',';}
: { return ':';}

ignore { return tIgnore; }
continuous { return tContinuous; }
discrete { return tDiscrete; }


[^:?,\t\n\r\|\.\\\ ] string_buf_ptr = string_buf; unput(yytext[0]); BEGIN(str_rule);

<str_rule>[:,?]             FC45FinishString(); unput(yytext[0]); return tString;
<str_rule>\.[\t\r\ ]    FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString;
<str_rule>\.\n    FC45FinishString(); unput(yytext[1]); unput(yytext[0]); return tString; gLineNumber++;

<str_rule><<EOF>> {
   int len = strlen(string_buf);
   //   printf("eof rule.\n");
   if(len == 1 && string_buf[0] == '.') {
     //printf("   period at end of file\n");
      return '.';
   } else if(string_buf[len - 1] == '.') {
     // printf("   period: %s - unput .\n", string_buf);

      FC45FinishString(); unput('.'); return tString;
   } else {
     // printf("   no-period: %s\n", string_buf);
      FC45FinishString(); return tString;
   }
}

<str_rule>\\:   *string_buf_ptr++ = ':';
<str_rule>\\\?  *string_buf_ptr++ = '?';
<str_rule>\\,   *string_buf_ptr++ = ',';
<str_rule>\\.    *string_buf_ptr++ = '.';

<str_rule>\n  *string_buf_ptr++ = ' '; gLineNumber++;
<str_rule>[ \t\r]+  *string_buf_ptr++ = ' ';

<str_rule>[^:?,\t\n\r\|\.\\\ ]+        {
   char *yptr = yytext;

   while(*yptr) {
      *string_buf_ptr++ = *yptr++;
   }
}


%%
int fc45wrap(void) {
    return 1;
}

void FC45SetFile(FILE *file) {
    fc45in = file;
    yyrestart(fc45in);
}

void FC45FinishString(void) {
   int len;
   char *tmpStr;

   BEGIN(INITIAL);
   *string_buf_ptr = '\0';

   len = strlen(string_buf);

   /* remove any ending spaces */
   while(string_buf[len - 1] == ' ') {
     string_buf[len - 1] = '\0';
     len--;
   }

   tmpStr = MNewPtr(len + 1);
   strncpy(tmpStr, string_buf, len + 1);
   fc45lval.string = tmpStr;
   string_buf[0] = '\0';
}

fc45.y :

%{
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "ExampleSpec1.h"
//#include "AttributeTracker.c"
//#include "vfml.h"
%}

%{
int fc45lex(void);
int fc45error(const char *);

/* HERE figure out how to give better error messages */
/* BUG needs a \n at the end of the names file */

/* These tmps are allocated at the begining of parsing and then
    used during parsing.  For example, so that we can simply
    add terrains to an area while parsing.  After parsing a
    statement, the associated tmp is added to the appropriate
    global list, and a new tmp is allocated.  Finally, at the
    end of parsing, all the tmps are freed
*/

ExampleSpecPtr        exampleSpec;
AttributeSpecPtr      attributeSpec;
int gLineNumber;

%}

%union {
   int integer;
   float f;
   char *string;
}

%token <integer> tInteger
%token <string>  tString

%token tIgnore tContinuous tDiscrete tEOF

%%

ExampleSpec: ClassList '.' AttributeList;

ClassList: ClassList ',' ClassSpec | ClassSpec /* ending */;

ClassSpec: tString { ExampleSpecAddClass(exampleSpec, $1); };

AttributeList: AttributeList AttributeSpec | /* ending */;

AttributeSpec: tString ':' AttributeInfo '.' { 
   AttributeSpecSetName(attributeSpec, $1);
   ExampleSpecAddAttributeSpec(exampleSpec, attributeSpec);
   attributeSpec = AttributeSpecNew();
};

AttributeInfo: tIgnore {
                   AttributeSpecSetType(attributeSpec, asIgnore);} |
               tContinuous {
                   AttributeSpecSetType(attributeSpec, asContinuous);} |
               tDiscrete tString {
                   AttributeSpecSetType(attributeSpec, asDiscreteNoName);
                   AttributeSpecSetNumValues(attributeSpec, atoi($2)); } |
               AttributeValueNameList { 
         AttributeSpecSetType(attributeSpec, asDiscreteNamed); };

AttributeValueNameList: AttributeValueNameList ',' tString {
   AttributeSpecSetNumValues(attributeSpec,
                     AttributeSpecGetNumValues(attributeSpec) + 1);
   AttributeSpecAddValue(attributeSpec, $3); } |
tString {
   AttributeSpecSetNumValues(attributeSpec,
                     AttributeSpecGetNumValues(attributeSpec) + 1);
   AttributeSpecAddValue(attributeSpec, $1); };

%%

void FC45SetFile(FILE *file);

int fc45error(const char *msg) {
   fprintf(stderr, "%s line %d\n", msg, gLineNumber);
   return 0;
}

ExampleSpecPtr ParseFC45(const char *file) {
   FILE *input;

   input = fopen(file, "r");
   if(input == 0) {
      return 0;
   }

   FC45SetFile(input);

   exampleSpec = ExampleSpecNew();
   attributeSpec = AttributeSpecNew();

   gLineNumber = 0;

   if(fc45parse()) {
      /* parse failed! */
      fprintf(stderr, "Error in parsing: %s\n", file);
   }

   fclose(input);

   /* free the left over attribute spec */
   AttributeSpecFree(attributeSpec);

   return exampleSpec;
}

I've searched Internet for the solution and was unable to come up with any. Hope someone recognizes the problem and has a quick solution to it. Any help will be appreciated.

Ajit Medhekar
  • 1,018
  • 1
  • 10
  • 39
Prabhakar
  • 513
  • 1
  • 5
  • 22
  • 1
    Typically your parser would read the *.y file and generate a *.c file for you to compile and link into your app or library. I don't see anywhere that you are doing that. – technosaurus Apr 15 '16 at 06:29
  • @technosaurus it is in fc45.tab.c file perhaps. link is : http://expirebox.com/download/e38e1eaab2b8e66d947104299a5e4929.html – Prabhakar Apr 15 '16 at 06:52
  • fc45.tab.c doesn't appear to appear in your makefile – technosaurus Apr 15 '16 at 07:43
  • @technosaurus I included it in APPID_SOURCES but error remains same. Can you provide more information on how to include parsers in this project ? – Prabhakar Apr 15 '16 at 08:25

2 Answers2

2

I just ran through a simple example, adding the following Autotools files:

configure.ac:

AC_PREREQ([2.69])
AC_INIT([example], [0.1a], [example@example.com])
AC_CONFIG_SRCDIR([ex1.l])

# Used only to shorten the otherwise lengthy compilation line in the output below.
AC_CONFIG_HEADERS([config.h])

AM_INIT_AUTOMAKE([foreign])

# I used C instead of C++.
AC_PROG_CC
AM_PROG_LEX
AC_PROG_YACC

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

Makefile.am (taken pretty much straight from the Automake manual):

BUILT_SOURCES = ex1.h
AM_YFLAGS = -d
bin_PROGRAMS = ex1
ex1_SOURCES = ex1.l ex1.y

It turned out that you can't name the files with the same base file name. In my case, I had ex1.l and ex1.y. Using ex1_SOURCES = ex1.l ex1.y resulted in the following output when I invoked make:

make[1]: Entering directory '/home/kit/ex1'
/bin/bash ./ylwrap ex1.l lex.yy.c ex1.c -- flex  
make[1]: Leaving directory '/home/kit/ex1'
make  all-am
make[1]: Entering directory '/home/kit/ex1'
gcc -DHAVE_CONFIG_H=1 -I. -g -O2 -MT ex1.o -MD -MP -MF .deps/ex1.Tpo -c -o ex1.o ex1.c
ex1.l:5:17: fatal error: ex1.h: No such file or directory
 #include "ex1.h"
                 ^
compilation terminated.
Makefile:378: recipe for target 'ex1.o' failed
make[1]: *** [ex1.o] Error 1
make[1]: Leaving directory '/home/kit/ex1'
Makefile:281: recipe for target 'all' failed
make: *** [all] Error 2

Note the fact that flex was invoked in the second line, but bison/yacc was not. What's the reason? Well, the ylwrap script is the reason:

ex1.c: ex1.l
ex1.c: ex1.y

Because the script renames the output of ex1.l from "lex.yy.c" to "ex1.c", the makefile thinks that ex1.c is already built, so it won't do anything with the bison/yacc file, which means that ex1.h isn't built either.

You can't disable the ylwrap script, but you can work around it: simply rename your flex source file and change the references to the file name in your Makefile.in and configure.ac files as necessary. You shouldn't need to rename your bison/yacc source file because that would mean changing every #include "fc45.h" to #include "fc45_g.h" (or whatever you renamed the file to) in every C file as well as your flex source file.

2

The problem is that neither make nor automake know anything about the non-standard .lex file extension, so when you have a source file that ends in .lex, they don't know what to do with it. You could create rules to handle .lex, but it's probably much easier to just rename the file with a .l file extension, which they know how to handle.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226