LLVM Cmake module?

I need to connect up some code written in C to link with LLVM. Since LLVM itself uses CMake, is there a standard CMake module to find and use the LLVM libraries?

Eli Gottlieb <eligottlieb@gmail.com> writes:

The two lines

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${LLVM_ROOT}/share/llvm/cmake")
include(LLVM)

don't seem to work. I'm checking with installing LLVM from source to
see if that makes it work, but the LLVM install from the Ubuntu repos
doesn't seem to have a /usr/share/llvm directory at all.

I'm certain that the LLVM distributed with Ubuntu was built with the
config&make procedure, so it is expected that it lacks CMake-related
features.

Like I said, checking with a hand-compiled installation to see if this
is a problem with that CMakeLists code, with LLVM, or with Ubuntu.

You are assigning to the LLVM_ROOT variable the root install directory
of LLVM, aren't you?

Please show the exact sequence of commands you used for building &
installing LLVM, the relevant part of your project's CMakeLists.txt and
the cmake command you used for configuring your project.

[Please CC the mailing list]

Eli Gottlieb <eligottlieb@gmail.com> writes:

OK, I'm just going to paste in my CMakeLists.txt file. Like I said,
I'm building an LLVM install myself by untarring llvm, mkdir build in
the root dir of the source, cd build/, cmake .., make.

cmake_minimum_required (VERSION 2.6)
project (libjllvm)
add_library(jllvm Analysis_wrap.c BitReader_wrap.c BitWriter_wrap.c
Core_wrap.c EnhancedDisassembly_wrap.c ExecutionEngine_wrap.c
LinkTimeOptimizer_wrap.c lto_wrap.c Target_wrap.c
Transforms/IPO_wrap.c Transforms/Scalar_wrap.c)

# A convenience variable:
set(LLVM_ROOT "/usr" CACHE /usr/ "Root of LLVM install.")
# A bit of a sanity check:
if( NOT EXISTS ${LLVM_ROOT}/include/llvm )
message(FATAL_ERROR "LLVM_ROOT (${LLVM_ROOT}) is not a valid LLVM
install")
endif()

# We incorporate the CMake features provided by LLVM:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${LLVM_ROOT}/share/llvm/cmake")
include(LLVM)
# Now set the header and library paths:
include_directories( ${LLVM_ROOT}/include )
link_directories( ${LLVM_ROOT}/lib )
# Let's suppose we want to build a JIT compiler with support for
# binary code (no interpreter):
llvm_map_components_to_libraries(REQ_LLVM_LIBRARIES jit native core)
# Finally, we link the LLVM libraries to our executable:
target_link_libraries(jllvm ${REQ_LLVM_LIBRARIES})

Where is the failure? On the "if( NOT EXISTS ${LLVM_ROOT}/include/llvm )" ?

If that's the problem, is LLVM installed on /usr ? On my Kubuntu machine
CMAKE_INSTALL_PREFIX defaults to /usr/local.

Please describe exactly the problem, pasting error messages if
necessary.

I compiled and installed it to the prefix /usr, but that's not the issue. Once I actually compile and install LLVM with CMake by hand, I get the share/llvm/cmake stuff installed correctly (can those files be included in "normal" builds, or will LLVM switch to CMake as its primary build system?). Now I'm running into the problem of cflags or includes or something not being set properly.

CMakeLists.txt:

cmake_minimum_required (VERSION 2.6)
project (libjllvm)
add_library(jllvm Analysis_wrap.c BitReader_wrap.c BitWriter_wrap.c Core_wrap.c EnhancedDisassembly_wrap.c ExecutionEngine_wrap.c LinkTimeOptimizer_wrap.c lto_wrap.c Target_wrap.c Transforms/IPO_wrap.c Transforms/Scalar_wrap.c)

# A convenience variable:
set(LLVM_ROOT "/usr" CACHE /usr/ "Root of LLVM install.")
# A bit of a sanity check:
if( NOT EXISTS ${LLVM_ROOT}/include/llvm )
message(FATAL_ERROR "LLVM_ROOT (${LLVM_ROOT}) is not a valid LLVM install")
endif()
# We incorporate the CMake features provided by LLVM:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LLVM_ROOT}/share/llvm/cmake")
include(LLVM)
# Now set the header and library paths:
include_directories( ${LLVM_ROOT}/include )
link_directories( ${LLVM_ROOT}/lib )
# Make sure to include the headers required for Java and JNI.
FIND_PACKAGE(Java REQUIRED)
FIND_PACKAGE(JNI REQUIRED)
INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH})
INCLUDE_DIRECTORIES(${JAVA_INCLUDE_PATH2})
# Let's suppose we want to build a JIT compiler with support for
# binary code (no interpreter):
llvm_map_components_to_libraries(REQ_LLVM_LIBRARIES jit native core)
# Finally, we link the LLVM libraries to our executable:
target_link_libraries(jllvm ${REQ_LLVM_LIBRARIES})

I run "cmake ." where I've got my source and then make. This results in:

eli@eli-netbook:~/Programs/decac/src/jllvm/llvm$ make
Scanning dependencies of target jllvm
[ 9%] Building C object CMakeFiles/jllvm.dir/Analysis_wrap.c.o
In file included from /usr/include/llvm-c/Core.h:36,
                 from /usr/include/llvm-c/Analysis.h:22,
                 from /home/eli/Programs/decac/src/jllvm/llvm/Analysis_wrap.c:190:
/usr/include/llvm/System/DataTypes.h:46: error: #error "Must #define __STDC_LIMIT_MACROS before #including System/DataTypes.h"
/usr/include/llvm/System/DataTypes.h:50: error: #error "Must #define __STDC_CONSTANT_MACROS before " "#including System/DataTypes.h"
make[2]: *** [CMakeFiles/jllvm.dir/Analysis_wrap.c.o] Error 1
make[1]: *** [CMakeFiles/jllvm.dir/all] Error 2
make: *** [all] Error 2

