Commit 0278468479

Andrew Kelley <superjoe30@gmail.com>
2016-01-27 08:01:49
upgrade to the libclang C++ API
c_import creates a tmp .h file and parses it with libclang, reporting any errors found. See #88
1 parent ac085a8
cmake/Findclang.cmake
@@ -1,16 +1,34 @@
-# Copyright (c) 2015 Andrew Kelley
+# Copyright (c) 2016 Andrew Kelley
 # This file is MIT licensed.
 # See http://opensource.org/licenses/MIT
 
 # CLANG_FOUND
-# CLANG_INCLUDE_DIR
-# CLANG_LIBRARY
+# CLANG_INCLUDE_DIRS
+# CLANG_LIBRARIES
 
-find_path(CLANG_INCLUDE_DIR NAMES clang-c/Index.h PATHS /usr/lib/llvm-3.7/include/)
+find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h)
 
-find_library(CLANG_LIBRARY NAMES clang PATHS /usr/lib/llvm-3.7/lib/)
+macro(FIND_AND_ADD_CLANG_LIB _libname_)
+    string(TOUPPER ${_libname_} _prettylibname_)
+    find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_})
+    if(CLANG_${_prettylibname_}_LIB)
+        set(CLANG_LIBRARIES ${CLANG_LIBRARIES} ${CLANG_${_prettylibname_}_LIB})
+    endif()
+endmacro(FIND_AND_ADD_CLANG_LIB)
+
+FIND_AND_ADD_CLANG_LIB(clangFrontend)
+FIND_AND_ADD_CLANG_LIB(clangDriver)
+FIND_AND_ADD_CLANG_LIB(clangSerialization)
+FIND_AND_ADD_CLANG_LIB(clangSema)
+FIND_AND_ADD_CLANG_LIB(clangAnalysis)
+FIND_AND_ADD_CLANG_LIB(clangAST)
+FIND_AND_ADD_CLANG_LIB(clangParse)
+FIND_AND_ADD_CLANG_LIB(clangSema)
+FIND_AND_ADD_CLANG_LIB(clangBasic)
+FIND_AND_ADD_CLANG_LIB(clangEdit)
+FIND_AND_ADD_CLANG_LIB(clangLex)
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARY CLANG_INCLUDE_DIR)
+find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)
 
-mark_as_advanced(CLANG_INCLUDE_DIR CLANG_LIBRARY)
+mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES)
src/all_types.hpp
@@ -995,6 +995,8 @@ struct CodeGen {
     bool have_exported_main;
     bool link_libc;
     Buf *libc_path;
+    Buf *libc_lib_path;
+    Buf *libc_include_path;
     CodeGenBuildType build_type;
     LLVMTargetMachineRef target_machine;
     LLVMZigDIFile *dummy_di_file;
@@ -1068,4 +1070,12 @@ struct BlockContext {
     Buf *c_import_buf;
 };
 
+struct ParseH {
+    ZigList<ErrorMsg*> errors;
+    ZigList<AstNode *> fn_list;
+    ZigList<AstNode *> struct_list;
+    ZigList<AstNode *> var_list;
+    ZigList<AstNode *> incomplete_struct_list;
+};
+
 #endif
src/analyze.cpp
@@ -10,6 +10,8 @@
 #include "error.hpp"
 #include "zig_llvm.hpp"
 #include "os.hpp"
+#include "parseh.hpp"
+#include "config.h"
 
 static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
         TypeTableEntry *expected_type, AstNode *node);
@@ -83,18 +85,12 @@ static AstNode *first_executing_node(AstNode *node) {
     zig_unreachable();
 }
 
-void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
-    ErrorMsg *err = allocate<ErrorMsg>(1);
-    err->line_start = node->line;
-    err->column_start = node->column;
-    err->line_end = -1;
-    err->column_end = -1;
-    err->msg = msg;
-    err->path = node->owner->path;
-    err->source = node->owner->source_code;
-    err->line_offsets = node->owner->line_offsets;
+ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
+    ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
+            node->owner->source_code, node->owner->line_offsets, msg);
 
     g->errors.append(err);
+    return err;
 }
 
 TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
@@ -1036,8 +1032,22 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *import, AstNode
         return;
     }
 
-    fprintf(stderr, "c import buf:\n%s\n", buf_ptr(child_context->c_import_buf));
-    zig_panic("TODO");
+    find_libc_path(g);
+    int err;
+    ParseH parse_h = {{0}};
+    if ((err = parse_h_buf(&parse_h, child_context->c_import_buf, buf_ptr(g->libc_include_path)))) {
+        zig_panic("unable to parse h file: %s\n", err_str(err));
+    }
+
+    if (parse_h.errors.length > 0) {
+        ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
+        for (int i = 0; i < parse_h.errors.length; i += 1) {
+            ErrorMsg *err_msg = parse_h.errors.at(i);
+            err_msg_add_note(parent_err_msg, err_msg);
+        }
+    } else {
+        zig_panic("TODO integrate the parsed AST");
+    }
 }
 
 static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
@@ -3444,7 +3454,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                     return g->builtin_types.entry_void;
                 }
 
-                buf_appendf(context->c_import_buf, "#include \"");
+                buf_appendf(context->c_import_buf, "#include <");
                 ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
                 uint64_t len = ptr_field->data.x_ptr.len;
                 for (uint64_t i = 0; i < len; i += 1) {
@@ -3454,7 +3464,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
                     uint8_t c = big_c;
                     buf_appendf(context->c_import_buf, "%c", c);
                 }
-                buf_appendf(context->c_import_buf, "\"\n");
+                buf_appendf(context->c_import_buf, ">\n");
 
                 return g->builtin_types.entry_void;
             }
@@ -4976,3 +4986,22 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
     }
     zig_unreachable();
 }
