forked from SharpGenTools/SharpGenTools
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCppHeaderGenerator.cs
More file actions
143 lines (112 loc) · 4.86 KB
/
Copy pathCppHeaderGenerator.cs
File metadata and controls
143 lines (112 loc) · 4.86 KB
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SharpGen.Config;
using SharpGen.Logging;
namespace SharpGen.Parser;
public sealed class CppHeaderGenerator
{
private readonly Ioc ioc;
private const string Version = "1.1";
private Logger Logger => ioc.Logger;
private string OutputPath { get; }
public CppHeaderGenerator(string outputPath, Ioc ioc)
{
OutputPath = outputPath;
this.ioc = ioc ?? throw new ArgumentNullException(nameof(ioc));
}
public readonly struct Result
{
public HashSet<ConfigFile> UpdatedConfigs { get; }
public string Prologue { get; }
public Result(HashSet<ConfigFile> updatedConfigs, string prolog)
{
UpdatedConfigs = updatedConfigs ?? throw new ArgumentNullException(nameof(updatedConfigs));
Prologue = prolog ?? throw new ArgumentNullException(nameof(prolog));
}
}
public Result GenerateCppHeaders(ConfigFile configRoot, IReadOnlyCollection<ConfigFile> configsWithIncludes,
ISet<ConfigFile> configsWithExtensionHeaders)
{
var updatedConfigs = new HashSet<ConfigFile>(ConfigFile.IdComparer);
var prologue = GeneratePrologue(configRoot);
// Dump includes
foreach (var configFile in configsWithIncludes)
{
var outputConfigStr = GenerateIncludeConfigContents(
configRoot, configFile, configsWithIncludes, configsWithExtensionHeaders, prologue
);
var fileName = Path.Combine(OutputPath, configFile.HeaderFileName);
// Test if Last config file was generated. If not, then we need to generate it
// If it exists, then we need to test if it is the same than previous run
bool isConfigUpdated;
if (File.Exists(fileName))
isConfigUpdated = outputConfigStr != File.ReadAllText(fileName);
else
isConfigUpdated = true;
// Small optim: just write the header file when the file is updated or new
if (!isConfigUpdated)
continue;
Logger.Message("Config file changed for C++ headers [{0}]/[{1}]", configFile.Id, configFile.FilePath);
updatedConfigs.Add(configFile);
File.WriteAllText(fileName, outputConfigStr, Encoding.UTF8);
}
return new Result(updatedConfigs, prologue);
}
private static string GeneratePrologue(ConfigFile configRoot)
{
var prolog = new StringBuilder();
foreach (var prologItem in configRoot.ConfigFilesLoaded.SelectMany(file => file.IncludeProlog))
{
prolog.Append(prologItem);
}
prolog.AppendLine();
return prolog.ToString();
}
private static string GenerateIncludeConfigContents(ConfigFile configRoot, ConfigFile configFile,
IReadOnlyCollection<ConfigFile> configsWithIncludes,
ISet<ConfigFile> configsWithExtensionHeaders,
string prolog)
{
using var outputConfig = new StringWriter();
outputConfig.WriteLine("// SharpGen include config [{0}] - Version {1}", configFile.Id, Version);
if (configRoot.Id == configFile.Id)
outputConfig.Write(prolog);
// Write includes
foreach (var includeRule in configFile.Includes)
{
if (!string.IsNullOrEmpty(includeRule.Pre))
{
outputConfig.WriteLine(includeRule.Pre);
}
outputConfig.WriteLine("#include \"{0}\"", includeRule.File);
if (!string.IsNullOrEmpty(includeRule.Post))
{
outputConfig.WriteLine(includeRule.Post);
}
}
// Write includes to references
foreach (var reference in configFile.References)
{
if (configsWithIncludes.Contains(reference))
outputConfig.WriteLine("#include \"{0}\"", reference.HeaderFileName);
}
// Dump Create from macros
if (configsWithExtensionHeaders.Contains(configFile))
{
foreach (var typeBaseRule in configFile.Extension)
{
if (typeBaseRule.GeneratesExtensionHeader())
outputConfig.WriteLine("// {0}", typeBaseRule);
}
// Include extension header if it exists
// so we can generate extension headers without needing them to already exist.
outputConfig.WriteLine("#if __has_include(\"{0}\")", configFile.ExtensionFileName);
outputConfig.WriteLine("#include \"{0}\"", configFile.ExtensionFileName);
outputConfig.WriteLine("#endif");
}
return outputConfig.ToString();
}
}