I'm trying to make a SConstruct that will...
All using Clang++ on Macos (Catalina)
Now is where I have to say that I'm not an expert in C++, so probably I'm missing something very obvious... hopefully.
The problem I have is on the first and last step.
I can build the Antlr4 runtime but later on it doesn't link with the final program. Simply invoking #include "antlr4-runtime.h"
results in an Undefined symbols for architecture x86_64
error.
The curious thing is that, if I build Antlr4 runtime with cmake, as explained in Antlr's repository, then the linking problem disappear.
So I built it with cmake and used the VERBOSE mode to see how make build the various object files and made sure that I use the same flags with Scons
Example of output with cmake/make:
clang++
-Iantlr4-master/runtime/Cpp/runtime/src
-Iantlr4-master/runtime/Cpp/runtime/src/atn
-Iantlr4-master/runtime/Cpp/runtime/src/dfa
-Iantlr4-master/runtime/Cpp/runtime/src/misc
-Iantlr4-master/runtime/Cpp/runtime/src/support
-Iantlr4-master/runtime/Cpp/runtime/src/tree
-Iantlr4-master/runtime/Cpp/runtime/src/tree/pattern
-Iantlr4-master/runtime/Cpp/runtime/src/tree/xpath
-Wall -pedantic -W -std=c++11 -stdlib=libc++ -O3 -DNDEBUG -O3 -DNDEBUG
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
-Wno-overloaded-virtual -Wno-dollar-in-identifier-extension -Wno-four-char-constants -std=gnu++11
-o CMakeFiles/antlr4_static.dir/src/atn/PredicateTransition.cpp.o
-c antlr4-master/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp
Obviously this is supposed to be one single line but I splitted in multiple lines for the sake of making it easier to read ;)
So I grabbed all those flags and putted them into a string and let Scons figure out how to apply them to an environment:
pf = env.ParseFlags('\
-Wall -pedantic -W -O3 -std=c++11 -stdlib=libc++ -DNDEBUG -std=gnu++11 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk \
-Wno-overloaded-virtual -Wno-dollar-in-identifier-extension -Wno-four-char-constants')
env.MergeFlags(pf)
Now I built Antlr4 again with SCons and this is and example of command that SCons creates:
clang++
-o antlr4-master/runtime/Cpp/runtime/src/atn/PredicateTransition.o
-c
-std=c++11 -stdlib=libc++ -Wall -pedantic -W -O3
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
-Wno-overloaded-virtual -Wno-dollar-in-identifier-extension -Wno-four-char-constants -DNDEBUG
-Iantlr4-master/runtime/Cpp/runtime/src
antlr4-master/runtime/Cpp/runtime/src/atn/PredicateTransition.cpp
Again I split in multiple lines only for make it easy to read...
The first thing I notice is that the order of the arguments in the command are all over the place in SCons but the rest is pretty much the same.
Unfortunately, this gives me the same Undefined symbols for architecture x86_64
error.
Probably you noticed that I have included only the main directory of antlr4 runtime, that should work because all the include starts from that directory... Anyway, i have also try to include all the subfolders like cmake/make does, the result was the same.
I'm really clueless at this point. Hopefully some of you will be able to put me in the right direction.
This is my SConstruct file (paths are different than the examples. but it shouldn't matter)
import os
import subprocess
env = Environment(
CC = "clang",
CXX = "clang++",
CXXFLAGS = ['-std=c++11', '-stdlib=libc++'],
LINKFLAGS = ['-stdlib=libc++'],
)
env.Append(ENV = {'CLASSPATH': './dependencies/antlr4/antlr-4.8-complete.jar'})
#
# Builder for generating grammar files with antlr4 (the java app)
#
def antlr_emitter(target, source, env):
root = os.path.splitext(source[0].name)[0]
target = ['./src/Parser/{}{}.cpp'.format(root, p) for p in (
'BaseListener',
'BaseVisitor',
'Lexer',
'Listener',
'Parser',
'Visitor'
)]
return target, source
AntlrBuilder = Builder(
action='java org.antlr.v4.Tool $SOURCE -Dlanguage=Cpp -package Coral -visitor -listener -o src/Parser',
emitter=antlr_emitter
)
env.Append(BUILDERS={'Antlr': AntlrBuilder})
#
# Cloning the Environment for Antlr4 runtime
#
antlrEnv = env.Clone()
pf = antlrEnv.ParseFlags('\
-Wall -pedantic -W -O3 -DNDEBUG -std=gnu++11 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk \
-Wno-overloaded-virtual -Wno-dollar-in-identifier-extension -Wno-four-char-constants')
antlrEnv.MergeFlags(pf)
#
# Building in 3 steps, first the antlr4 runtime library, then the parser files with Antlr then the final program
#
AntlrRuntime = antlrEnv.Library(
'antlr4-runtime',
source =
Glob('./dependencies/antlr4Runtime/*.cpp') + \
Glob('./dependencies/antlr4Runtime/atn/*.cpp') + \
Glob('./dependencies/antlr4Runtime/dfa/*.cpp') + \
Glob('./dependencies/antlr4Runtime/misc/*.cpp') + \
Glob('./dependencies/antlr4Runtime/support/.cpp') + \
Glob('./dependencies/antlr4Runtime/tree/*.cpp') + \
Glob('./dependencies/antlr4Runtime/tree/pattern/*.cpp') + \
Glob('./dependencies/antlr4Runtime/tree/xpath/*.cpp'),
CPPPATH = './dependencies/antlr4Runtime',
ARFLAGS = 'qc'
)
ParserFiles = env.Antlr(source='Coral.g4')
CoralLang = env.Program(target = 'coral',
source = Glob('./src/*.cpp') + Glob('./src/Parser/*.cpp'),
CPPPATH = ['./src', './dependencies/antlr4Runtime'],
LIBPATH = '.',
LIBS = 'antlr4-runtime'
)
Requires(ParserFiles, AntlrRuntime)
Depends(CoralLang, ParserFiles)
Clean(ParserFiles, Glob('./src/Parser/*'))
And finally this is the main.cpp file. As you see it has nothing, just the include to antlr runtime and that is enough to see the error.
#include <cstdio>
#include "antlr4-runtime.h"
int main(int argc, const char *argv[])
{
if (!argv[1]) {
printf("hey! pass at least a file to parse...");
return 0;
}
else {
printf("parsing %s\n", argv[1]);
}
return 1;
}
The whole SCons' output when trying to build the program with the relative error is this:
clang++ -o src/Parser/CoralParser.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralParser.cpp
clang++ -o src/Parser/CoralBaseVisitor.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralBaseVisitor.cpp
clang++ -o src/Parser/CoralListener.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralListener.cpp
clang++ -o src/Parser/CoralVisitor.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralVisitor.cpp
clang++ -o src/Parser/CoralBaseListener.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralBaseListener.cpp
clang++ -o src/Parser/CoralLexer.o -c -std=c++11 -stdlib=libc++ -Isrc -Idependencies/antlr4Runtime src/Parser/CoralLexer.cpp
clang++ -o coral -stdlib=libc++ src/main.o src/Parser/CoralBaseListener.o src/Parser/CoralBaseVisitor.o src/Parser/CoralLexer.o src/Parser/CoralListener.o src/Parser/CoralParser.o src/Parser/CoralVisitor.o -L. -lantlr4-runtime
Undefined symbols for architecture x86_64:
"Guid::Guid(unsigned short const*, bool)", referenced from:
antlr4::atn::ATNDeserializer::deserialize(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::toUUID(unsigned short const*, unsigned long) in libantlr4-runtime.a(ATNDeserializer.o)
"Guid::Guid(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
antlr4::atn::ATNDeserializer::ADDED_PRECEDENCE_TRANSITIONS() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::ADDED_LEXER_ACTIONS() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::ADDED_UNICODE_SMP() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::SERIALIZED_UUID() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::BASE_SERIALIZED_UUID() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::SUPPORTED_UUIDS() in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::deserialize(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) in libantlr4-runtime.a(ATNDeserializer.o)
...
"Guid::Guid(Guid const&)", referenced from:
antlr4::atn::ATNDeserializer::SUPPORTED_UUIDS() in libantlr4-runtime.a(ATNDeserializer.o)
"antlr4::ANTLRErrorListener::~ANTLRErrorListener()", referenced from:
antlr4::Recognizer::Recognizer() in libantlr4-runtime.a(Recognizer.o)
antlr4::Recognizer::~Recognizer() in libantlr4-runtime.a(Recognizer.o)
antlr4::ProxyErrorListener::~ProxyErrorListener() in libantlr4-runtime.a(ProxyErrorListener.o)
antlr4::ProxyErrorListener::~ProxyErrorListener() in libantlr4-runtime.a(ProxyErrorListener.o)
antlr4::ConsoleErrorListener::~ConsoleErrorListener() in libantlr4-runtime.a(ConsoleErrorListener.o)
antlr4::ConsoleErrorListener::~ConsoleErrorListener() in libantlr4-runtime.a(ConsoleErrorListener.o)
antlr4::BaseErrorListener::~BaseErrorListener() in libantlr4-runtime.a(BaseErrorListener.o)
...
"antlrcpp::replaceAll(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
antlr4::Recognizer::getTokenErrorDisplay(antlr4::Token*) in libantlr4-runtime.a(Recognizer.o)
antlr4::DefaultErrorStrategy::escapeWSAndQuote(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const in libantlr4-runtime.a(DefaultErrorStrategy.o)
antlr4::CommonToken::toString(antlr4::Recognizer*) const in libantlr4-runtime.a(CommonToken.o)
"antlrcpp::arrayToString(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)", referenced from:
antlr4::ParserRuleContext::toInfoString(antlr4::Parser*) in libantlr4-runtime.a(ParserRuleContext.o)
"antlrcpp::escapeWhitespace(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool)", referenced from:
antlr4::LexerNoViableAltException::toString() in libantlr4-runtime.a(LexerNoViableAltException.o)
antlr4::tree::Trees::toStringTree(antlr4::tree::ParseTree*, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, bool) in libantlr4-runtime.a(Trees.o)
"antlrcpp::SingleWriteMultipleReadLock::readUnlock()", referenced from:
antlr4::atn::LexerATNSimulator::getExistingTargetState(antlr4::dfa::DFAState*, unsigned long) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::ParserATNSimulator::getExistingTargetState(antlr4::dfa::DFAState*, unsigned long) in libantlr4-runtime.a(ParserATNSimulator.o)
"antlrcpp::SingleWriteMultipleReadLock::writeUnlock()", referenced from:
antlr4::atn::LexerATNSimulator::addDFAEdge(antlr4::dfa::DFAState*, unsigned long, antlr4::dfa::DFAState*) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::LexerATNSimulator::addDFAState(antlr4::atn::ATNConfigSet*) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::ParserATNSimulator::adaptivePredict(antlr4::TokenStream*, unsigned long, antlr4::ParserRuleContext*) in libantlr4-runtime.a(ParserATNSimulator.o)
antlr4::atn::ParserATNSimulator::addDFAEdge(antlr4::dfa::DFA&, antlr4::dfa::DFAState*, long, antlr4::dfa::DFAState*) in libantlr4-runtime.a(ParserATNSimulator.o)
antlr4::dfa::DFA::setPrecedenceStartState(int, antlr4::dfa::DFAState*, antlrcpp::SingleWriteMultipleReadLock&) in libantlr4-runtime.a(DFA.o)
"antlrcpp::SingleWriteMultipleReadLock::readLock()", referenced from:
antlr4::atn::LexerATNSimulator::getExistingTargetState(antlr4::dfa::DFAState*, unsigned long) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::ParserATNSimulator::getExistingTargetState(antlr4::dfa::DFAState*, unsigned long) in libantlr4-runtime.a(ParserATNSimulator.o)
"antlrcpp::SingleWriteMultipleReadLock::writeLock()", referenced from:
antlr4::atn::LexerATNSimulator::addDFAEdge(antlr4::dfa::DFAState*, unsigned long, antlr4::dfa::DFAState*) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::LexerATNSimulator::addDFAState(antlr4::atn::ATNConfigSet*) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::ParserATNSimulator::adaptivePredict(antlr4::TokenStream*, unsigned long, antlr4::ParserRuleContext*) in libantlr4-runtime.a(ParserATNSimulator.o)
antlr4::atn::ParserATNSimulator::addDFAEdge(antlr4::dfa::DFA&, antlr4::dfa::DFAState*, long, antlr4::dfa::DFAState*) in libantlr4-runtime.a(ParserATNSimulator.o)
antlr4::dfa::DFA::setPrecedenceStartState(int, antlr4::dfa::DFAState*, antlrcpp::SingleWriteMultipleReadLock&) in libantlr4-runtime.a(DFA.o)
"antlrcpp::toMap(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&)", referenced from:
antlr4::Recognizer::getRuleIndexMap() in libantlr4-runtime.a(Recognizer.o)
"antlrcpp::indent(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool)", referenced from:
antlr4::atn::ATN::toString() const in libantlr4-runtime.a(ATN.o)
"antlrcpp::finally(std::__1::function<void ()>)", referenced from:
Coral::CoralParser::unit() in CoralParser.o
Coral::CoralParser::assignment() in CoralParser.o
Coral::CoralParser::variable() in CoralParser.o
Coral::CoralParser::number() in CoralParser.o
Coral::CoralParser::expression(int) in CoralParser.o
antlr4::atn::LexerATNSimulator::match(antlr4::CharStream*, unsigned long) in libantlr4-runtime.a(LexerATNSimulator.o)
antlr4::atn::LexerATNSimulator::evaluatePredicate(antlr4::CharStream*, unsigned long, unsigned long, bool) in libantlr4-runtime.a(LexerATNSimulator.o)
...
"Guid::toString() const", referenced from:
antlr4::atn::ATNDeserializer::deserialize(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) in libantlr4-runtime.a(ATNDeserializer.o)
"Guid::operator==(Guid const&) const", referenced from:
antlr4::atn::ATNDeserializer::isFeatureSupported(Guid const&, Guid const&) in libantlr4-runtime.a(ATNDeserializer.o)
antlr4::atn::ATNDeserializer::deserialize(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > const&) in libantlr4-runtime.a(ATNDeserializer.o)
"typeinfo for antlr4::ANTLRErrorListener", referenced from:
typeinfo for antlr4::ProxyErrorListener in libantlr4-runtime.a(ProxyErrorListener.o)
typeinfo for antlr4::BaseErrorListener in libantlr4-runtime.a(BaseErrorListener.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Based on the missing symbol output, you need to add at least one more library to your LIBS. Whatever provides:
Guid::*
antlr4::*
antlrcpp::*
You might try running
ldd libantlr-runtime.so
To see what library it expects to link against?