+
+void find_libc_path(CodeGen *g) {
+    if (!g->libc_path || buf_len(g->libc_path) == 0) {
+        g->libc_path = buf_create_from_str(ZIG_LIBC_DIR);
+        if (!g->libc_path || buf_len(g->libc_path) == 0) {
+            // later we can handle this better by reporting an error via the normal mechanism
+            zig_panic("Unable to determine libc path. You can use `--libc-path`");
+        }
+    }
+    if (!g->libc_lib_path) {
+        g->libc_lib_path = buf_alloc();
+        os_path_join(g->libc_path, buf_create_from_str("lib"), g->libc_lib_path);
+    }
+    if (!g->libc_include_path) {
+        g->libc_include_path = buf_alloc();
+        os_path_join(g->libc_path, buf_create_from_str("include"), g->libc_include_path);
+    }
+}
+
src/analyze.hpp
@@ -11,7 +11,7 @@
 #include "all_types.hpp"
 
 void semantic_analyze(CodeGen *g);
-void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
+ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
 TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
 TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
 VariableTableEntry *find_variable(BlockContext *context, Buf *name);
@@ -23,4 +23,6 @@ bool is_node_void_expr(AstNode *node);
 TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
 TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
 bool handle_is_ptr(TypeTableEntry *type_entry);
+void find_libc_path(CodeGen *g);
+
 #endif
src/codegen.cpp
@@ -3051,15 +3051,8 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
     tokenize(source_code, &tokenization);
 
     if (tokenization.err) {
-        ErrorMsg *err = allocate<ErrorMsg>(1);
-        err->line_start = tokenization.err_line;
-        err->column_start = tokenization.err_column;
-        err->line_end = -1;
-        err->column_end = -1;
-        err->msg = tokenization.err;
-        err->path = full_path;
-        err->source = source_code;
-        err->line_offsets = tokenization.line_offsets;
+        ErrorMsg *err = err_msg_create_with_line(full_path, tokenization.err_line, tokenization.err_column,
+                source_code, tokenization.line_offsets, tokenization.err);
 
         print_err_msg(err, g->err_color);
         exit(1);
@@ -3401,19 +3394,9 @@ static void generate_h_file(CodeGen *g) {
         zig_panic("unable to close h file: %s", strerror(errno));
 }
 
-static void find_libc_path(CodeGen *g) {
-    if (g->libc_path && buf_len(g->libc_path))
-        return;
-    g->libc_path = buf_create_from_str(ZIG_LIBC_DIR);
-    if (g->libc_path && buf_len(g->libc_path))
-        return;
-    fprintf(stderr, "Unable to determine libc path. Consider using `--libc-path [path]`\n");
-    exit(1);
-}
-
 static const char *get_libc_file(CodeGen *g, const char *file) {
     Buf *out_buf = buf_alloc();
-    os_path_join(g->libc_path, buf_create_from_str(file), out_buf);
+    os_path_join(g->libc_lib_path, buf_create_from_str(file), out_buf);
     return buf_ptr(out_buf);
 }
 
src/errmsg.cpp
@@ -15,16 +15,7 @@ void print_err_msg(ErrorMsg *err, ErrColor color) {
                 err->line_start + 1, err->column_start + 1,
                 buf_ptr(err->msg));
 
-        assert(err->source);
-        assert(err->line_offsets);
-
-        int line_start_offset = err->line_offsets->at(err->line_start);
-        int end_line = err->line_start + 1;
-        int line_end_offset = (end_line >= err->line_offsets->length) ?
-            buf_len(err->source) : err->line_offsets->at(err->line_start + 1);
-
-        fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr);
-        fprintf(stderr, "\n");
+        fprintf(stderr, "%s\n", buf_ptr(&err->line_buf));
         for (int i = 0; i < err->column_start; i += 1) {
             fprintf(stderr, " ");
         }
@@ -36,5 +27,62 @@ void print_err_msg(ErrorMsg *err, ErrColor color) {
                 err->line_start + 1, err->column_start + 1,
                 buf_ptr(err->msg));
     }
+
+    for (int i = 0; i < err->notes.length; i += 1) {
+        ErrorMsg *note = err->notes.at(i);
+        print_err_msg(note, color);
+    }
+}
+
+void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) {
+    parent->notes.append(note);
 }
 
+ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset,
+        const char *source, Buf *msg)
+{
+    ErrorMsg *err_msg = allocate<ErrorMsg>(1);
+    err_msg->path = path;
+    err_msg->line_start = line;
+    err_msg->column_start = column;
+    err_msg->msg = msg;
+
+    int line_start_offset = offset;
+    for (;;) {
+        if (line_start_offset == 0) {
+            break;
+        } else if (source[line_start_offset] == '\n') {
+            line_start_offset += 1;
+            break;
+        }
+        line_start_offset -= 1;
+    }
+
+    int line_end_offset = offset;
+    while (source[line_end_offset] && source[line_end_offset] != '\n') {
+        line_end_offset += 1;
+    }
+
+    buf_init_from_mem(&err_msg->line_buf, source + line_start_offset, line_end_offset - line_start_offset);
+
+    return err_msg;
+}
+
+ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column,
+        Buf *source, ZigList<int> *line_offsets, Buf *msg)
+{
+    ErrorMsg *err_msg = allocate<ErrorMsg>(1);
+    err_msg->path = path;
+    err_msg->line_start = line;
+    err_msg->column_start = column;
+    err_msg->msg = msg;
+
+    int line_start_offset = line_offsets->at(line);
+    int end_line = line + 1;
+    int line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1);
+
+    buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset,
+            line_end_offset - line_start_offset - 1);
+
+    return err_msg;
+}
src/errmsg.hpp
@@ -20,14 +20,20 @@ enum ErrColor {
 struct ErrorMsg {
     int line_start;
     int column_start;
-    int line_end;
-    int column_end;
     Buf *msg;
     Buf *path;
-    Buf *source;
-    ZigList<int> *line_offsets;
+    Buf line_buf;
+
+    ZigList<ErrorMsg *> notes;
 };
 
 void print_err_msg(ErrorMsg *msg, ErrColor color);
 
+void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note);
+ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset,
+        const char *source, Buf *msg);
+
+ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column,
+        Buf *source, ZigList<int> *line_offsets, Buf *msg);
+
 #endif
