Skip to content

Commit 628029e

Browse files
committed
Switch to GCC for portability
1 parent 94d9ee7 commit 628029e

5 files changed

Lines changed: 154 additions & 4 deletions

File tree

FastData.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
</Folder>
8282
<Folder Name="/_Scripts/">
8383
<File Path="Scripts/Build.ps1" />
84+
<File Path="Scripts/Install-Gcc.ps1" />
8485
<File Path="Scripts/Publish.ps1" />
8586
</Folder>
8687
<Project Path="Src/FastData.Benchmarks/FastData.Benchmarks.csproj" />

Scripts/Install-Gcc.ps1

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
$Color = "DarkBlue"
2+
3+
Write-Host -ForegroundColor $Color "Checking g++ availability"
4+
5+
$gcc = Get-Command g++ -ErrorAction SilentlyContinue
6+
if ($gcc)
7+
{
8+
Write-Host -ForegroundColor $Color "g++ found: $( $gcc.Source )"
9+
exit 0
10+
}
11+
12+
Write-Host -ForegroundColor $Color "Installing MinGW-w64 (g++) via winget"
13+
14+
if (-not (Get-Command winget -ErrorAction SilentlyContinue))
15+
{
16+
Write-Host -ForegroundColor Red "winget not found. Install App Installer from Microsoft Store."
17+
exit 1
18+
}
19+
20+
winget install -e --id BrechtSanders.WinLibs.POSIX.MSVCRT --accept-package-agreements --accept-source-agreements
21+
22+
Write-Host -ForegroundColor Yellow "Restart PowerShell and try again."

Src/FastData.Generator.CPlusPlus.Benchmarks/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Globalization;
1+
using System.Globalization;
22
using System.Text;
33
using Genbox.FastData.Enums;
44
using Genbox.FastData.Generator.CPlusPlus.Internal.Framework;
@@ -17,7 +17,7 @@ private static void Main()
1717
string rootDir = Path.Combine(Path.GetTempPath(), "FastData", "CPlusPlus");
1818
TestHelper.CreateOrEmptyDirectory(rootDir);
1919

