2
votes

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"
1
That's not CMake complaining, but the linker. What does your code look like? Demangling the symbol, it seems to be a missing vtable: vtable for (anonymous namespace)::Hydrogen - Dan Mašek
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
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 of class Hydrogen. Hard to tell without actually seeing the code. - Dan Mašek
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
@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 your answer, which automatically means that you solve the problem. Note, that the question should contain original code (with problem) in any case. - Tsyvarev

1 Answers

1
votes

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"