src/main.cpp
@@ -156,6 +156,25 @@ static int build(const char *arg0, int argc, char **argv) {
     return 0;
 }
 
+struct ParseHPrint {
+    ParseH parse_h;
+    FILE *f;
+    int cur_indent;
+};
+
+static const int indent_size = 4;
+
+static void print_indent(ParseHPrint *p) {
+    for (int i = 0; i < p->cur_indent; i += 1) {
+        fprintf(p->f, " ");
+    }
+}
+
+static const char *type_node_to_name(AstNode *type_node) {
+    assert(type_node->type == NodeTypeSymbol);
+    return buf_ptr(&type_node->data.symbol_expr.symbol);
+}
+
 static int parseh(const char *arg0, int argc, char **argv) {
     char *in_file = nullptr;
     ZigList<const char *> clang_argv = {0};
@@ -187,7 +206,73 @@ static int parseh(const char *arg0, int argc, char **argv) {
         return usage(arg0);
     }
 
-    parse_h_file(in_file, &clang_argv, stdout);
+    clang_argv.append(in_file);
+
+    ParseHPrint parse_h_print = {{{0}}};
+    ParseHPrint *p = &parse_h_print;
+    p->f = stdout;
+    p->cur_indent = 0;
+
+    parse_h_file(&p->parse_h, &clang_argv);
+
+    if (p->parse_h.errors.length > 0) {
+        for (int i = 0; i < p->parse_h.errors.length; i += 1) {
+            ErrorMsg *err_msg = p->parse_h.errors.at(i);
+            // TODO respect --color arg
+            print_err_msg(err_msg, ErrColorAuto);
+        }
+        return EXIT_FAILURE;
+    }
+
+    for (int struct_i = 0; struct_i < p->parse_h.struct_list.length; struct_i += 1) {
+        AstNode *struct_decl = p->parse_h.struct_list.at(struct_i);
+        assert(struct_decl->type == NodeTypeStructDecl);
+        const char *struct_name = buf_ptr(&struct_decl->data.struct_decl.name);
+        print_indent(p);
+        fprintf(p->f, "struct %s {\n", struct_name);
+        p->cur_indent += indent_size;
+        for (int field_i = 0; field_i < struct_decl->data.struct_decl.fields.length; field_i += 1) {
+            AstNode *field_node = struct_decl->data.struct_decl.fields.at(field_i);
+            assert(field_node->type == NodeTypeStructField);
+            const char *field_name = buf_ptr(&field_node->data.struct_field.name);
+            const char *type_name = type_node_to_name(field_node->data.struct_field.type);
+            print_indent(p);
+            fprintf(p->f, "%s: %s,\n", field_name, type_name);
+        }
+
+        p->cur_indent -= indent_size;
+        fprintf(p->f, "}\n\n");
+    }
+
+    for (int fn_i = 0; fn_i < p->parse_h.fn_list.length; fn_i += 1) {
+        AstNode *fn_proto = p->parse_h.fn_list.at(fn_i);
+        assert(fn_proto->type == NodeTypeFnProto);
+        print_indent(p);
+        const char *fn_name = buf_ptr(&fn_proto->data.fn_proto.name);
+        fprintf(p->f, "extern fn %s(", fn_name);
+        int arg_count = fn_proto->data.fn_proto.params.length;
+        bool is_var_args = fn_proto->data.fn_proto.is_var_args;
+        for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
+            AstNode *param_decl = fn_proto->data.fn_proto.params.at(arg_i);
+            assert(param_decl->type == NodeTypeParamDecl);
+            const char *arg_name = buf_ptr(&param_decl->data.param_decl.name);
+            const char *arg_type = type_node_to_name(param_decl->data.param_decl.type);
+            fprintf(p->f, "%s: %s", arg_name, arg_type);
+            if (arg_i + 1 < arg_count || is_var_args) {
+                fprintf(p->f, ", ");
+            }
+        }
+        if (is_var_args) {
+            fprintf(p->f, "...");
+        }
+        fprintf(p->f, ")");
+        const char *return_type_name = type_node_to_name(fn_proto->data.fn_proto.return_type);
+        if (strcmp(return_type_name, "void") != 0) {
+            fprintf(p->f, " -> %s", return_type_name);
+        }
+        fprintf(p->f, ";\n");
+    }
+
     return 0;
 }
 
src/os.cpp
@@ -208,3 +208,29 @@ int os_get_cwd(Buf *out_cwd) {
 bool os_stderr_tty(void) {
     return isatty(STDERR_FILENO);
 }
+
+int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
+    buf_resize(out_tmp_path, 0);
+    buf_appendf(out_tmp_path, "/tmp/XXXXXX%s", buf_ptr(suffix));
+
+    int fd = mkstemps(buf_ptr(out_tmp_path), buf_len(suffix));
+    if (fd < 0) {
+        return ErrorFileSystem;
+    }
+
+    ssize_t amt_written = write(fd, buf_ptr(contents), buf_len(contents));
+    if (amt_written != buf_len(contents))
+        zig_panic("write failed: %s", strerror(errno));
+    if (close(fd) == -1)
+        zig_panic("close failed");
+
+    return 0;
+}
+
+int os_delete_file(Buf *path) {
+    if (remove(buf_ptr(path))) {
+        return ErrorFileSystem;
+    } else {
+        return 0;
+    }
+}
src/os.hpp
@@ -29,7 +29,9 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
 
 int os_get_cwd(Buf *out_cwd);
 