20-
CPlusPlusCompiler compiler = new CPlusPlusCompiler(true, rootDir);
20+
GccCompiler compiler = new GccCompiler(true, rootDir, true);
2121
StringBuilder sb = new StringBuilder();
2222
sb.AppendLine("""
2323
#include <benchmark/benchmark.h>

Src/FastData.Generator.CPlusPlus.TestHarness/CPlusPlusTestHarness.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ namespace Genbox.FastData.Generator.CPlusPlus.TestHarness;
1313

1414
public sealed class CPlusPlusTestHarness : TestHarnessBase
1515
{
16-
private readonly CPlusPlusCompiler _compiler;
16+
private readonly GccCompiler _compiler;
1717

1818
public CPlusPlusTestHarness() : base("CPlusPlus")
1919
{
2020
string rootDir = Path.Combine(Path.GetTempPath(), "FastData", "CPlusPlus");
2121
Directory.CreateDirectory(rootDir);
22-
_compiler = new CPlusPlusCompiler(false, rootDir);
22+
_compiler = new GccCompiler(false, rootDir, false);
2323
}
2424

2525
public override ICodeGenerator CreateGenerator(string id) => CPlusPlusCodeGenerator.Create(new CPlusPlusCodeGeneratorConfig(id));
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System.Collections.Generic;
2+
using System.IO.Compression;
3+
using Genbox.FastData.InternalShared.Helpers;
4+
using static Genbox.FastData.InternalShared.Helpers.TestHelper;
5+
6+
namespace Genbox.FastData.Generator.CPlusPlus.TestHarness;
7+
8+
public sealed class GccCompiler
9+
{
10+
private readonly string _compiler;
11+
private readonly string _includesPath;
12+
private readonly string _libsPath;
13+
private readonly bool _linkBenchmark;
14+
private readonly bool _release;
15+
private readonly string _rootPath;
16+
17+
public GccCompiler(bool release, string rootDir, bool linkBenchmark)
18+
{
19+
_release = release;
20+
_rootPath = rootDir;
21+
_linkBenchmark = linkBenchmark;
22+
23+
_includesPath = Path.Combine(_rootPath, "Includes");
24+
Directory.CreateDirectory(_includesPath);
25+
26+
string benchPath = Path.Combine(_includesPath, "benchmark");
27+
Directory.CreateDirectory(benchPath);
28+
29+
CopyResource("benchmark.h", Path.Combine(benchPath, "benchmark.h"));
30+
CopyResource("export.h", Path.Combine(benchPath, "export.h"));
31+
32+
_libsPath = Path.Combine(_rootPath, "Libs");
33+
Directory.CreateDirectory(_libsPath);
34+
35+
if (!TryGetCompiler(out _compiler))
36+
throw new InvalidOperationException("No compiler found");
37+
}
38+
39+
private static void CopyResource(string name, string dst)
40+
{
41+
if (File.Exists(dst))
42+
return;
43+
44+
const string ns = "Genbox.FastData.Generator.CPlusPlus.TestHarness.Resources.";
45+
using Stream? stream = typeof(GccCompiler).Assembly.GetManifestResourceStream(ns + name + ".gz");
46+
47+
if (stream == null)
48+
throw new InvalidOperationException("Resource not found");
49+
50+
using GZipStream gz = new GZipStream(stream, CompressionMode.Decompress);
51+
using FileStream fs = File.OpenWrite(dst);
52+
53+
gz.CopyTo(fs);
54+
}
55+
56+
private static bool TryGetCompiler(out string compiler)
57+
{
58+
if (TryRunProcess("g++.exe", "--version"))
59+
{
60+
compiler = "g++.exe";
61+
return true;
62+
}
63+
64+
if (TryRunProcess("g++", "--version"))
65+
{
66+
compiler = "g++";
67+
return true;
68+
}
69+
70+
compiler = string.Empty;
71+
return false;
72+
}
73+
74+
private ProcessResult CompileGcc(string src, string dst)
75+
{
76+
string args = BuildArgs(src, dst);
77+
return RunProcess(_compiler, args);
78+
}
79+
80+
private string BuildArgs(string src, string dst)
81+
{
82+
List<string> args = new List<string>
83+
{
84+
$"\"{src}\"",
85+
"-std=c++17",
86+
_release ? "-O2" : "-O1",
87+
"-DNDEBUG",
88+
$"-I \"{_includesPath}\""
89+
};
90+
91+
if (_linkBenchmark)
92+
{
93+
args.Add("-DBENCHMARK_STATIC_DEFINE");
94+
args.Add($"-L \"{_libsPath}\"");
95+
args.Add("-lbenchmark");
96+
97+
if (OperatingSystem.IsWindows())
98+
args.Add("-lshlwapi");
99+
else
100+
args.Add("-pthread");
101+
}
102+
103+
args.Add($"-o \"{dst}\"");
104+
105+
return string.Join(" ", args);
106+
}
107+
108+
public string Compile(string fileId, string source)
109+
{
110+
string srcFile = Path.Combine(_rootPath, fileId + ".cpp");
111+
string dstFile = Path.Combine(_rootPath, OperatingSystem.IsWindows() ? fileId + ".exe" : fileId);
112+
113+
//If the source hasn't changed, we skip compilation
114+
if (!TryWriteFile(srcFile, source) && File.Exists(dstFile))
115+
return dstFile;
116+
117+
ProcessResult res = CompileGcc(srcFile, dstFile);
118+
119+
if (res.ExitCode != 0)
120+
{
121+
File.Delete(dstFile); // We need to delete the file on failure to avoid returning the cache on next run
122+
throw new InvalidOperationException($"Failed to compile. Exit code: {res.ExitCode}\nSTDOUT:\n{res.StandardOutput}\nSTDERR:\n{res.StandardError}");
123+
}
124+
125+
return dstFile;
126+
}
127+
}

0 commit comments

Comments
 (0)