| 1 |
import std.stdio; |
|---|
| 2 |
import std.utf; |
|---|
| 3 |
import std.file; |
|---|
| 4 |
import std.path; |
|---|
| 5 |
import std.algorithm; |
|---|
| 6 |
import std.string; |
|---|
| 7 |
import std.process; |
|---|
| 8 |
import core.stdc.ctype; |
|---|
| 9 |
import std.c.windows.windows; |
|---|
| 10 |
|
|---|
| 11 |
string compiler = "dmd"; |
|---|
| 12 |
|
|---|
| 13 |
class Test |
|---|
| 14 |
{ |
|---|
| 15 |
enum EXTRA_SOURCES = "EXTRA_SOURCES"; |
|---|
| 16 |
enum COMPILE_SEPARATELY = "COMPILE_SEPARATELY"; |
|---|
| 17 |
enum PERMUTE_ARGS = "PERMUTE_ARGS"; |
|---|
| 18 |
enum REQUIRED_ARGS = "REQUIRED_ARGS"; |
|---|
| 19 |
enum POST_SCRIPT = "POST_SCRIPT"; |
|---|
| 20 |
enum EXECUTE_ARGS = "EXECUTE_ARGS"; |
|---|
| 21 |
|
|---|
| 22 |
this(string path, string outputDir) |
|---|
| 23 |
{ |
|---|
| 24 |
this.outputDir = outputDir; |
|---|
| 25 |
this.baseDir = dirname(path); |
|---|
| 26 |
|
|---|
| 27 |
this.baseName = getBaseName(path); |
|---|
| 28 |
this.name = getName(baseName); |
|---|
| 29 |
|
|---|
| 30 |
this.fileNames ~= baseName; |
|---|
| 31 |
|
|---|
| 32 |
auto file = File(path); |
|---|
| 33 |
while (true) { |
|---|
| 34 |
auto line = file.readln(); |
|---|
| 35 |
if (!line.startsWith("// ")) { |
|---|
| 36 |
break; |
|---|
| 37 |
} |
|---|
| 38 |
|
|---|
| 39 |
line = trim(line[3..$]); |
|---|
| 40 |
if (line.startsWith(EXTRA_SOURCES)) { |
|---|
| 41 |
fileNames ~= split(line[EXTRA_SOURCES.length + 2..$], " "); |
|---|
| 42 |
} else if (line.startsWith(COMPILE_SEPARATELY)) { |
|---|
| 43 |
compileSeparately = true; |
|---|
| 44 |
} else if (line.startsWith(EXECUTE_ARGS)) { |
|---|
| 45 |
executeArgs = line[EXECUTE_ARGS.length + 2..$]; |
|---|
| 46 |
} else if (line.startsWith(PERMUTE_ARGS)) { |
|---|
| 47 |
// ignore for now |
|---|
| 48 |
} else if (line.startsWith(REQUIRED_ARGS)) { |
|---|
| 49 |
requiredArgs = line[REQUIRED_ARGS.length + 2..$]; |
|---|
| 50 |
} else if (line.startsWith(POST_SCRIPT)) { |
|---|
| 51 |
// ignore for now |
|---|
| 52 |
} else { |
|---|
| 53 |
continue; |
|---|
| 54 |
} |
|---|
| 55 |
} |
|---|
| 56 |
} |
|---|
| 57 |
|
|---|
| 58 |
private string prefix() |
|---|
| 59 |
{ |
|---|
| 60 |
return std.string.format(compiler ~ " -od%s -I%s %s", outputDir, baseDir, requiredArgs); |
|---|
| 61 |
} |
|---|
| 62 |
|
|---|
| 63 |
private string csuffix(string fileName) |
|---|
| 64 |
{ |
|---|
| 65 |
// output to console |
|---|
| 66 |
return ""; //std.string.format(" > %s\\%s.clog", outputDir, getBaseName(fileName)); |
|---|
| 67 |
} |
|---|
| 68 |
|
|---|
| 69 |
private string lsuffix(string fileName) |
|---|
| 70 |
{ |
|---|
| 71 |
return std.string.format(" > %s\\%s.llog", outputDir, getBaseName(fileName)); |
|---|
| 72 |
} |
|---|
| 73 |
|
|---|
| 74 |
private string output() |
|---|
| 75 |
{ |
|---|
| 76 |
return std.string.format(" -of%s\\%s.exe", outputDir, name); |
|---|
| 77 |
} |
|---|
| 78 |
|
|---|
| 79 |
private void execute(string command) |
|---|
| 80 |
{ |
|---|
| 81 |
system(command); |
|---|
| 82 |
} |
|---|
| 83 |
|
|---|
| 84 |
void compile() |
|---|
| 85 |
{ |
|---|
| 86 |
if (compileSeparately) { |
|---|
| 87 |
string link_command = compiler ~ output(); |
|---|
| 88 |
foreach (fileName; fileNames) { |
|---|
| 89 |
string compile_command = prefix(); |
|---|
| 90 |
|
|---|
| 91 |
compile_command ~= std.string.format(" %s\\%s -c", baseDir, fileName); |
|---|
| 92 |
compile_command ~= csuffix(fileName); |
|---|
| 93 |
|
|---|
| 94 |
execute(compile_command); |
|---|
| 95 |
link_command ~= std.string.format(" %s\\%s.obj", outputDir, getName(getBaseName(fileName))); |
|---|
| 96 |
} |
|---|
| 97 |
|
|---|
| 98 |
link_command ~= lsuffix(baseName); |
|---|
| 99 |
|
|---|
| 100 |
execute(link_command); |
|---|
| 101 |
} else { |
|---|
| 102 |
string compile_command = prefix(); |
|---|
| 103 |
foreach (fileName; fileNames) { |
|---|
| 104 |
compile_command ~= std.string.format(" %s\\%s", baseDir, fileName); |
|---|
| 105 |
} |
|---|
| 106 |
|
|---|
| 107 |
compile_command ~= output(); |
|---|
| 108 |
compile_command ~= csuffix(baseName); |
|---|
| 109 |
|
|---|
| 110 |
execute(compile_command); |
|---|
| 111 |
} |
|---|
| 112 |
} |
|---|
| 113 |
|
|---|
| 114 |
private string[] fileNames; |
|---|
| 115 |
|
|---|
| 116 |
private string name; |
|---|
| 117 |
private string baseName; |
|---|
| 118 |
private string outputDir; |
|---|
| 119 |
private string baseDir; |
|---|
| 120 |
private string requiredArgs; |
|---|
| 121 |
private string executeArgs; |
|---|
| 122 |
|
|---|
| 123 |
private bool compileSeparately = false; |
|---|
| 124 |
} |
|---|
| 125 |
|
|---|
| 126 |
class RunnableTest : Test |
|---|
| 127 |
{ |
|---|
| 128 |
this(string path, string outputDir) |
|---|
| 129 |
{ |
|---|
| 130 |
super(path, outputDir); |
|---|
| 131 |
} |
|---|
| 132 |
|
|---|
| 133 |
void run() |
|---|
| 134 |
{ |
|---|
| 135 |
string run_command = std.string.format("%s\\%s.exe %s > %s\\%s.exe.rlog", outputDir, name, executeArgs, outputDir, name); |
|---|
| 136 |
execute(run_command); |
|---|
| 137 |
} |
|---|
| 138 |
} |
|---|
| 139 |
|
|---|
| 140 |
int main(string[] args) |
|---|
| 141 |
{ |
|---|
| 142 |
auto runnable_tests = wildcard("runnable/*.d"/*, "runnable/*.html", "runnable/*.sh"*/); |
|---|
| 143 |
auto runnable_test_results = map!q{"result/" ~ a ~ ".out"}(runnable_tests); |
|---|
| 144 |
|
|---|
| 145 |
auto outputDir = "result"; |
|---|
| 146 |
|
|---|
| 147 |
if (args.length >= 2) { |
|---|
| 148 |
compiler = args[1]; |
|---|
| 149 |
} else { |
|---|
| 150 |
// compiler = "dmd"; // value by default |
|---|
| 151 |
} |
|---|
| 152 |
|
|---|
| 153 |
foreach (fileName; runnable_tests) { |
|---|
| 154 |
//fileName = "runnable\\a18.d"; |
|---|
| 155 |
writeln("testing ", fileName); |
|---|
| 156 |
auto test = new RunnableTest(fileName, outputDir); |
|---|
| 157 |
test.compile(); |
|---|
| 158 |
// test.run(); |
|---|
| 159 |
// break; |
|---|
| 160 |
} |
|---|
| 161 |
|
|---|
| 162 |
return 0; |
|---|
| 163 |
} |
|---|
| 164 |
|
|---|
| 165 |
string[] wildcard(string[] paths...) |
|---|
| 166 |
{ |
|---|
| 167 |
string[] fileNames; |
|---|
| 168 |
|
|---|
| 169 |
foreach (path; paths) { |
|---|
| 170 |
filter(path, (string fileName) { fileNames ~= fileName; return true; }); |
|---|
| 171 |
} |
|---|
| 172 |
|
|---|
| 173 |
return fileNames; |
|---|
| 174 |
} |
|---|
| 175 |
|
|---|
| 176 |
string trimLeft(string s) |
|---|
| 177 |
{ |
|---|
| 178 |
for (int i = 0; i < s.length; ++i) { |
|---|
| 179 |
if (!isspace(s[i])) { |
|---|
| 180 |
return s[i..$]; |
|---|
| 181 |
} |
|---|
| 182 |
} |
|---|
| 183 |
|
|---|
| 184 |
return null; |
|---|
| 185 |
} |
|---|
| 186 |
|
|---|
| 187 |
string trimRight(string s) |
|---|
| 188 |
{ |
|---|
| 189 |
for (int i = s.length - 1; i >= 0; --i) { |
|---|
| 190 |
if (!isspace(s[i])) { |
|---|
| 191 |
return s[0..i + 1]; |
|---|
| 192 |
} |
|---|
| 193 |
} |
|---|
| 194 |
|
|---|
| 195 |
return null; |
|---|
| 196 |
} |
|---|
| 197 |
|
|---|
| 198 |
string trim(string s) |
|---|
| 199 |
{ |
|---|
| 200 |
return trimLeft(trimRight(s)); |
|---|
| 201 |
} |
|---|
| 202 |
|
|---|
| 203 |
version(Windows) void filter(string pattern, bool delegate(string fileName) callback) |
|---|
| 204 |
{ |
|---|
| 205 |
WIN32_FIND_DATAW fileinfo; |
|---|
| 206 |
|
|---|
| 207 |
auto h = FindFirstFileW(std.utf.toUTF16z(pattern), &fileinfo); |
|---|
| 208 |
if (h == INVALID_HANDLE_VALUE) |
|---|
| 209 |
return; |
|---|
| 210 |
|
|---|
| 211 |
auto path = dirname(pattern); |
|---|
| 212 |
|
|---|
| 213 |
do |
|---|
| 214 |
{ |
|---|
| 215 |
// Skip "." and ".." |
|---|
| 216 |
auto name = fileinfo.cFileName.ptr; |
|---|
| 217 |
if (name[0] == '.' && (name[1] == 0 || name[1] == '.')) |
|---|
| 218 |
continue; |
|---|
| 219 |
|
|---|
| 220 |
size_t clength = std.string.wcslen(fileinfo.cFileName.ptr); |
|---|
| 221 |
auto fileName = std.path.join(path, std.utf.toUTF8(fileinfo.cFileName[0 .. clength])); |
|---|
| 222 |
|
|---|
| 223 |
if (!callback(fileName)) { |
|---|
| 224 |
break; |
|---|
| 225 |
} |
|---|
| 226 |
} while (FindNextFileW(h, &fileinfo) != FALSE); |
|---|
| 227 |
|
|---|
| 228 |
FindClose(h); |
|---|
| 229 |
} |
|---|
| 230 |
|
|---|
| 231 |
string getBaseName(string fullname, string extension = null) |
|---|
| 232 |
{ |
|---|
| 233 |
auto i = fullname.length; |
|---|
| 234 |
for (; i > 0; i--) |
|---|
| 235 |
{ |
|---|
| 236 |
version(Windows) |
|---|
| 237 |
{ |
|---|
| 238 |
if (fullname[i - 1] == ':' || fullname[i - 1] == '\\' || fullname[i - 1] == '/') |
|---|
| 239 |
break; |
|---|
| 240 |
} |
|---|
| 241 |
else version(Posix) |
|---|
| 242 |
{ |
|---|
| 243 |
if (fullname[i - 1] == '/') |
|---|
| 244 |
break; |
|---|
| 245 |
} |
|---|
| 246 |
else |
|---|
| 247 |
{ |
|---|
| 248 |
static assert(0); |
|---|
| 249 |
} |
|---|
| 250 |
} |
|---|
| 251 |
return chomp(fullname[i .. fullname.length], |
|---|
| 252 |
extension.length ? extension : ""); |
|---|
| 253 |
} |
|---|