-
 bool os_stderr_tty(void);
 
+int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
+int os_delete_file(Buf *path);
+
 #endif
src/parseh.cpp
@@ -7,540 +7,52 @@
 
 #include "parseh.hpp"
 #include "config.h"
+#include "os.hpp"
+#include "error.hpp"
 
-#include <clang-c/Index.h>
+#include <clang/Frontend/ASTUnit.h>
+#include <clang/Frontend/CompilerInstance.h>
 
 #include <string.h>
 
-struct TypeDef {
-    Buf alias;
-    Buf target;
-};
-
-struct Arg {
-    Buf name;
-    Buf *type;
-};
-
-struct Fn {
-    Buf name;
-    Buf *return_type;
-    Arg *args;
-    int arg_count;
-    bool is_variadic;
-};
-
-struct Field {
-    Buf name;
-    Buf *type;
-};
-
-struct Struct {
-    Buf name;
-    ZigList<Field*> fields;
-    bool have_def;
-};
-
-struct ParseH {
-    CXTranslationUnit tu;
-    FILE *f;
-    ZigList<Fn *> fn_list;
-    ZigList<Struct *> struct_list;
-    ZigList<TypeDef *> type_def_list;
-    ZigList<Struct *> incomplete_struct_list;
-    Fn *cur_fn;
-    Struct *cur_struct;
-    int arg_index;
-    int cur_indent;
-    CXSourceRange range;
-    CXSourceLocation location;
-};
-
-static const int indent_size = 4;
+using namespace clang;
 
