2

I've been struggling with this for longer than I care to admit and would really appreciate some help.

I'm trying to do a project which involves building a linker and scheduler, and thought if I could use some of the functionality that's already been build into LLVM that would be great. I'm using LLVM 10. To get started I did some reading and tried to build this example. Because I plan on embedding LLVM into another project, used this as a reference for 'how to build' the example (see below). I figured the dependencies are just the components from the example CMakeLists.txt.

If I'm not mistaken, I'm getting a linker error and that the component list is the problem, but I'm struggling to resolve it. The way it seems LLVM does linking is by mapping a component name to an library file, but since I don't know which missing library might be causing it I'm stuck. Also, I don't know what llvm_libs is, but adding it to the component list seemed to resolve some of the linker errors I was getting originally. Also also, changing the order of the component list will give me different amounts of errors, which absolutely confounds me.

CMakeLists.txt

cmake_minimum_required(VERSION 3.13.4)
project(HowToUseJIT)

find_package(LLVM REQUIRED CONFIG)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

# Set your project compile flags.
# E.g. if using the C++ header files
# you will need to enable C++11 support
# for your compiler.

message(STATUS "INCLUDE ${LLVM_INCLUDE_DIRS}")
include_directories(${LLVM_INCLUDE_DIRS})

message(STATUS "DEFINITIONS ${LLVM_DEFINITIONS}\n${LLVM_DEFINITIONS_LIST}")
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})

# Now build our tools
add_executable(HowToUseJIT HowToUseJIT.cpp)

# Find the libraries that correspond to the LLVM components
# that we wish to use
llvm_map_components_to_libnames(llvm_libs support core interpreter nativecodegen executionengine)

# Link against LLVM libraries
message(STATUS "LIBS ${llvm_libs}")
target_link_libraries(HowToUseJIT ${llvm_libs})

Then from a subdir I run

