1 /**
2  * Copyright: Copyright (c) 2015 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 31, 2015
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module clang.Compiler;
8 
9 import std.path;
10 import std.typetuple : staticMap;
11 
12 import clang.c.Index;
13 
14 struct Compiler
15 {
16     private
17     {
18         version (Windows)
19             enum root = `C:\`;
20 
21         else
22             enum root = "/";
23 
24         string virtualPath_;
25         string[] sysRootFlag_;
26 
27         static template toInternalHeader (string file)
28         {
29             enum toInternalHeader = InternalHeader(file, import(file));
30         }
31 
32         static struct InternalHeader
33         {
34             string filename;
35             string content;
36         }
37 
38         enum internalHeaders_ = [
39             staticMap!(
40                 toInternalHeader,
41                 "__stddef_max_align_t.h",
42                 "float.h",
43                 "limits.h",
44                 "stdarg.h",
45                 "stdbool.h",
46                 "stddef.h"
47             )
48         ];
49     }
50 
51     string[] internalFlags ()
52     {
53         import std.algorithm : map;
54         import std.array : array;
55         import std.range : chain;
56 
57         return extraIncludePaths
58             .map!(path => "-I" ~ path)
59             .chain(sysRootFlag)
60             .array;
61     }
62 
63     CXUnsavedFile[] internalHeaders ()
64     {
65         import std.algorithm : map;
66         import std.array : array;
67         import std..string : toStringz;
68 
69         return internalHeaders_.map!((e) {
70             auto path = buildPath(virtualPath, e.filename);
71             return CXUnsavedFile(path.toStringz, e.content.ptr, cast(uint)e.content.length);
72         }).array();
73     }
74 
75 private:
76 
77     string[] extraIncludePaths ()
78     {
79         return [virtualPath];
80     }
81 
82     string virtualPath ()
83     {
84         import std.random;
85         import std.conv;
86 
87         if (virtualPath_.length)
88             return virtualPath_;
89 
90         return virtualPath_ = buildPath(root, uniform(1, 10_000_000).to!string);
91     }
92 
93     string[] sysRootFlag ()
94     {
95         if (sysRootFlag_.length)
96             return sysRootFlag_;
97 
98         version (OSX)
99         {
100             import std..string : strip;
101             import std.array : join;
102             import std.format : format;
103             import std.process : execute;
104 
105             import dstep.core.Exceptions : DStepException;
106 
107             static immutable command = ["xcrun", "--show-sdk-path", "--sdk", "macosx"];
108             const result = execute(command);
109 
110             if (result.status == 0)
111                 return sysRootFlag_ = ["-isysroot", result.output.strip];
112 
113             enum fmt = "Failed get the path of the SDK.\nThe command '%s' " ~
114                 "returned the following output:\n%s";
115 
116             const message = format!fmt(command.join(" "), result.output);
117             throw new DStepException(message);
118         }
119 
120         else
121             return null;
122     }
123 }