-struct TypeMapping {
-    const char *c_name;
-    const char *zig_name;
+struct Context {
+    ParseH *parse_h;
 };
 
-static const TypeMapping type_mappings[] = {
-    {
-        "int8_t",
-        "i8",
-    },
-    {
-        "uint8_t",
-        "u8",
-    },
-    {
-        "uint16_t",
-        "u16",
-    },
-    {
-        "uint32_t",
-        "u32",
-    },
-    {
-        "uint64_t",
-        "u64",
-    },
-    {
-        "int16_t",
-        "i16",
-    },
-    {
-        "int32_t",
-        "i32",
-    },
-    {
-        "int64_t",
-        "i64",
-    },
-    {
-        "intptr_t",
-        "isize",
-    },
-    {
-        "uintptr_t",
-        "usize",
-    },
-};
-
-static bool have_struct_def(ParseH *p, Buf *name) {
-    for (int i = 0; i < p->struct_list.length; i += 1) {
-        Struct *struc = p->struct_list.at(i);
-        if (struc->fields.length > 0 && buf_eql_buf(&struc->name, name)) {
-            return true;
-        }
-    }
-    return false;
-}
+static bool decl_visitor(void *context, const Decl *decl) {
+    //Context *c = (Context*)context;
 
-static const char *c_to_zig_name(const char *name) {
-    for (int i = 0; i < array_length(type_mappings); i += 1) {
-        const TypeMapping *mapping = &type_mappings[i];
-        if (strcmp(mapping->c_name, name) == 0)
-            return mapping->zig_name;
-    }
-    return nullptr;
-}
+    fprintf(stderr, "got top level decl\n");
 
-static bool str_has_prefix(const char *str, const char *prefix) {
-    while (*prefix) {
-        if (*str && *str == *prefix) {
-            str += 1;
-            prefix += 1;
-        } else {
-            return false;
-        }
-    }
     return true;
 }
 
-static const char *prefixes_stripped(CXType type) {
-    CXString name = clang_getTypeSpelling(type);
-    const char *c_name = clang_getCString(name);
-
-    static const char *prefixes[] = {
-        "struct ",
-        "enum ",
-        "const ",
-    };
-
-start_over:
-
-    for (int i = 0; i < array_length(prefixes); i += 1) {
-        const char *prefix = prefixes[i];
-        if (str_has_prefix(c_name, prefix)) {
-            c_name += strlen(prefix);
-            goto start_over;
-        }
-    }
-    return c_name;
-}
-
-static void print_location(ParseH *p) {
-    CXFile file;
-    unsigned line, column, offset;
-    clang_getFileLocation(p->location, &file, &line, &column, &offset);
-    CXString file_name = clang_getFileName(file);
-
-    fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column);
-}
-
-static bool resolves_to_void(ParseH *p, CXType raw_type) {
-    if (raw_type.kind == CXType_Unexposed) {
-        CXType canonical = clang_getCanonicalType(raw_type);
-        if (canonical.kind == CXType_Unexposed)
-            zig_panic("clang C api insufficient");
-        else
-            return resolves_to_void(p, canonical);
-    }
-    if (raw_type.kind == CXType_Void) {
-        return true;
-    } else if (raw_type.kind == CXType_Typedef) {
-        CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
-        CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
-        return resolves_to_void(p, underlying_type);
-    }
-    return false;
-}
-
-static Buf *to_zig_type(ParseH *p, CXType raw_type) {
-    if (raw_type.kind == CXType_Unexposed) {
-        CXType canonical = clang_getCanonicalType(raw_type);
-        if (canonical.kind == CXType_Unexposed)
-            zig_panic("clang C api insufficient");
-        else
-            return to_zig_type(p, canonical);
-    }
-    switch (raw_type.kind) {
-        case CXType_Invalid:
-        case CXType_Unexposed:
-            zig_unreachable();
-        case CXType_Void:
-            zig_panic("void type encountered");
-        case CXType_Bool:
-            return buf_create_from_str("bool");
-        case CXType_SChar:
-            return buf_create_from_str("i8");
-        case CXType_UChar:
-        case CXType_Char_U:
-        case CXType_Char_S:
-            return buf_create_from_str("u8");
-        case CXType_WChar:
-            print_location(p);
-            zig_panic("TODO wchar");
-        case CXType_Char16:
-            print_location(p);
-            zig_panic("TODO char16");
-        case CXType_Char32:
-            print_location(p);
-            zig_panic("TODO char32");
-        case CXType_UShort:
-            return buf_create_from_str("c_ushort");
-        case CXType_UInt:
-            return buf_create_from_str("c_uint");
-        case CXType_ULong:
-            return buf_create_from_str("c_ulong");
-        case CXType_ULongLong:
-            return buf_create_from_str("c_ulonglong");
-        case CXType_UInt128:
-            print_location(p);
-            zig_panic("TODO uint128");
-        case CXType_Short:
-            return buf_create_from_str("c_short");
-        case CXType_Int:
-            return buf_create_from_str("c_int");
-        case CXType_Long:
-            return buf_create_from_str("c_long");
-        case CXType_LongLong:
-            return buf_create_from_str("c_longlong");
-        case CXType_Int128:
-            print_location(p);
-            zig_panic("TODO int128");
-        case CXType_Float:
-            return buf_create_from_str("f32");
-        case CXType_Double:
-            return buf_create_from_str("f64");
-        case CXType_LongDouble:
-            return buf_create_from_str("f128");
-        case CXType_IncompleteArray:
-            {
-                CXType pointee_type = clang_getArrayElementType(raw_type);
-                Buf *pointee_buf = to_zig_type(p, pointee_type);
-                if (clang_isConstQualifiedType(pointee_type)) {
-                    return buf_sprintf("&const %s", buf_ptr(pointee_buf));
-                } else {
-                    return buf_sprintf("&%s", buf_ptr(pointee_buf));
-                }
-            }
-        case CXType_Pointer:
-            {
-                CXType pointee_type = clang_getPointeeType(raw_type);
-                Buf *pointee_buf;
-                if (resolves_to_void(p, pointee_type)) {
-                    pointee_buf = buf_create_from_str("u8");
-                } else {
-                    pointee_buf = to_zig_type(p, pointee_type);
-                }
-                if (clang_isConstQualifiedType(pointee_type)) {
-                    return buf_sprintf("&const %s", buf_ptr(pointee_buf));
-                } else {
-                    return buf_sprintf("&%s", buf_ptr(pointee_buf));
-                }
-            }
-        case CXType_Record:
-            {
-                const char *name = prefixes_stripped(raw_type);
-                return buf_sprintf("%s", name);
-            }
-        case CXType_Enum:
-            {
-                const char *name = prefixes_stripped(raw_type);
-                return buf_sprintf("%s", name);
-            }
-        case CXType_Typedef:
-            {
-                const char *name = prefixes_stripped(raw_type);
-                const char *zig_name = c_to_zig_name(name);
-                if (zig_name) {
-                    return buf_create_from_str(zig_name);
-                } else {
-                    CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
-                    CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
-                    if (resolves_to_void(p, underlying_type)) {
-                        return buf_create_from_str("u8");
-                    } else {
-                        return buf_create_from_str(name);
-                    }
-                }
-            }
-        case CXType_ConstantArray:
-            {
-                CXType child_type = clang_getArrayElementType(raw_type);
-                Buf *zig_child_type = to_zig_type(p, child_type);
-                long size = (long)clang_getArraySize(raw_type);
-                return buf_sprintf("[%s; %ld]", buf_ptr(zig_child_type), size);
-            }
-        case CXType_FunctionProto:
-            fprintf(stderr, "warning: TODO function proto\n");
-            print_location(p);
-            return buf_create_from_str("u8");
-        case CXType_FunctionNoProto:
-            print_location(p);
-            zig_panic("TODO function no proto");
-        case CXType_BlockPointer:
-            print_location(p);
-            zig_panic("TODO block pointer");
-        case CXType_Vector:
-            print_location(p);
-            zig_panic("TODO vector");
-        case CXType_LValueReference:
-        case CXType_RValueReference:
-        case CXType_VariableArray:
-        case CXType_DependentSizedArray:
-        case CXType_MemberPointer:
-        case CXType_ObjCInterface:
-        case CXType_ObjCObjectPointer:
-        case CXType_NullPtr:
-        case CXType_Overload:
-        case CXType_Dependent:
-        case CXType_ObjCId:
-        case CXType_ObjCClass:
-        case CXType_ObjCSel:
-        case CXType_Complex:
-            print_location(p);
-            zig_panic("TODO");
-    }
-
-    zig_unreachable();
-}
-
-static bool is_storage_class_export(CX_StorageClass storage_class) {
-    switch (storage_class) {
-        case CX_SC_Invalid:
-            zig_unreachable();
-        case CX_SC_None:
-        case CX_SC_Extern:
-        case CX_SC_Auto:
-            return true;
-        case CX_SC_Static:
-        case CX_SC_PrivateExtern:
-        case CX_SC_OpenCLWorkGroupLocal:
-        case CX_SC_Register:
-            return false;
-    }
-    zig_unreachable();
-}
-
-static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor parent, CXClientData client_data) {
-    ParseH *p = (ParseH*)client_data;
-    enum CXCursorKind kind = clang_getCursorKind(cursor);
-
-    switch (kind) {
-    case CXCursor_ParmDecl:
-        {
-            assert(p->cur_fn);
-            assert(p->arg_index < p->cur_fn->arg_count);
-            CXString name = clang_getCursorSpelling(cursor);
-            Buf *arg_name = &p->cur_fn->args[p->arg_index].name;
-            buf_init_from_str(arg_name, clang_getCString(name));
-            if (buf_len(arg_name) == 0) {
-                buf_appendf(arg_name, "arg%d", p->arg_index);
-            }
-
-            p->arg_index += 1;
-            return CXChildVisit_Continue;
-        }
-    default:
-        return CXChildVisit_Recurse;
-    }
-}
-
-static enum CXChildVisitResult visit_struct_children(CXCursor cursor, CXCursor parent, CXClientData client_data) {
-    ParseH *p = (ParseH*)client_data;
-    enum CXCursorKind kind = clang_getCursorKind(cursor);
-
-    switch (kind) {
-    case CXCursor_FieldDecl:
-        {
-            assert(p->cur_struct);
-            CXString name = clang_getCursorSpelling(cursor);
-            Field *field = allocate<Field>(1);
-            buf_init_from_str(&field->name, clang_getCString(name));
-            CXType cursor_type = clang_getCursorType(cursor);
-            field->type = to_zig_type(p, cursor_type);
-
-            p->cur_struct->fields.append(field);
-
-            return CXChildVisit_Continue;
-        }
-    default:
-        return CXChildVisit_Recurse;
-    }
-}
-
-static bool handle_struct_cursor(ParseH *p, CXCursor cursor, const char *name, bool expect_name) {
-    p->cur_struct = allocate<Struct>(1);
-
-    buf_init_from_str(&p->cur_struct->name, name);
-
-    bool got_name = (buf_len(&p->cur_struct->name) != 0);
-    if (expect_name != got_name)
-        return false;
-
-    clang_visitChildren(cursor, visit_struct_children, p);
-
-    if (p->cur_struct->fields.length > 0) {
-        p->struct_list.append(p->cur_struct);
-    } else {
-        p->incomplete_struct_list.append(p->cur_struct);
+int parse_h_buf(ParseH *parse_h, Buf *source, const char *libc_include_path) {
+    int err;
+    Buf tmp_file_path = BUF_INIT;
+    if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) {
+        return err;
     }
+    ZigList<const char *> clang_argv = {0};
+    clang_argv.append(buf_ptr(&tmp_file_path));
 
-    p->cur_struct = nullptr;
-
-    return true;
-}
-
-
-static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
-    ParseH *p = (ParseH*)client_data;
-    enum CXCursorKind kind = clang_getCursorKind(cursor);
-    CXString name = clang_getCursorSpelling(cursor);
-
-    p->range = clang_getCursorExtent(cursor);
-    p->location = clang_getRangeStart(p->range);
-
-    switch (kind) {
-    case CXCursor_FunctionDecl:
-        {
-            CX_StorageClass storage_class = clang_Cursor_getStorageClass(cursor);
-            if (!is_storage_class_export(storage_class))
-                return CXChildVisit_Continue;
-
-            CXType fn_type = clang_getCursorType(cursor);
-            if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) {
-                print_location(p);
-                fprintf(stderr, "warning: skipping non c calling convention function, not yet supported\n");
-                return CXChildVisit_Continue;
-            }
-
-            assert(!p->cur_fn);
-            p->cur_fn = allocate<Fn>(1);
-
-            p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type);
-
-            CXType return_type = clang_getResultType(fn_type);
-            if (!resolves_to_void(p, return_type)) {
-                p->cur_fn->return_type = to_zig_type(p, return_type);
-            }
-
-            buf_init_from_str(&p->cur_fn->name, clang_getCString(name));
-
-            p->cur_fn->arg_count = clang_getNumArgTypes(fn_type);
-            p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count);
-
-            for (int i = 0; i < p->cur_fn->arg_count; i += 1) {
-                CXType param_type = clang_getArgType(fn_type, i);
-                p->cur_fn->args[i].type = to_zig_type(p, param_type);
-            }
-
-            p->arg_index = 0;
-
-            clang_visitChildren(cursor, visit_fn_children, p);
-
-            p->fn_list.append(p->cur_fn);
-            p->cur_fn = nullptr;
-
-            return CXChildVisit_Recurse;
-        }
-    case CXCursor_CompoundStmt:
-    case CXCursor_FieldDecl:
-    case CXCursor_TypedefDecl:
-        {
-            CXType underlying_type = clang_getTypedefDeclUnderlyingType(cursor);
-
-            if (resolves_to_void(p, underlying_type)) {
-                return CXChildVisit_Continue;
-            }
-
-            if (underlying_type.kind == CXType_Unexposed) {
-                underlying_type = clang_getCanonicalType(underlying_type);
-            }
-            bool skip_typedef;
-            if (underlying_type.kind == CXType_Unexposed) {
-                fprintf(stderr, "warning: unexposed type\n");
-                print_location(p);
-                skip_typedef = true;
-            } else if (underlying_type.kind == CXType_Record) {
-                CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type);
-                skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false);
-            } else if (underlying_type.kind == CXType_Invalid) {
-                fprintf(stderr, "warning: invalid type\n");
-                print_location(p);
-                skip_typedef = true;
-            } else {
-                skip_typedef = false;
-            }
-
-            CXType typedef_type = clang_getCursorType(cursor);
-            const char *name_str = prefixes_stripped(typedef_type);
-            if (!skip_typedef && c_to_zig_name(name_str)) {
-                skip_typedef = true;
-            }
+    clang_argv.append("-isystem");
+    clang_argv.append(libc_include_path);
 
