diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,18 +1,100 @@
-{-
-Copyright 2014 Google Inc. All Rights Reserved.
+{-|
+Module      : Main
+Description : Setup script for clang-pure build
+Copyright   : (C) Richard Cook, Patrick Chilton 2016
+Licence     : Apache 2.0
+Maintainer  : rcook@rcook.org
+Stability   : experimental
+Portability : portable
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+This setup script adds a configuration hook to the build process to discover
+the LLVM library and include paths from the standard system-wide installation
+location or from an alternative location if overridden with both the
+@CLANG_PURE_LLVM_LIB_DIR@ and @CLANG_PURE_LLVM_INCLUDE_DIR@ environment variables.
+-}
 
-    http://www.apache.org/licenses/LICENSE-2.0
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# OPTIONS_GHC -Wall #-}
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--}
+module Main (main) where
 
+import Control.Exception
+import Control.Monad
+import Distribution.PackageDescription
 import Distribution.Simple
-main = defaultMain
+import Distribution.Simple.LocalBuildInfo
+import Distribution.Simple.Setup
+import System.Environment
+import System.IO.Error
+import System.Process
+
+data SetupException = SetupException String deriving Show
+
+instance Exception SetupException
+
+data LLVMPathInfo = LLVMPathInfo
+  { llvmLibraryDir :: FilePath
+  , llvmIncludeDir :: FilePath
+  } deriving (Eq, Ord, Show)
+
+llvmLibDirEnvVarName :: String
+llvmLibDirEnvVarName = "CLANG_PURE_LLVM_LIB_DIR"
+
+llvmIncludeDirEnvVarName :: String
+llvmIncludeDirEnvVarName = "CLANG_PURE_LLVM_INCLUDE_DIR"
+
+findLLVMConfigPaths :: IO LLVMPathInfo
+findLLVMConfigPaths = do
+  let llvmConfigCandidates =
+        "llvm-config" :
+          [ "llvm-config-" ++ show major ++ "." ++ show minor
+          | major <- [9,8..3 :: Int]
+          , minor <- [9,8..0 :: Int]
+          ]
+  let tryCandidates [] = throwIO $ SetupException "Could not find llvm-config."
+      tryCandidates (llvmConfig : candidates) = do
+        llvmConfigResult <- tryJust (guard . isDoesNotExistError) (readProcess llvmConfig ["--libdir", "--includedir"] "")
+        case llvmConfigResult of
+          Left _ -> tryCandidates candidates
+          Right llvmConfigOutput -> case lines llvmConfigOutput of
+            [ libraryDir, includeDir ] -> return $ LLVMPathInfo libraryDir includeDir
+            _ -> throwIO $ SetupException "Unexpected llvm-config output."
+  tryCandidates llvmConfigCandidates
+
+getLLVMPathInfo :: IO LLVMPathInfo
+getLLVMPathInfo = do
+  m'llvmLibDirEnvVar <- lookupEnv llvmLibDirEnvVarName
+  m'llvmIncludeDirEnvVar <- lookupEnv llvmIncludeDirEnvVarName
+  case (m'llvmLibDirEnvVar, m'llvmIncludeDirEnvVar) of
+    ( Just libraryDir, Just includeDir ) -> return $ LLVMPathInfo libraryDir includeDir
+    _ -> findLLVMConfigPaths
+
+clangPureConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
+clangPureConfHook (d, bi) flags = do
+  localBuildInfo <- confHook simpleUserHooks (d, bi) flags
+  let pd = localPkgDescr localBuildInfo
+  let Just lib = library pd
+  let lbi = libBuildInfo lib
+
+  LLVMPathInfo{..} <- getLLVMPathInfo
+
+  return localBuildInfo {
+    localPkgDescr = pd {
+      library = Just $ lib {
+        libBuildInfo = lbi
+        { includeDirs = llvmIncludeDir : includeDirs lbi
+        , extraLibDirs = llvmLibraryDir : extraLibDirs lbi
+        , cSources = -- define the generated c-sources here so that they don't get picked up by sdist
+#ifdef mingw32_HOST_OS
+            ["srcLanguageCClangInternalFFI.c"] -- work around a bug in inline-c (?)
+#else
+            ["src/Language/C/Clang/Internal/FFI.c"]
+#endif
+        }
+      }
+    }
+  }
+
+main :: IO ()
+main = defaultMainWithHooks simpleUserHooks { confHook = clangPureConfHook }
diff --git a/clang-pure.cabal b/clang-pure.cabal
--- a/clang-pure.cabal
+++ b/clang-pure.cabal
@@ -1,5 +1,5 @@
 name:                  clang-pure
