In this post I'll show you how to download, install and use clang on Windows. Ok but, what is clang in a first place? clang is compiler front-end for C, C++ and Objective-C languages. Front-end means that it takes source code and turns it into IR. IR stands for Intermediate Representation and it's sort of byte-code that will be optimized and converted into actual machine code (e.g. .exe file) for specific platform by LLVM - the compiler back-end. IR is also assembly-like language which's files have .ll extension. clang is also a name of terminal command that we'll use to compile examples.
So basically it goes like this: source code > clang > IR > LLVM > exe
Downloading and installing
In order to install anything you have to download it first. So do this:
1 Go to http://releases.llvm.org and click donwload link on the left at the top of the list. This will move you to donwload website for that version of clang.
2 Under Pre-Built Binaries, find Clang for Windows. In my case, I used Clang for Windows (64-bit). And click it. It's downloading LLVM-4.0.0-win64.exe file.
3 Run this file and remember to set select option Add LLVM to the system PATH for all users.
4 Restart computer. Sometimes terminal do not take new PATH variable.
5 After installation, open terminal and type clang. You should see clang.exe: error: no input files. It means that clang is installed and ready to work with.
Let's make some code
Next step is to prepare two files. A HelloWorld.cpp file and Build.bat file.
HelloWorld.cpp
1 2 3 4 5 6 7 8 |
#include <stdio.h> int main( ) { printf("Hello World!\n"); } |
Build.bat
1 2 3 4 5 6 |
clang HelloWorld.cpp -S -emit-llvm # Creates .ll file clang HelloWorld.cpp -emit-ast # Creates .ast file clang HelloWorld.ll -o HelloWorld.exe # Creates .exe file from .ll clang HelloWorld.cpp -o HelloWorld.exe # Creates .exe file from .cpp |
Build it!
Now, let's run Build.bat from terminal. As an outcome you should get couple new files:
HelloWorld.exe - The compiled .cpp file in form of .exe file. Run it and you'll see Hello World!
HelloWorld.ll - C++ code translated to text file that contains It's assembly-like language IR.
HelloWorld.ast - Binary file that represents Abstract Syntax Tree of HelloWorld.cpp file.
The first line translates .cpp file to IR language text file. Next line translates .cpp file into .ast file. And the last one takes IR source code
(.ll file) and builds .exe file from it. One of the most interesting files here is .ll. Command: clang HelloWorld.ll -o HelloWorld.exe allows me to write my own IR code and build it into fully working .exe file. That is good starting point to learn IR. That's all for today, the Hello World looks like ... this:
HelloWorld.ll
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
; ModuleID = 'HelloWorld.cpp' source_filename = "HelloWorld.cpp" target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc19.0.24215" %struct._iobuf = type { i8* } %struct.__crt_locale_pointers = type { %struct.__crt_locale_data*, %struct.__crt_multibyte_data* } %struct.__crt_locale_data = type opaque %struct.__crt_multibyte_data = type opaque $printf = comdat any $_vfprintf_l = comdat any $__local_stdio_printf_options = comdat any $"\01??_C@_0O@NFOCKKMG@Hello?5World?$CB?6?$AA@" = comdat any $"\01?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = comdat any @"\01??_C@_0O@NFOCKKMG@Hello?5World?$CB?6?$AA@" = linkonce_odr unnamed_addr constant [14 x i8] c"Hello World!\0A\00", comdat, align 1 @"\01?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" = linkonce_odr global i64 0, comdat, align 8 ; Function Attrs: noinline norecurse uwtable define i32 @main() #0 { entry: %call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01??_C@_0O@NFOCKKMG@Hello?5World?$CB?6?$AA@", i32 0, i32 0)) ret i32 0 } ; Function Attrs: noinline uwtable define linkonce_odr i32 @printf(i8* %_Format, ...) #1 comdat { entry: %_Format.addr = alloca i8*, align 8 %_Result = alloca i32, align 4 %_ArgList = alloca i8*, align 8 store i8* %_Format, i8** %_Format.addr, align 8 %_ArgList1 = bitcast i8** %_ArgList to i8* call void @llvm.va_start(i8* %_ArgList1) %0 = load i8*, i8** %_ArgList, align 8 %1 = load i8*, i8** %_Format.addr, align 8 %call = call %struct._iobuf* @__acrt_iob_func(i32 1) %call2 = call i32 @_vfprintf_l(%struct._iobuf* %call, i8* %1, %struct.__crt_locale_pointers* null, i8* %0) store i32 %call2, i32* %_Result, align 4 %_ArgList3 = bitcast i8** %_ArgList to i8* call void @llvm.va_end(i8* %_ArgList3) %2 = load i32, i32* %_Result, align 4 ret i32 %2 } ; Function Attrs: nounwind declare void @llvm.va_start(i8*) #2 ; Function Attrs: noinline uwtable define linkonce_odr i32 @_vfprintf_l(%struct._iobuf* %_Stream, i8* %_Format, %struct.__crt_locale_pointers* %_Locale, i8* %_ArgList) #1 comdat { entry: %_ArgList.addr = alloca i8*, align 8 %_Locale.addr = alloca %struct.__crt_locale_pointers*, align 8 %_Format.addr = alloca i8*, align 8 %_Stream.addr = alloca %struct._iobuf*, align 8 store i8* %_ArgList, i8** %_ArgList.addr, align 8 store %struct.__crt_locale_pointers* %_Locale, %struct.__crt_locale_pointers** %_Locale.addr, align 8 store i8* %_Format, i8** %_Format.addr, align 8 store %struct._iobuf* %_Stream, %struct._iobuf** %_Stream.addr, align 8 %0 = load i8*, i8** %_ArgList.addr, align 8 %1 = load %struct.__crt_locale_pointers*, %struct.__crt_locale_pointers** %_Locale.addr, align 8 %2 = load i8*, i8** %_Format.addr, align 8 %3 = load %struct._iobuf*, %struct._iobuf** %_Stream.addr, align 8 %call = call i64* @__local_stdio_printf_options() %4 = load i64, i64* %call, align 8 %call1 = call i32 @__stdio_common_vfprintf(i64 %4, %struct._iobuf* %3, i8* %2, %struct.__crt_locale_pointers* %1, i8* %0) ret i32 %call1 } declare %struct._iobuf* @__acrt_iob_func(i32) #3 ; Function Attrs: nounwind declare void @llvm.va_end(i8*) #2 declare i32 @__stdio_common_vfprintf(i64, %struct._iobuf*, i8*, %struct.__crt_locale_pointers*, i8*) #3 ; Function Attrs: noinline nounwind uwtable define linkonce_odr i64* @__local_stdio_printf_options() #4 comdat { entry: ret i64* @"\01?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA" } attributes #0 = { noinline norecurse uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { noinline uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind } attributes #3 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #4 = { noinline nounwind uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } !llvm.module.flags = !{!0, !3} !llvm.ident = !{!4} !0 = !{i32 6, !"Linker Options", !1} !1 = !{!2} !2 = !{!"/FAILIFMISMATCH:\22_CRT_STDIO_ISO_WIDE_SPECIFIERS=0\22"} !3 = !{i32 1, !"PIC Level", i32 2} !4 = !{!"clang version 4.0.0 (tags/RELEASE_400/final)"} |