-            if (!skip_typedef) {
-                TypeDef *type_def = allocate<TypeDef>(1);
-                buf_init_from_str(&type_def->alias, name_str);
-                buf_init_from_buf(&type_def->target, to_zig_type(p, underlying_type));
-                p->type_def_list.append(type_def);
-            }
-
-            return CXChildVisit_Continue;
-        }
-    case CXCursor_StructDecl:
-        {
-            handle_struct_cursor(p, cursor, clang_getCString(name), true);
+    err = parse_h_file(parse_h, &clang_argv);
 
-            return CXChildVisit_Continue;
-        }
-    default:
-        return CXChildVisit_Recurse;
-    }
-}
+    os_delete_file(&tmp_file_path);
 
-static void print_indent(ParseH *p) {
-    for (int i = 0; i < p->cur_indent; i += 1) {
-        fprintf(p->f, " ");
-    }
+    return err;
+    // write to temp file, parse it, delete it
 }
 
-void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f) {
-    ParseH parse_h = {0};
-    ParseH *p = &parse_h;
-    p->f = f;
-    CXIndex index = clang_createIndex(1, 0);
+int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv) {
+    Context context = {0};
+    Context *c = &context;
+    c->parse_h = parse_h;
 
     char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS");
     if (ZIG_PARSEH_CFLAGS) {
@@ -558,105 +70,78 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI
         buf_init_from_str(&tmp_buf, start);
         clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf)));
     }
