We can’t install software into the /usr tree at my office, so I end up having local installs of lots of software. Some things, like GODI, play well with this. I had some trouble finding the right way to get LLVM‘s Ocaml bindings to work, so I figured I’d share the wealth. The following instructions will put an install into the directory $PREFIX/llvm-install.
Here are the steps; they’re followed by a plain English explanation.
cd $PREFIX
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
wget http://llvm.org/releases/2.5/llvm-gcc4.2-2.5-x86-linux-RHEL4.tar.gz
tar xzf llvm-gcc4.2-2.5-x86-linux-RHEL4.tar.gz
mkdir llvm-objects llvm-install
cd llvm-objects
../llvm/configure --with-llvmgccdir=$PREFIX/llvm-gcc4.2-2.5-x86-linux-RHEL4 --enable-optimized --enable-jit --prefix=$PREFIX/llvm-install --with-ocaml-libdir=$GODI_PATH/lib/ocaml/std-lib
make
make install
My PREFIX is my home directory, and GODI_PATH = ~/godi. First, we checkout the latest LLVM from SVN (step 2). Then we download and extract the latest release (2.5, as of writing) of LLVM-gcc (steps 3 and 4). (I couldn’t get the SVN version of LLVM-gcc to work with the SVN version of LLVM.) Notably, LLVM does not support in-place builds, so we create the llvm-objects directory to actually build LLVM; we’ll install it into llvm-install (step 5). We configure the software from the llvm-objects directory (steps 6 and 7). The long configure is necessary; the only optional item is --enable-jit. You may have to adjust your --with-ocaml-libdir to point to wherever your Ocaml libraries live. Then make and make install (steps 8 and 9). Voila!
To test it out, we can use the “Hello, World!” program written by Gordon Henrikson. I had to change it a little to bring it up to date with the latest APIs (in particular, the global context had to be added). You can download it as llvm_test.ml.
open Printf
open Llvm
let main filename =
let c = create_context () in
let i8_t = i8_type c in
let i32_t = i32_type c in
let m = create_module c filename in
(* @greeting = global [14 x i8] c"Hello, world!\00" *)
let greeting =
define_global "greeting" (const_string c "Hello, world!\000") m in
(* declare i32 @puts(i8* ) *)
let puts =
declare_function "puts"
(function_type i32_t [|pointer_type i8_t|]) m in
(* define i32 @main() { entry: *)
let main = define_function "main" (function_type i32_t [| |]) m in
let at_entry = builder_at_end c (entry_block main) in
(* %tmp = getelementptr [14 x i8]* @greeting, i32 0, i32 0 *)
let zero = const_int i32_t 0 in
let str = build_gep greeting [| zero; zero |] "tmp" at_entry in
(* call i32 @puts( i8* %tmp ) *)
ignore (build_call puts [| str |] "" at_entry);
(* ret void *)
ignore (build_ret (const_null i32_t) at_entry);
(* write the module to a file *)
if not (Llvm_bitwriter.write_bitcode_file m filename) then exit 1;
dispose_module m
let () = match Sys.argv with
| [|_; filename|] -> main filename
| _ -> main "a.out"
Now we can compile:
ocamlopt -cc g++ llvm.cmxa llvm_bitwriter.cmxa llvm_test.ml -o llvm_test
./llvm_test hello.bc # generates bitcode
$PREFIX/llvm-install/bin/llvm-dis hello.bc # disassembles bitcode into hello.ll
$PREFIX/llvm-install/bin/lli hello.bc # outputs "Hello, world!"
If interpretation via lli isn’t your bag, you can also compile to native code:
$PREFIX/llvm-install/bin/llc hello.bc # generates assembly, hello.s
gcc -o hello hello.s
./hello # outputs "Hello, world!"