Having slight difficulties with the C++ Runtime. Linking fails.

1,060 views
Skip to first unread message

Norman Dunbar

unread,
Sep 18, 2018, 3:36:21 PM9/18/18
to antlr-di...@googlegroups.com
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.

Thomas Burg

unread,
Sep 18, 2018, 6:59:33 PM9/18/18
to antlr-di...@googlegroups.com
Hi

You run a command similar to this one :
antlr4 -Dlanguage=Cpp usbmParser.g4

The command must have generate those file :usbmLexer.cpp usbmParser.cpp usbmBaseListener.cpp and a couple of others. You must compile those file too.
Then you must have usbmLexer.o usbmParser.o usbmBaseListener.o on your link command.
If you don't have them there is probably somthing wrong in your CMakeList.txt.

Thomas

--
You received this message because you are subscribed to the Google Groups "antlr-discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to antlr-discussi...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Norman Dunbar

unread,
Sep 19, 2018, 3:45:32 AM9/19/18
to antlr-discussion
Morning Thomas,

thanks for your reply. 

I've got no problem with the grammar file being processed and it is being done as I can see the files produced in the appropriate directory, I'm using the tutorial at http://blorente.me//Antlr-,-C++-and-CMake-Wait-what.html whihc advises that I use the following:

# Call macro to add lexer and grammar to your build dependencies.
# NOTE: Here, we define "antlrcpptest" as our project's namespace
antlr4cpp_process_grammar(demo antlrcpptest
  ${CMAKE_CURRENT_SOURCE_DIR}/TLexer.g4
  ${CMAKE_CURRENT_SOURCE_DIR}/TParser.g4)
# include generated files in project environment
include_directories(${antlr4cpp_include_dirs_antlrcpptest})


The macro is defined in the C++ runtime's 'ExternalAntlr4Cpp.cmake'  file, (also on GitHub at https://github.com/antlr/antlr4/blob/master/runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake) and has the following in the comments:

############ Generate runtime #################
# macro to add dependencies to target
#
# Param 1 project name
# Param 1 namespace (postfix for dependencies)
# Param 2 Lexer file (full path)
# Param 3 Parser File (full path)
#
# output
#
# antlr4cpp_src_files_{namespace} - src files for add_executable
# antlr4cpp_include_dirs_{namespace} - include dir for generated headers
# antlr4cpp_generation_{namespace} - for add_dependencies tracking



so, I'm assuming that CMake is doing what it should. It's certainly finding the *.h files which are in that generated location. 


I'll see if there's a CMake debug switch, or something, to get it to dump out something useful when I get home tonight.

Thanks again.

Norman Dunbar

unread,
Sep 19, 2018, 4:05:33 AM9/19/18
to antlr-discussion
> I'll see if there's a CMake debug switch, or something, to get it to dump out something useful when I get home tonight.

Looks like --trace or --trace-expand is what I need. :-)

Norman Dunbar

unread,
Sep 19, 2018, 12:56:31 PM9/19/18
to antlr-discussion
 Ok, now I'm confused!

I got home and fired up the laptop. When I ran the cmake command with --trace-expand I realised it was no good to me as I needed to debug the make process.

However, when I then typed make -d, everything compiled and linked with no errors at all.

Sorry about the noise. There must have been "something" wrong in the shell session I was working in that has gone away now that I've started a new one. Sigh.
Reply all
Reply to author
Forward
0 new messages