Greetings.
First of all, today is the first time I've tried out the C++ runtime,
but I have a new project and I'm keen to try C++ as I'm rather unfond of
Java.
So, I've spent the evening getting a small test file to compile. I used
the tutorial at
http://blorente.me//Antlr-,-C++-and-CMake-Wait-what.html
which duly downloaded the runtime sources and built them quite happily
(and eventually - I have an older laptop!)
However, the test program from that site needed a wee massage to fit
with my grammar, it looks like this:
#include <iostream>
#include "antlr4-runtime.h"
#include "usbmLexer.h"
#include "usbmParser.h"
#include "usbmBaseListener.h"
using namespace antlr4;
using namespace antlrcpptest;
using std::cout;
using std::endl;
class myListener : public usbmBaseListener {
public:
void enterKeyword(usbmParser::KeywordContext *ctx) override {
// Do something when entering the keyword rule.
cout << "enterKeyword() entered." << endl;
}
void exitKeyword(usbmParser::KeywordContext *ctx) override {
// Do something when entering the keyword rule.
cout << "enterKeyword() entered." << endl;
}
};
int main(int argc, const char* argv[]) {
// Open input file from command line.
std::ifstream stream;
stream.open(argv[1]);
// Convert for ANTLR4.
ANTLRInputStream input(stream);
// We need a lexer to tokenise the input file.
usbmLexer lexer(&input);
// Grab the lexer's tokens.
CommonTokenStream tokens(&lexer);
// We now need a parser to parse those tokens into a parse tree.
usbmParser parser(&tokens);
// Grab the parse tree, top rule is to be 'file'.
tree::ParseTree *tree = parser.file();
// Now, create the listener we will use when walking the tree.
myListener listener;
// And walk the tree, calling the listener for every rule.
tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
return 0;
}
I'll keep the code stuff short, apologies in advance.
My grammar is named 'usbm.g4' and has been built with ANTLR4 version
4.7.1 the runtime is the same version as far as I can see.
Anyway, I have a listener:
namespace antlrcpptest {
class usbmListener : public antlr4::tree::ParseTreeListener {
public:
...
virtual void enterKeyword(usbmParser::KeywordContext *ctx) = 0;
virtual void exitKeyword(usbmParser::KeywordContext *ctx) = 0;
...
}
And a parser:
namespace antlrcpptest {
class usbmParser : public antlr4::Parser {
...
usbmParser(antlr4::TokenStream *input);
~usbmParser();
...
}
}
And a lexer:
namespace antlrcpptest {
class usbmLexer : public antlr4::Lexer {
...
usbmLexer(antlr4::CharStream *input);
~usbmLexer();
...
}
}
And everything compiles ok, on Linux Mint 18.3, with g++ version 5.4.0.
However, the link fails as follows (using a makefile created by CMake as
per the tutorial):
[100%] Linking CXX executable test_antlr
CMakeFiles/test_antlr.dir/main.cpp.o: In function `main':
main.cpp:(.text+0x8a): undefined reference to
`antlrcpptest::usbmLexer::usbmLexer(antlr4::CharStream*)'
main.cpp:(.text+0xc0): undefined reference to
`antlrcpptest::usbmParser::usbmParser(antlr4::TokenStream*)'
main.cpp:(.text+0xcf): undefined reference to
`antlrcpptest::usbmParser::file()'
main.cpp:(.text+0x130): undefined reference to
`antlrcpptest::usbmParser::~usbmParser()'
main.cpp:(.text+0x14e): undefined reference to
`antlrcpptest::usbmLexer::~usbmLexer()'
main.cpp:(.text+0x1ac): undefined reference to
`antlrcpptest::usbmParser::~usbmParser()'
main.cpp:(.text+0x1d4): undefined reference to
`antlrcpptest::usbmLexer::~usbmLexer()'
collect2: error: ld returned 1 exit status
Normally, I can sort these things out in C++, but I'm a tad stumped this
evening, and I just know it will be something simple.
It appears that perhaps the linker hasn't been passed the location of
the library that was built (static and dynamic) and running 'make
--just-print' unfortunately, doesn't offer much assistance - this line
appears to be significant:
/usr/bin/cmake -E cmake_link_script CMakeFiles/test_antlr.dir/link.txt
--verbose=
And looking in the link.txt file mentioned, I see this, which I've split
up across various parameters for ease of reading:
/usr/bin/c++ CMakeFiles/test_antlr.dir/main.cpp.o -o test_antlr
-L/data/SourceCode/ANTLR4/test_antlr/build/externals/antlr4cpp/lib
-lantlr4-runtime
-Wl,-rpath,
/data/SourceCode/ANTLR4/test_antlr/build/externals/antlr4cpp/lib
And in the '-L' directory, I see these files:
libantlr4-runtime.a
libantlr4-runtime.so
libantlr4-runtime.so.4.7.1
Which are obviously the static and dynamic libraries, all present and
correct as far as the -L and -l parameters in the link.txt file are
concerned.
If you are still with me this far, thanks, and the question has to be,
what is the simple thing I'm missing?
Many thanks indeed.
Cheers,
Norm.
Disclaimer: I'm not a compiler writer, nor do I play one on TV.