+
     clang_argv->append("-isystem");
     clang_argv->append(ZIG_HEADERS_DIR);
 
+    // we don't need spell checking and it slows things down
+    clang_argv->append("-fno-spell-checking");
+    // to make the end argument work
     clang_argv->append(nullptr);
 
-    enum CXErrorCode err_code;
-    if ((err_code = clang_parseTranslationUnit2(index, target_path,
-            clang_argv->items, clang_argv->length - 1,
-            NULL, 0, CXTranslationUnit_None, &p->tu)))
-    {
-        zig_panic("parse translation unit failure");
-    }
-
-
-    unsigned diag_count = clang_getNumDiagnostics(p->tu);
+    IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
 
-    if (diag_count > 0) {
-        for (unsigned i = 0; i < diag_count; i += 1) {
-            CXDiagnostic diagnostic = clang_getDiagnostic(p->tu, i);
-            CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
-
-            CXFile file;
-            unsigned line, column, offset;
-            clang_getSpellingLocation(location, &file, &line, &column, &offset);
-            CXString text = clang_getDiagnosticSpelling(diagnostic);
-            CXString file_name = clang_getFileName(file);
-            fprintf(stderr, "%s line %u, column %u: %s\n", clang_getCString(file_name),
-                    line, column, clang_getCString(text));
-        }
-
-        exit(1);
-    }
+    std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>();
 
+    bool skip_function_bodies = true;
+    bool only_local_decls = true;
+    bool capture_diagnostics = true;
+    bool user_files_are_volatile = true;
+    bool allow_pch_with_compiler_errors = false;
+    const char *resources_path = ZIG_HEADERS_DIR;
+    std::unique_ptr<ASTUnit> err_unit;
+    std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine(
+            &clang_argv->at(0), &clang_argv->last(),
+            pch_container_ops, diags, resources_path,
+            only_local_decls, capture_diagnostics, None, true, false, TU_Complete,
+            false, false, allow_pch_with_compiler_errors, skip_function_bodies,
+            user_files_are_volatile, false, &err_unit));
 
-    CXCursor cursor = clang_getTranslationUnitCursor(p->tu);
-    clang_visitChildren(cursor, fn_visitor, p);
-
-    for (int struct_i = 0; struct_i < p->struct_list.length; struct_i += 1) {
-        Struct *struc = p->struct_list.at(struct_i);
-        fprintf(f, "struct %s {\n", buf_ptr(&struc->name));
-        p->cur_indent += indent_size;
-        for (int field_i = 0; field_i < struc->fields.length; field_i += 1) {
-            Field *field = struc->fields.at(field_i);
-            print_indent(p);
-            fprintf(f, "%s: %s,\n", buf_ptr(&field->name), buf_ptr(field->type));
-        }
-
-        p->cur_indent -= indent_size;
-        fprintf(f, "}\n\n");
-    }
 
-    int total_typedef_count = p->type_def_list.length;
-    for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
-        Struct *struc = p->incomplete_struct_list.at(i);
-        struc->have_def = have_struct_def(p, &struc->name);
-        total_typedef_count += (int)!struc->have_def;
+    // Early failures in LoadFromCommandLine may return with ErrUnit unset.
+    if (!ast_unit && !err_unit) {
+        return ErrorFileSystem;
     }
 
-    if (total_typedef_count) {
-        for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
-            Struct *struc = p->incomplete_struct_list.at(i);
-            if (struc->have_def)
-                continue;
-
-            fprintf(f, "struct %s;\n", buf_ptr(&struc->name));
+    if (diags->getClient()->getNumErrors() > 0) {
+        if (ast_unit) {
+            err_unit = std::move(ast_unit);
         }
 
-        for (int type_def_i = 0; type_def_i < p->type_def_list.length; type_def_i += 1) {
-            TypeDef *type_def = p->type_def_list.at(type_def_i);
-            fprintf(f, "type %s = %s;\n", buf_ptr(&type_def->alias), buf_ptr(&type_def->target));
+        for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), 
+                it_end = err_unit->stored_diag_end();
+                it != it_end; ++it)
+        {
+            switch (it->getLevel()) {
+                case DiagnosticsEngine::Ignored:
+                case DiagnosticsEngine::Note:
+                case DiagnosticsEngine::Remark:
+                case DiagnosticsEngine::Warning:
+                    continue;
+                case DiagnosticsEngine::Error:
+                case DiagnosticsEngine::Fatal:
+                    break;
+            }
+            StringRef msg_str_ref = it->getMessage();
+            FullSourceLoc fsl = it->getLocation();
+            FileID file_id = fsl.getManager().getFileID(fsl);
+            StringRef filename = fsl.getManager().getFilename(fsl);
+            unsigned line = fsl.getSpellingLineNumber() - 1;
+            unsigned column = fsl.getSpellingColumnNumber() - 1;
+            unsigned offset = fsl.getManager().getFileOffset(fsl);
+            const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
+            Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
+            Buf *path = buf_create_from_str((const char *)filename.bytes_begin());
+
+            ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
+
+            parse_h->errors.append(err_msg);
         }
 
-        fprintf(f, "\n");
+        return 0;
     }
 
