2

I am trying to create an LLVM Pass with two source files, but when I compile, cmake yells at me with:

[1/1] Linking CXX shared module lib/LLVMHydrogen.so
FAILED: : && /usr/bin/c++  -fPIC -fPIC -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long -Wno-maybe-uninitialized -Wdelete-non-virtual-dtor -Wno-comment -std=c++11 -fPIC -g   -shared -Wl,-soname,LLVMHydrogen.so -o lib/LLVMHydrogen.so lib/Transforms/Hydrogen/CMakeFiles/LLVMHydrogen.dir/Hydrogen.cpp.o lib/Transforms/Hydrogen/CMakeFiles/LLVMHydrogen.dir/conditional_blocks.cpp.o  -Wl,-rpath,"\$ORIGIN/../lib" && :
/usr/bin/ld: lib/Transforms/Hydrogen/CMakeFiles/LLVMHydrogen.dir/conditional_blocks.cpp.o: relocation R_X86_64_PC32 against undefined symbol `_ZTVN12_GLOBAL__N_18HydrogenE' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value

The key point being:

relocation R_X86_64_PC32 against undefined symbol `_ZTVN12_GLOBAL__N_18HydrogenE' can not be used when making a shared object; recompile with -fPIC

I tried add -fPIC to my compilation flags (and link flags for good measure), but nothing helped. This is my CMakeLists.txt:

SET(COMPILE_FLAGS "-fPIC")
SET(LINK_FLAGS    "-lPIC")

SET( CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS}" )
SET( CMAKE_EXE_LINKER_FLAGS  "${CMAKE_EXE_LINKER_FLAGS} ${LINK_FLAGS}" )

add_llvm_loadable_module( LLVMHydrogen
  Hydrogen.cpp
  conditional_blocks.cpp

  DEPENDS
  intrinsics_gen
)

But I get the same output. What am I doing wrong? I feel using multiple source files should be exceedingly simple :/

Thanks

Source code:

hydrogen.h:

#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

using namespace std;
using namespace llvm;

namespace {
    struct Hydrogen : public FunctionPass {

    static char ID; // Pass identification, replacement for typeid
    Hydrogen() : FunctionPass(ID) {}

    bool runOnFunction(Function &f) override;
    void getAnalysisUsage(AnalysisUsage &AU) const override {
        AU.setPreservesAll();       
    }
    };
}

static const char h_name[] = "Hydrogen pass";
char Hydrogen::ID = 0;
static RegisterPass<Hydrogen> X("Hydrogen", "Hydrogen Pass");

hydrogen.cpp: (The first 'main' file)

#include "hydrogen.h"

bool Hydrogen::runOnFunction(Function &fun)
{
        return true;
}

conditional_blocks.cpp: (The second file)

#include "hydrogen.h"
tdwyer
  • 79
  • 5
  • That's not CMake complaining, but the linker. What does your code look like? [Demangling](http://demangler.com/) the symbol, it seems to be a missing vtable: `vtable for (anonymous namespace)::Hydrogen` – Dan Mašek Apr 11 '16 at 00:40
  • Currently there is no actual code in the second file (conditional_blocks.cpp) besides inclusion of the header file. The first file has just a basic function pass in it. Nothing special. – tdwyer Apr 11 '16 at 00:59
  • I wrote "show", not "describe briefly", so we don't need to guess. For what it's worth, you probably [don't have a body on a virtual destructor](http://stackoverflow.com/questions/3065154/undefined-reference-to-vtable) of class `Hydrogen`. Hard to tell without actually seeing the code. – Dan Mašek Apr 11 '16 at 01:48
  • I updated the post to include all relevant files (reduced down a bit). Also, I am building with Ninja if that makes any difference. – tdwyer Apr 11 '16 at 02:03
  • That anonymous namespace for a class that you want to use in multiple compilation units, plus the way `bool Hydrogen::runOnFunction(Function &fun)` is defined outside... that looks suspicious. What if you use a regular namespace instead? – Dan Mašek Apr 11 '16 at 02:18
  • Ok, I believe you were correct with either the namespace, or the virtual functions, .. or both. I made a couple changes and now it seems to work :D Thank you @DanMašek :) – tdwyer Apr 11 '16 at 02:27
  • 2
    @tdwyer: On Stack Overflow we don't use SOLVED mark in the question's title or body. Instead, create an **answer** post and describe solution there. Then you may [accept](http://stackoverflow.com/help/accepted-answer) your answer, which automatically means that you solve the problem. Note, that the question should contain original code (*with problem*) in any case. – Tsyvarev Apr 11 '16 at 08:09

1 Answers1

1

Changing the code into the following fixed the problem. I believe it was the addition of the "virtual" keywords in the header, along with the inclusion of "virtual ~Hydrogen() { }"

Working source with multiple LLVM source files:

Same CMakeLists.txt as posted in question.

hydrogen.h:

#include ....

using namespace std;
using namespace llvm;

struct Hydrogen : public FunctionPass {

    static char ID; // Pass identification, replacement for typeid
    Hydrogen() : FunctionPass(ID) {}

    virtual ~Hydrogen() { }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
        AU.setPreservesAll();       
    }

    virtual bool runOnFunction(Function &f) override;
};

hydrogen.cpp:

#include "hydrogen.h"

using namespace hydrogen_ns;

static const char h_name[] = "Hydrogen pass";
char Hydrogen::ID = 0;
static RegisterPass<Hydrogen> X("Hydrogen", "Hydrogen Pass");

bool Hydrogen::runOnFunction(Function &fun)
{
        return true;
}

conditional_blocks.cpp:

#include "hydrogen.h"
tdwyer
  • 79
  • 5