GetConfigFeatures (string path, string featuresRegex)
{
var features = new List ();
if (File.Exists (path))
{
var regex = new Regex (featuresRegex);
using (StreamReader reader = new StreamReader (path))
{
string line;
while ((line = reader.ReadLine ()) != null)
{
var match = regex.Match (line);
if (match != null && match.Success)
{
if (match.Groups != null && match.Groups.Count == 1)
{
var configLine = match.Groups[0].ToString ();
if (!String.IsNullOrEmpty (configLine))
{
var configItems = configLine.Trim ().Split (' ');
if (configItems != null && configItems.Length == 3)
{
// Second item should be the define.
features.Add (configItems[1]);
}
}
}
}
}
}
}
return features;
}
string [] GetEnabledConfigFeatures (string path, string enableDefines)
{
string [] supportedFeatures = { "ENABLE_ICALL_SYMBOL_MAP",
"ENABLE_LLVM",
"ENABLE_LLVM_RUNTIME",
"ENABLE_HYBRID_SUSPEND",
"ENABLE_COOP_SUSPEND",
"ENABLE_NETCORE" };
var enableFeatures = GetConfigFeatures(path, ".*#define.*ENABLE_.*1");
if (enableDefines != null)
enableFeatures.AddRange (enableDefines.Split (';'));
// Only keep supported features on Windows platforms using MSVC.
var features = new List ();
foreach (var feature in enableFeatures)
if (Array.Exists(supportedFeatures, s => String.CompareOrdinal (s,feature) == 0))
features.Add(feature);
return features.ToArray ();
}
string [] GetDisabledConfigFeatures (string path)
{
return GetConfigFeatures(path, ".*#define.*DISABLE_.*1").ToArray ();
}
void CreateConfigUsingTemplate (string templatePath, string targetPath, string [] disabledDefines, string [] enabledDefines, string [] haveDefines, string monoVersion, string monoCorlibVersion)
{
string tempFilePath = "";
try
{
if (File.Exists (templatePath))
{
var disabledDefinesRegex = new Regex (".*@DISABLE_DEFINES@.*");
var enabledDefinesRegex = new Regex (".*@ENABLE_DEFINES@.*");
var haveDefinesRegex = new Regex (".*@HAVE_DEFINES.*");
var definesList = new List>
{
new Tuple(disabledDefinesRegex, disabledDefines),
new Tuple(enabledDefinesRegex, enabledDefines),
new Tuple(haveDefinesRegex, haveDefines)
};
var monoCorlibVersions = new string [] {
".*#MONO_CORLIB_VERSION#.*",
"#MONO_CORLIB_VERSION#",
monoCorlibVersion
};
var monoCorlibVersionRegex = new Regex (monoCorlibVersions[0]);
var monoVersions = new string [] {
".*#MONO_VERSION#.*",
"#MONO_VERSION#",
monoVersion
};
var monoVersionRegex = new Regex (monoVersions[0]);
var versionList = new List>
{
new Tuple(monoCorlibVersionRegex, monoCorlibVersions),
new Tuple(monoVersionRegex, monoVersions)
};
tempFilePath = Path.GetTempFileName ();
using (StreamReader reader = new StreamReader (templatePath))
using (StreamWriter writer = new StreamWriter (tempFilePath))
{
string line;
Match match;
while ((line = reader.ReadLine ()) != null)
{
var replaced = false;
foreach (var defines in definesList)
{
match = defines.Item1.Match (line);
if (match != null && match.Success && defines.Item2 != null)
{
// Replace with disabled defines.
foreach (var define in defines.Item2)
{
writer.WriteLine ("#ifndef {0}", define);
writer.WriteLine ("#define {0} 1", define);
writer.WriteLine ("#endif");
}
replaced = true;
break;
}
}
if (!replaced)
{
foreach (var version in versionList)
{
match = version.Item1.Match (line);
if (match != null && match.Success)
{
writer.WriteLine (line.Replace(version.Item2[1], version.Item2[2]));
replaced = true;
break;
}
}
}
if (!replaced)
writer.WriteLine (line);
}
}
bool overwrite = true;
if (File.Exists (targetPath))
{
if (File.ReadAllBytes (tempFilePath).SequenceEqual (File.ReadAllBytes (targetPath)))
overwrite = false;
}
if (overwrite)
File.Copy (tempFilePath, targetPath, true);
}
}
finally
{
if (!String.IsNullOrEmpty (tempFilePath))
File.Delete (tempFilePath);
}
}
void CreateVersionFile (string targetFile)
{
string tempFile = "";
try
{
tempFile = Path.GetTempFileName ();
using (StreamWriter writer = new StreamWriter (tempFile))
{
writer.WriteLine ("#define FULL_VERSION \"Visual Studio built mono\"");
}
bool overwrite = true;
if (File.Exists (targetFile))
{
if (File.ReadAllBytes (tempFile).SequenceEqual (File.ReadAllBytes (targetFile)))
overwrite = false;
}
if (overwrite)
File.Copy (tempFile, targetFile, true);
}
finally
{
if (!String.IsNullOrEmpty (tempFile))
File.Delete (tempFile);
}
}
bool BackupConfigFile (string sourceConfigFile, string targetConfigFile)
{
bool result = false;
if (File.Exists (sourceConfigFile))
{
var includesCygconfig = new Regex (".*#include \"cygconfig.h\".*");
var allText = File.ReadAllText (sourceConfigFile);
var match = includesCygconfig.Match (allText);
if (match == null || !match.Success)
{
File.Copy (sourceConfigFile, targetConfigFile, true);
result = true;
}
}
return result;
}
public string ConfigFileRoot { get; set; }
public string MonoVersion { get; set; }
public string MonoCorlibVersion { get; set; }
public string DisableDefines { get; set; }
public string EnableDefines { get; set; }
public string HaveDefines { get; set; }
public override bool Execute ()
{
if (String.IsNullOrEmpty (ConfigFileRoot))
{
Log.LogError("Missing ConfigFileRoot");
return false;
}
if (String.IsNullOrEmpty (MonoVersion))
{
Log.LogError("Missing MonoVersion");
return false;
}
if (String.IsNullOrEmpty (MonoCorlibVersion))
{
Log.LogError("Missing MonoCorlibVersion");
return false;
}
string configFile = Path.Combine (ConfigFileRoot, @"config.h");
string cygConfigFile = Path.Combine (ConfigFileRoot, @"cygconfig.h");
string winConfigFile = Path.Combine (ConfigFileRoot, @"winconfig.h");
string versionFile = Path.Combine (ConfigFileRoot, @"mono\mini\version.h");
Log.LogMessage (MessageImportance.High, "Setting up Mono configuration headers...");
BackupConfigFile (configFile, cygConfigFile);
var disableDefines = GetDisabledConfigFeatures (cygConfigFile);
var enableDefines = GetEnabledConfigFeatures (cygConfigFile, EnableDefines);
var haveDefines = (HaveDefines != null) ? HaveDefines.Split (';') : null;
CreateConfigUsingTemplate (winConfigFile, configFile, disableDefines, enableDefines, haveDefines, MonoVersion, MonoCorlibVersion);
CreateVersionFile (versionFile);
Log.LogMessage (MessageImportance.High, "Successfully setup Mono configuration headers {0} and {1} from {2}.", configFile, versionFile, winConfigFile);
return true;
}
}
]]>