-    if (p->fn_list.length) {
-        fprintf(f, "extern {\n");
-        p->cur_indent += indent_size;
-        for (int fn_i = 0; fn_i < p->fn_list.length; fn_i += 1) {
-            Fn *fn = p->fn_list.at(fn_i);
-            print_indent(p);
-            fprintf(p->f, "fn %s(", buf_ptr(&fn->name));
-            for (int arg_i = 0; arg_i < fn->arg_count; arg_i += 1) {
-                Arg *arg = &fn->args[arg_i];
-                fprintf(p->f, "%s: %s", buf_ptr(&arg->name), buf_ptr(arg->type));
-                if (arg_i + 1 < fn->arg_count || fn->is_variadic) {
-                    fprintf(p->f, ", ");
-                }
-            }
-            if (fn->is_variadic) {
-                fprintf(p->f, "...");
-            }
-            fprintf(p->f, ")");
-            if (fn->return_type) {
-                fprintf(p->f, " -> %s", buf_ptr(fn->return_type));
-            }
-            fprintf(p->f, ";\n");
-        }
-        p->cur_indent -= indent_size;
-        fprintf(f, "}\n");
-    }
+    ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
+
+    return 0;
 }
src/parseh.hpp
@@ -9,10 +9,9 @@
 #ifndef ZIG_PARSEH_HPP
 #define ZIG_PARSEH_HPP
 
-#include "buffer.hpp"
+#include "all_types.hpp"
 
-#include <stdio.h>
-
-void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f);
+int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv);
+int parse_h_buf(ParseH *parse_h, Buf *buf, const char *libc_include_path);
 
 #endif
src/parser.cpp
@@ -488,23 +488,16 @@ __attribute__ ((noreturn))
 static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const char *format, ...) {
     assert(node->type == NodeTypeAsmExpr);
 
-    ErrorMsg *err = allocate<ErrorMsg>(1);
 
     SrcPos pos = node->data.asm_expr.offset_map.at(offset);
 
-    err->line_start = pos.line;
-    err->column_start = pos.column;
-    err->line_end = -1;
-    err->column_end = -1;
-
     va_list ap;
     va_start(ap, format);
-    err->msg = buf_vprintf(format, ap);
+    Buf *msg = buf_vprintf(format, ap);
     va_end(ap);
 
-    err->path = pc->owner->path;
-    err->source = pc->owner->source_code;
-    err->line_offsets = pc->owner->line_offsets;
+    ErrorMsg *err = err_msg_create_with_line(pc->owner->path, pos.line, pos.column,
+            pc->owner->source_code, pc->owner->line_offsets, msg);
 
     print_err_msg(err, pc->err_color);
     exit(EXIT_FAILURE);
@@ -513,20 +506,16 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const cha
 __attribute__ ((format (printf, 3, 4)))
 __attribute__ ((noreturn))
 static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
-    ErrorMsg *err = allocate<ErrorMsg>(1);
-    err->line_start = token->start_line;
-    err->column_start = token->start_column;
-    err->line_end = -1;
-    err->column_end = -1;
-
     va_list ap;
     va_start(ap, format);
-    err->msg = buf_vprintf(format, ap);
+    Buf *msg = buf_vprintf(format, ap);
     va_end(ap);
 
-    err->path = pc->owner->path;
-    err->source = pc->owner->source_code;
-    err->line_offsets = pc->owner->line_offsets;
+
+    ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column,
+            pc->owner->source_code, pc->owner->line_offsets, msg);
+    err->line_start = token->start_line;
+    err->column_start = token->start_column;
 
     print_err_msg(err, pc->err_color);
     exit(EXIT_FAILURE);
test/run_tests.cpp
@@ -1673,6 +1673,13 @@ fn f(s: []u8) -> []u8 {
 }
     )SOURCE", 1, ".tmp_source.zig:3:5: error: string concatenation requires constant expression");
 
+    add_compile_fail_case("c_import with bogus include", R"SOURCE(
+c_import {
+    @c_include("bogus.h");
+}
+    )SOURCE", 2, ".tmp_source.zig:2:1: error: C import failed",
+                 ".h:1:10: error: 'bogus.h' file not found");
+
 }
 
 static void print_compiler_invocation(TestCase *test_case) {
CMakeLists.txt
@@ -17,7 +17,7 @@ include_directories(${LLVM_INCLUDE_DIRS})
 link_directories(${LLVM_LIBDIRS})
 
 find_package(clang)
-include_directories(${CLANG_INCLUDE_DIR})
+include_directories(${CLANG_INCLUDE_DIRS})
 
 include_directories(
     ${CMAKE_SOURCE_DIR}
@@ -148,7 +148,7 @@ set_target_properties(zig PROPERTIES
     COMPILE_FLAGS ${EXE_CFLAGS})
 target_link_libraries(zig LINK_PUBLIC
     ${LLVM_LIBRARIES}
-    ${CLANG_LIBRARY}
+    ${CLANG_LIBRARIES}
 )
 install(TARGETS zig DESTINATION bin)
 
README.md
@@ -75,7 +75,7 @@ be set to (example below).
 ```
 mkdir build
 cd build
-cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(cc -print-file-name=crt1.o))
+cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(dirname $(cc -print-file-name=crt1.o)))
 make
 make install
 ./run_tests