-version:               0.1.0.2
+version:               0.1.0.3
 synopsis:              Pure C++ code analysis with libclang
 description:
   Pure C++ code analysis with libclang.
@@ -12,7 +12,7 @@
 maintainer:            chpatrick@gmail.com
 copyright:             Copyright 2014 Google Inc. All Rights Reserved.
 category:              Language
-build-type:            Simple
+build-type:            Custom
 -- extra-source-files:  
 cabal-version:         >=1.10
 extra-source-files:  cbits/utils.h
@@ -53,7 +53,6 @@
   hs-source-dirs:      src/
   build-tools:         hsc2hs
   default-language:    Haskell2010
-  c-sources:           src/Language/C/Clang/Internal/FFI.c
   include-dirs:        cbits/
   cc-options:          -Wall
   extra-libraries:     clang
diff --git a/src/Language/C/Clang/Internal/FFI.c b/src/Language/C/Clang/Internal/FFI.c
deleted file mode 100644
--- a/src/Language/C/Clang/Internal/FFI.c
+++ /dev/null
@@ -1,201 +0,0 @@
-
-#include "stdlib.h"
-
-#include "clang-c/Index.h"
-
-#include "utils.h"
-
-CXIndex inline_c_Language_C_Clang_Internal_FFI_0_bbb74fcef49f2173e226e50e36672d4cf20c26cf() {
-return ( clang_createIndex(0, 1) );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_1_1b457d61428a48cbfcc276ae3010234ac1f6d4aa(CXIndex idxp_inline_c_0, char * cPath_inline_c_1, const char *const* cArgs_inline_c_2, long cArgs_inline_c_3, CXTranslationUnit * tupp_inline_c_4) {
-return (
-        clang_parseTranslationUnit2(
-          idxp_inline_c_0,
-          cPath_inline_c_1,
-          cArgs_inline_c_2, cArgs_inline_c_3,
-          NULL, 0,
-          0,
-          tupp_inline_c_4)
-        );
-}
-
-
-CXCursor * inline_c_Language_C_Clang_Internal_FFI_2_0a41a8f07961cb59fe1e6c0eff8cfa59bd837a75(CXTranslationUnit tup_inline_c_0) {
-return ( ALLOC(
-      clang_getTranslationUnitCursor(tup_inline_c_0)
-      ));
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_3_26dd79d987cb18fd9b60848f6fef9651ea596325(CXCursor * cp_inline_c_0, void (* visitChild_inline_c_1)(CXCursor *)) {
-
-    clang_visitChildren(
-      *cp_inline_c_0,
-      visit_haskell,
-      visitChild_inline_c_1)
-    ;
-}
-
-
-const char * inline_c_Language_C_Clang_Internal_FFI_4_f0fd60d11137e5526d0d29649cf6a80152af4ee5(CXString * cxsp_inline_c_0) {
-return ( clang_getCString(*cxsp_inline_c_0) );
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_5_aaa15c5f7cc155f34bd7888c71f492c421ec921f(CXString * cxsp_inline_c_0) {
- clang_disposeString(*cxsp_inline_c_0) ;
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_6_654625d7632bdac1227544395da0595f7f2bd246(CXString * cxsp_inline_c_0, CXCursor * cp_inline_c_1) {
-
-    *cxsp_inline_c_0 = clang_getCursorSpelling(*cp_inline_c_1);
-    
-}
-
-
-CXSourceRange * inline_c_Language_C_Clang_Internal_FFI_7_4a16e3c5ff5e0e56ede260ae320b6e3fcb519be8(CXCursor * cp_inline_c_0) {
-
-    CXSourceRange sr = clang_getCursorExtent(*cp_inline_c_0);
-    if (clang_Range_isNull(sr)) {
-      return NULL;
-    }
-
-    return ALLOC(sr);
-    
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_8_654cc4d7a15ca22098e2b76991025bfea8e2a7c1(CXString * cxsp_inline_c_0, CXCursor * cp_inline_c_1) {
-
-    *cxsp_inline_c_0 = clang_getCursorUSR(*cp_inline_c_1);
-    
-}
-
-
-CXCursor * inline_c_Language_C_Clang_Internal_FFI_9_51239005fc283577baef0a3a25ccc32c163474ff(CXCursor * cp_inline_c_0) {
-
-    CXCursor ref = clang_getCursorReferenced(*cp_inline_c_0);
-    if (clang_Cursor_isNull(ref)) {
-      return NULL;
-    }
-
-    return ALLOC(ref);
-    
-}
-
-
-CXSourceLocation * inline_c_Language_C_Clang_Internal_FFI_10_01174c5fad196653eadc0d75887813449f7c6c44(CXSourceRange * srp_inline_c_0) {
-return ( ALLOC(
-    clang_getRangeStart(*srp_inline_c_0)
-    ));
-}
-
-
-CXSourceLocation * inline_c_Language_C_Clang_Internal_FFI_11_2506f272dc0f8ef468c4c127a2e3a5614300afbd(CXSourceRange * srp_inline_c_0) {
-return ( ALLOC(
-    clang_getRangeEnd(*srp_inline_c_0)
-    ));
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_12_9be112e443ca74d8bc4c831343b6891c4295dcbc(CXSourceLocation * slp_inline_c_0, CXFile * fp_inline_c_1, unsigned * lp_inline_c_2, unsigned * cp_inline_c_3, unsigned * offp_inline_c_4) {
-
-      clang_getSpellingLocation(
-        *slp_inline_c_0,
-        fp_inline_c_1,
-        lp_inline_c_2,
-        cp_inline_c_3,
-        offp_inline_c_4)
-      ;
-}
-
-
-CXFile inline_c_Language_C_Clang_Internal_FFI_13_1dc5653d3b316566a228a71d6efa749cc40c291a(CXTranslationUnit tup_inline_c_0, const char * fn_inline_c_1) {
-return (
-    clang_getFile(tup_inline_c_0, fn_inline_c_1)
-    );
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_14_b988619e4ed48ddcd0c83f2aa9e6177263942258(CXString * cxsp_inline_c_0, CXFile fp_inline_c_1) {
-
-    *cxsp_inline_c_0 = clang_getFileName(fp_inline_c_1);
-    
-}
-
-
-CXType * inline_c_Language_C_Clang_Internal_FFI_15_28d3d6c8bb9cdf93c0c25a3a8ea6431777e40068(CXCursor * cp_inline_c_0) {
-
-    CXType type = clang_getCursorType(*cp_inline_c_0);
-
-    if (type.kind == CXType_Invalid) {
-      return NULL;
-    }
-
-    return ALLOC(type);
-    
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_16_ea90d6d14f81725ca6b378b32b5f0a8692cb183e(CXString * cxsp_inline_c_0, CXType * tp_inline_c_1) {
- *cxsp_inline_c_0 = clang_getTypeSpelling(*tp_inline_c_1); ;
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_17_ea0cc06208c508bf31fdb2025f7ab1764e2212ba(CXTranslationUnit tup_inline_c_0, CXSourceRange * srp_inline_c_1, CXToken ** tspp_inline_c_2, unsigned * tnp_inline_c_3) {
-
-          clang_tokenize(
-            tup_inline_c_0, 
-            *srp_inline_c_1,
-            tspp_inline_c_2,
-            tnp_inline_c_3);
-          ;
-}
-
-
-void inline_c_Language_C_Clang_Internal_FFI_18_565f5dad2370e065f27bdc06f712faa17fd7c3d4(CXString * cxsp_inline_c_0, CXTranslationUnit tup_inline_c_1, CXToken * tp_inline_c_2) {
-
-          *cxsp_inline_c_0 = clang_getTokenSpelling(
-            tup_inline_c_1,
-            *tp_inline_c_2);
-          
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_19_75619e5975a8539d6a4f8a3f168e800a2f60e6be(CXSourceLocation * lp_inline_c_0) {
-return (
-    clang_Location_isInSystemHeader(*lp_inline_c_0)
-    );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_20_0dce75380f88691f9cf6d3de92251c770e071385(CXSourceLocation * lp_inline_c_0) {
-return (
-    clang_Location_isFromMainFile(*lp_inline_c_0)
-    );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_21_7c43b31e73b16206ea9c68efab47d1040d99de95(CXType * lp_inline_c_0, CXType * rp_inline_c_1) {
-return ( clang_equalTypes(*lp_inline_c_0, *rp_inline_c_1) );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_22_1dc05152878244ed78aba394ab8e0fefccda1dd7(CXSourceLocation * lp_inline_c_0, CXSourceLocation * rp_inline_c_1) {
-return ( clang_equalLocations(*lp_inline_c_0, *rp_inline_c_1) );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_23_51cac3d3c6607e337c0c1a424533416af56247d8(CXSourceRange * lp_inline_c_0, CXSourceRange * rp_inline_c_1) {
-return ( clang_equalRanges(*lp_inline_c_0, *rp_inline_c_1) );
-}
-
-
-int inline_c_Language_C_Clang_Internal_FFI_24_6edd96afecef70cb0090f782283f6f6a9cf124dc(CXCursor * lp_inline_c_0, CXCursor * rp_inline_c_1) {
-return ( clang_equalCursors(*lp_inline_c_0, *rp_inline_c_1) );
-}
-