$ cmake ../
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jeremy_arsenault/Documents/random/llvm_examples/HowToUseJIT/build
$ cmake --build .
[ 50%] Building CXX object CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o
[100%] Linking CXX executable HowToUseJIT
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `main':
HowToUseJIT.cpp:(.text+0x4b7): undefined reference to `llvm::EngineBuilder::EngineBuilder(std::unique_ptr<llvm::Module, std::default_delete<llvm::Module> >)'
/usr/bin/ld: HowToUseJIT.cpp:(.text+0x4dc): undefined reference to `llvm::EngineBuilder::~EngineBuilder()'
/usr/bin/ld: HowToUseJIT.cpp:(.text+0x693): undefined reference to `llvm::EngineBuilder::~EngineBuilder()'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::EngineBuilder::create()':
HowToUseJIT.cpp:(.text._ZN4llvm13EngineBuilder6createEv[_ZN4llvm13EngineBuilder6createEv]+0x18): undefined reference to `llvm::EngineBuilder::selectTarget()'
/usr/bin/ld: HowToUseJIT.cpp:(.text._ZN4llvm13EngineBuilder6createEv[_ZN4llvm13EngineBuilder6createEv]+0x2a): undefined reference to `llvm::EngineBuilder::create(llvm::TargetMachine*)'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::IRBuilderDefaultInserter::IRBuilderDefaultInserter()':
HowToUseJIT.cpp:(.text._ZN4llvm24IRBuilderDefaultInserterC2Ev[_ZN4llvm24IRBuilderDefaultInserterC5Ev]+0xf): undefined reference to `vtable for llvm::IRBuilderDefaultInserter'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::InitializeNativeTarget()':
HowToUseJIT.cpp:(.text._ZN4llvm22InitializeNativeTargetEv[_ZN4llvm22InitializeNativeTargetEv]+0x9): undefined reference to `LLVMInitializeX86TargetInfo'
/usr/bin/ld: HowToUseJIT.cpp:(.text._ZN4llvm22InitializeNativeTargetEv[_ZN4llvm22InitializeNativeTargetEv]+0xe): undefined reference to `LLVMInitializeX86Target'
/usr/bin/ld: HowToUseJIT.cpp:(.text._ZN4llvm22InitializeNativeTargetEv[_ZN4llvm22InitializeNativeTargetEv]+0x13): undefined reference to `LLVMInitializeX86TargetMC'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>::~IRBuilder()':
HowToUseJIT.cpp:(.text._ZN4llvm9IRBuilderINS_14ConstantFolderENS_24IRBuilderDefaultInserterEED2Ev[_ZN4llvm9IRBuilderINS_14ConstantFolderENS_24IRBuilderDefaultInserterEED5Ev]+0x1c): undefined reference to `llvm::IRBuilderDefaultInserter::~IRBuilderDefaultInserter()'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::IRBuilderFolder::IRBuilderFolder()':
HowToUseJIT.cpp:(.text._ZN4llvm15IRBuilderFolderC2Ev[_ZN4llvm15IRBuilderFolderC5Ev]+0xf): undefined reference to `vtable for llvm::IRBuilderFolder'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::ConstantFolder::ConstantFolder()':
HowToUseJIT.cpp:(.text._ZN4llvm14ConstantFolderC2Ev[_ZN4llvm14ConstantFolderC5Ev]+0x1f): undefined reference to `vtable for llvm::ConstantFolder'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>::IRBuilder(llvm::BasicBlock*, llvm::MDNode*, llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value*> >)':
HowToUseJIT.cpp:(.text._ZN4llvm9IRBuilderINS_14ConstantFolderENS_24IRBuilderDefaultInserterEEC2EPNS_10BasicBlockEPNS_6MDNodeENS_8ArrayRefINS_17OperandBundleDefTIPNS_5ValueEEEEE[_ZN4llvm9IRBuilderINS_14ConstantFolderENS_24IRBuilderDefaultInserterEEC5EPNS_10BasicBlockEPNS_6MDNodeENS_8ArrayRefINS_17OperandBundleDefTIPNS_5ValueEEEEE]+0xbb): undefined reference to `llvm::IRBuilderDefaultInserter::~IRBuilderDefaultInserter()'
/usr/bin/ld: CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o: in function `llvm::ConstantFolder::~ConstantFolder()':
HowToUseJIT.cpp:(.text._ZN4llvm14ConstantFolderD2Ev[_ZN4llvm14ConstantFolderD5Ev]+0x13): undefined reference to `vtable for llvm::ConstantFolder'
/usr/bin/ld: HowToUseJIT.cpp:(.text._ZN4llvm14ConstantFolderD2Ev[_ZN4llvm14ConstantFolderD5Ev]+0x26): undefined reference to `llvm::IRBuilderFolder::~IRBuilderFolder()'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/HowToUseJIT.dir/build.make:91: HowToUseJIT] Error 1
make[1]: *** [CMakeFiles/Makefile2:77: CMakeFiles/HowToUseJIT.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

If anyone knows what my problem is, has any advice on running these LLVM examples, or knows of any resources that might better my understanding of wtf is happening I will be eternally grateful :). Thanks in advance for any help!

Edit 1: I tried the same procedure on some other examples to see what would happen. On Fibonacci everything build fine then seg faulted on runtime. On ModuleMaker I build fails on undefined reference to main... I'm really bungling something up here I just don't know what.

Edit 2: Thank you for the responses. I'm currently attempting to get everything to build correctly using Alexs advice. Simply using the CMakeLists.txt and building using Ninja did not work :( (I updated the build process outputs above). I was getting similar errors as before. Since Alex mentioned that he needed to use a different version of llvm header files, I figured I'd just build an updated version from source - but LLVM bested me once again. The build from source procedure in the README bombs on every release version I try (I'm running Ubuntu 20.04 lts). I'm starting to think my best bet is to just cherry-pick files and hack something together myself because this is getting to be too much of a headache.

Edit 3: I got it working :)

Solution


Everything ran and built fine when I updated to the newest version of LLVM. I ran into a lot of build problems on Ubuntu 20.04 lts that were a product of missing dependencies. This kind soul posted all the deps he needed to install in order to build llvm without errors.

1
  • 1
    Can you show the CMake configure output? Also, can you tell us which compiler you're using, how you acquired (or built) LLVM, and what the values of the variables LLVM_ENABLE_RTTI and LLVM_ENABLE_EH are? Commented Jan 25, 2022 at 4:43

1 Answer 1

2

So the following build worked for me and should hopefully be a model for you re: how to use CMake...

cmake_minimum_required(VERSION 3.22)
project(test)

# Find LLVM and the components we require.
find_package(LLVM 10 REQUIRED)
llvm_map_components_to_libnames(
  LLVM_LIBRARIES
  Core
  ExecutionEngine
  Interpreter
  MC
  MCJIT
  Support
  nativecodegen
)

# Create a wrapper for the LLVM components we need in this
# project. This will allow us to link it to multiple targets
# without duplicating a lot of code. It's too bad that LLVM
# doesn't provide anything like this.
add_library(test::LLVM INTERFACE IMPORTED)
target_include_directories(test::LLVM INTERFACE ${LLVM_INCLUDE_DIRS})
target_compile_definitions(test::LLVM INTERFACE ${LLVM_DEFINITIONS})
target_link_libraries(test::LLVM INTERFACE ${LLVM_LIBRARIES})

# Create our actual executable and link LLVM to it.
add_executable(HowToUseJIT HowToUseJIT.cpp)
target_link_libraries(HowToUseJIT PRIVATE test::LLVM)

Notice the following:

  1. LLVM does not provide its own imported targets (bad)
  2. We therefore create our own imported target to wrap it, test::LLVM.
  3. We add the MC and MCJIT components to the list of components.
  4. We assign the package-provided variables and computed list of libraries to the relevant properties of our imported target.
  5. We always call target_link_libraries with a visibility specifier (they are PRIVATE, INTERFACE, and PUBLIC. Omitting it is none of the above.)
  6. We state the version number of LLVM we require in the find_package call and omit the unnecessary CONFIG argument. Every major version of LLVM breaks the API in significant ways.

At the terminal, I now see:

$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release
-- The C compiler identification is GNU 9.3.0
-- The CXX compiler identification is GNU 9.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /path/to/build
$ cmake --build build/ --verbose
[1/2] /usr/bin/c++ -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -isystem /usr/lib/llvm-10/include -O3 -DNDEBUG -MD -MT CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o -MF CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o.d -o CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o -c /path/to/HowToUseJIT.cpp
[2/2] : && /usr/bin/c++ -O3 -DNDEBUG  CMakeFiles/HowToUseJIT.dir/HowToUseJIT.cpp.o -o HowToUseJIT  /usr/lib/llvm-10/lib/libLLVMInterpreter.a  /usr/lib/x86_64-linux-gnu/libffi.so  /usr/lib/llvm-10/lib/libLLVMMCJIT.a  /usr/lib/llvm-10/lib/libLLVMExecutionEngine.a  /usr/lib/llvm-10/lib/libLLVMRuntimeDyld.a  /usr/lib/llvm-10/lib/libLLVMX86CodeGen.a  /usr/lib/llvm-10/lib/libLLVMAsmPrinter.a  /usr/lib/llvm-10/lib/libLLVMDebugInfoDWARF.a  /usr/lib/llvm-10/lib/libLLVMCFGuard.a  /usr/lib/llvm-10/lib/libLLVMGlobalISel.a  /usr/lib/llvm-10/lib/libLLVMSelectionDAG.a  /usr/lib/llvm-10/lib/libLLVMCodeGen.a  /usr/lib/llvm-10/lib/libLLVMTarget.a  /usr/lib/llvm-10/lib/libLLVMBitWriter.a  /usr/lib/llvm-10/lib/libLLVMScalarOpts.a  /usr/lib/llvm-10/lib/libLLVMAggressiveInstCombine.a  /usr/lib/llvm-10/lib/libLLVMInstCombine.a  /usr/lib/llvm-10/lib/libLLVMTransformUtils.a  /usr/lib/llvm-10/lib/libLLVMAnalysis.a  /usr/lib/llvm-10/lib/libLLVMProfileData.a  /usr/lib/llvm-10/lib/libLLVMX86Desc.a  /usr/lib/llvm-10/lib/libLLVMObject.a  /usr/lib/llvm-10/lib/libLLVMBitReader.a  /usr/lib/llvm-10/lib/libLLVMCore.a  /usr/lib/llvm-10/lib/libLLVMRemarks.a  /usr/lib/llvm-10/lib/libLLVMBitstreamReader.a  /usr/lib/llvm-10/lib/libLLVMMCParser.a  /usr/lib/llvm-10/lib/libLLVMTextAPI.a  /usr/lib/llvm-10/lib/libLLVMX86Utils.a  /usr/lib/llvm-10/lib/libLLVMMCDisassembler.a  /usr/lib/llvm-10/lib/libLLVMMC.a  /usr/lib/llvm-10/lib/libLLVMBinaryFormat.a  /usr/lib/llvm-10/lib/libLLVMDebugInfoCodeView.a  /usr/lib/llvm-10/lib/libLLVMDebugInfoMSF.a  /usr/lib/llvm-10/lib/libLLVMX86Info.a  /usr/lib/llvm-10/lib/libLLVMSupport.a  -lz  -lrt  -ldl  -ltinfo  -lpthread  -lm  /usr/lib/llvm-10/lib/libLLVMDemangle.a && :
$ ./build/HowToUseJIT 
We just constructed this LLVM module:

; ModuleID = 'test'
source_filename = "test"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"

define i32 @add1(i32 %AnArg) {
EntryBlock:
  %0 = add i32 1, %AnArg
  ret i32 %0
}

define i32 @foo() {
EntryBlock:
  %0 = tail call i32 @add1(i32 10)
  ret i32 %0
}


Running foo: Result: 11

Note: I had to use the sources for HowToUseJIT from a more recent LLVM release (the one from 13.0.0) because the old one has a segfault on some systems. However, that bug is unrelated to the build process.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.