Building LLVM on OS X Yosemite & Passes

I want to create LLVM passes on OS X Yosemite. First, I built LLVM as such (based on http://llvm.org/docs/GettingStarted.html and trial & error):

$ mkdir build && cd build
$ CC=clang CXX=“clang++ -stdlib=libc++” …/llvm/configure --enable-libcpp --enable-shared
$ make
$ make install

Then, I tested it with the following command. It worked!

$ opt -load /usr/local/lib/LLVMHello.dylib -hello <test.bc>/dev/null

However, when attempting to build my own pass in OS X Yosemite, I ran into confusing linking problems:

$ c++ $(CXXFLAGS) SourceLineAnnotator.cpp -c -o SourceLineAnnotator.o
$ c++ SourceLineAnnotator.o -shared -o annotate.so

Undefined symbols for architecture x86_64:
“llvm::ModulePass::assignPassManager(llvm::PMStack&, llvm::PassManagerType)”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::ModulePass::~ModulePass()”, referenced from:
cs380c::SourceLineAnnotator::~SourceLineAnnotator() in SourceLineAnnotator.o
“llvm::raw_ostream::write(char const*, unsigned long)”, referenced from:
llvm::raw_ostream::operator<<(llvm::StringRef) in SourceLineAnnotator.o
“llvm::raw_ostream::operator<<(unsigned long)”, referenced from:
llvm::raw_ostream::operator<<(unsigned int) in SourceLineAnnotator.o
“llvm::PassRegistry::registerPass(llvm::PassInfo const&, bool)”, referenced from:
llvm::RegisterPasscs380c::SourceLineAnnotator::RegisterPass(char const*, char const*, bool, bool) in SourceLineAnnotator.o
“llvm::PassRegistry::getPassRegistry()”, referenced from:
llvm::RegisterPasscs380c::SourceLineAnnotator::RegisterPass(char const*, char const*, bool, bool) in SourceLineAnnotator.o
“llvm::AssemblyAnnotationWriter::~AssemblyAnnotationWriter()”, referenced from:
SourceLineAssemblyAnnotationWriter::~SourceLineAssemblyAnnotationWriter() in SourceLineAnnotator.o
“llvm::Pass::releaseMemory()”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::dumpPassStructure(unsigned int)”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::getAsImmutablePass()”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::getAsPMDataManager()”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::preparePassManager(llvm::PMStack&)”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::getAdjustedAnalysisPointer(void const*)”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::outs()”, referenced from:
cs380c::SourceLineAnnotator::runOnModule(llvm::Module&) in SourceLineAnnotator.o
“llvm::ModulePass::createPrinterPass(llvm::raw_ostream&, std::__1::basic_string<char, std::__1::char_traits, std::__1::allocator > const&) const”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::ModulePass::getPotentialPassManagerType() const”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Instruction::getMetadataImpl(llvm::StringRef) const”, referenced from:
llvm::Instruction::getMetadata(llvm::StringRef) const in SourceLineAnnotator.o
“llvm::Pass::getPassName() const”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::verifyAnalysis() const”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Pass::print(llvm::raw_ostream&, llvm::Module const*) const”, referenced from:
vtable for cs380c::SourceLineAnnotator in SourceLineAnnotator.o
“llvm::Module::print(llvm::raw_ostream&, llvm::AssemblyAnnotationWriter*) const”, referenced from:
cs380c::SourceLineAnnotator::runOnModule(llvm::Module&) in SourceLineAnnotator.o
“vtable for llvm::ModulePass”, referenced from:
llvm::ModulePass::ModulePass(char&) in SourceLineAnnotator.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
“vtable for llvm::AssemblyAnnotationWriter”, referenced from:
llvm::AssemblyAnnotationWriter::AssemblyAnnotationWriter() in SourceLineAnnotator.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
“vtable for llvm::Pass”, referenced from:
llvm::Pass::Pass(llvm::PassKind, char&) in SourceLineAnnotator.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [annotate.so] Error 1

Eventually, I discovered the .so file could be successfully compiled as follows:

$ c++ SourceLineAnnotator.o -shared /usr/local/bin/llvm-config --ldflags --libs --system-libs -o annotate.so

By adding the flags specified, I can now compile the pass to a .so file. However, when I attempt to load it with opt, I get another type of error (also related to linking from what I can tell):

$ opt -load annotate.so -annotate <test.bc>/dev/null

opt: CommandLine Error: Option ‘print-before-all’ registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options

I’m quite stuck. I have fought with linker errors for weeks now and I’m not sure what to try. Any help would be greatly appreciated.

Andrew Selvia

I want to create LLVM passes on OS X Yosemite. First, I built LLVM as such (based on http://llvm.org/docs/GettingStarted.html and trial & error):

...
$ mkdir build && cd build
$ CC=clang CXX="clang++ -stdlib=libc++" ../llvm/configure --enable-libcpp --enable-shared
$ make
$ make install

Then, I tested it with the following command. It worked!

$ opt -load /usr/local/lib/LLVMHello.dylib -hello <test.bc>/dev/null

However, when attempting to build my own pass in OS X Yosemite, I ran into confusing linking problems:

$ c++ $(CXXFLAGS) SourceLineAnnotator.cpp -c -o SourceLineAnnotator.o
$ c++ SourceLineAnnotator.o -shared -o annotate.so

I have no trouble building my passes with the following commands:

$> /usr/bin/c++ $CPPFLAGS -std=c++11 -fno-rtti -fPIC -fno-exceptions -fno-rtti -o my.o -c my.cpp
$> /usr/bin/c++ -std=c++11 -fno-rtti -fPIC -std=c++11 -bundle -Wl,-headerpad_max_install_names -Wl,-dead_strip -Wl,-flat_namespace -Wl,-undefined -Wl,suppress -o my.dylib my.o

This command was generated by cmake thanks to the LLVM config...

[...]

Eventually, I discovered the .so file could be successfully compiled as follows:

$ c++ SourceLineAnnotator.o -shared `/usr/local/bin/llvm-config --ldflags --libs --system-libs` -o annotate.so

By adding the flags specified, I can now compile the pass to a .so file. However, when I attempt to load it with opt, I get another type of error (also related to linking from what I can tell):

$ opt -load annotate.so -annotate <test.bc>/dev/null

opt: CommandLine Error: Option 'print-before-all' registered more than once!
LLVM ERROR: inconsistency in registered CommandLine options

You get this error because you're linking statically with some LLVM core
libs (from the /usr/local/bin/llvm-config --ldflags --libs --system-libs). They have static conbstructors that register options, and those have already been registered when liked within opt.