Thanks for all your help,
Eli

Eli Gottlieb <eligottlieb@gmail.com> writes:

I compiled and installed it to the prefix /usr, but that's not the
issue. Once I actually compile and install LLVM with CMake by hand, I
get the share/llvm/cmake stuff installed correctly (can those files be
included in "normal" builds, or will LLVM switch to CMake as its
primary build system?). Now I'm running into the problem of cflags or
includes or something not being set properly.

[snip]

[ 9%] Building C object CMakeFiles/jllvm.dir/Analysis_wrap.c.o
In file included from /usr/include/llvm-c/Core.h:36,
                 from /usr/include/llvm-c/Analysis.h:22,
                 from
/home/eli/Programs/decac/src/jllvm/llvm/Analysis_wrap.c:190:
/usr/include/llvm/System/DataTypes.h:46: error: #error "Must #define
__STDC_LIMIT_MACROS before #including System/DataTypes.h"
/usr/include/llvm/System/DataTypes.h:50: error: #error "Must #define
__STDC_CONSTANT_MACROS before " "#including System/DataTypes.h"
make[2]: *** [CMakeFiles/jllvm.dir/Analysis_wrap.c.o] Error 1
make[1]: *** [CMakeFiles/jllvm.dir/all] Error 2
make: *** [all] Error 2

Yes, you must define __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS on
your CMakeLists.txt. Put this before any add_executable/add_library that
contains source files that uses LLVM stuff:

add_definitions( -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS )

Works now, thank you.

After I actually get everything compiling, install the library, and load it from my Java program, I get the following:

Exception in thread "main" java.lang.UnsatisfiedLinkError: /usr/lib/libjllvm.so: /usr/lib/libjllvm.so: undefined symbol: _ZTVN10__cxxabiv120__si_class_type_infoE

If I have to guess, this means that the CMake stuff given is linking to the C++ libraries of LLVM when I wanted them linking to the C bindings. Any ideas? I definitely included the headers for the C bindings only.

Oh, and I've definitely configured CMake to compile everything as C.

project(jllvm C)

[Please don't top-post.]

Eli Gottlieb <eligottlieb@gmail.com> writes:

After I actually get everything compiling, install the library, and
load it from my Java program, I get the following:

Exception in thread "main" java.lang.UnsatisfiedLinkError:
/usr/lib/libjllvm.so: /usr/lib/libjllvm.so: undefined symbol:
_ZTVN10__cxxabiv120__si_class_type_infoE

If I have to guess, this means that the CMake stuff given is linking
to the C++ libraries of LLVM when I wanted them linking to the C
bindings. Any ideas? I definitely included the headers for the C
bindings only.

The error is about missing RTTI support (C++ runtime type
information). The C bindings are just a layer around the C++ LLVM
libraries. More specifically, the LLVM libraries must be linked to the
C++ runtime to work. So use g++ for linking or pass the C++ runtime
libraries on the link command (stdc++ and maybe some other).

Eli Gottlieb <eligottlieb@gmail.com> writes:

So you're saying that the default CMake build of LLVM creates static
libraries that got linked into my shared-object and now require me to
link in everything they require myself? Shouldn't the linker be able
to track down C++ runtime for this?

You told CMake to manage your shared library as if it were a pure C
application, which isn't (because it links to static LLVM libraries.)
The linker is doing what you requested: link a C executable.

So either you add the required C++ libraries yourself, or link the
shared library as a C++ executable.

So... couldn't I just tell it to compile LLVM as shared libraries instead of static?

Eli Gottlieb <eligottlieb@gmail.com> writes:

So either you add the required C++ libraries yourself, or link the
shared library as a C++ executable.

So... couldn't I just tell it to compile LLVM as shared libraries
instead of static?

Yes, although that configuration is not as well tested as the static one.

(pass -DBUILD_SHARED_LIBS=ON to cmake before building LLVM. Be sure to
remove the LLVM files you previously installed before installing the new
build)

IMO linking your shared library as a C++ application is the easier path:

set_target_properties(your-shared-object PROPERTIES LINKER_LANGUAGE CXX)

Well, now I've got another problem. When I actually connect things up to *use* the binding library I built, I run into an unresolved symbol error with respect to the function LLVMWriteBitcodeToFile().

The assembly dump showing that my library does have that function follows:

eli@eli-netbook:~/Programs/decac$ objdump -d src/jllvm/llvm/libjllvm.so | grep LLVMWriteBitcodeToFile
0055cd54 <LLVMWriteBitcodeToFileHandle@plt>:
0058c504 <LLVMWriteBitcodeToFile@plt>:
0059b577 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFile>:
  59b5bd: 74 32 je 59b5f1 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFile+0x7a>
  59b5e8: 75 07 jne 59b5f1 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFile+0x7a>
  59b5ef: eb 45 jmp 59b636 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFile+0xbf>
  59b5fe: e8 01 0f ff ff call 58c504 <LLVMWriteBitcodeToFile@plt>
  59b610: 74 21 je 59b633 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFile+0xbc>
0059b6b4 <Java_jllvm_llvm_BitWriterJNI_LLVMWriteBitcodeToFileHandle>:
  59b6fb: e8 54 16 fc ff call 55cd54 <LLVMWriteBitcodeToFileHandle@plt>

Attempting to actually use the library, however, results in:

java: symbol lookup error: /usr/lib/libjllvm.so: undefined symbol: LLVMWriteBitcodeToFile

I am not at all sure what @plt is, nor why linking to LLVM apparently fails to link to LLVM.

Thanks for your help,
Eli