On Thursday, 26 August 2021 at 09:38:54 UTC, deadalnix wrote:
> The root of the problem, really, is that I don't cares about main when running unit tests. I don't want to know if it is there or not, I don't want it to run, nothing. If the compiler needs one to link under the hood, then good for it, but this is an implementation detail.
OK. Create a bugzilla issue. There are some related bugs that someone might want to fix at the same time (#20340 it doesn't use a betterC main when -betterC is passed, #16440 it breaks with -c and -of).
This is about the extent of the current support, in src/dmd/mars.d's tryMain:
if (params.addMain)
files.push("__main.d");
// Create Modules
Modules modules = createModules(files, libmodules);
// Read files
// Start by "reading" the special files (__main.d, __stdin.d)
foreach (m; modules)
{
if (params.addMain && m.srcfile.toString() == "__main.d")
{
auto data = arraydup("int main(){return 0;}\0\0\0\0"); // need 2 trailing nulls for sentinel and 2 for lexer
m.srcBuffer = new FileBuffer(cast(ubyte[]) data[0 .. $-4]);
}
and src/dmd/glue.d:
private bool onlyOneMain(Loc loc)
{
__gshared Loc lastLoc;
__gshared bool hasMain = false;
if (hasMain)
{
const(char)* msg = "";
if (global.params.addMain)
msg = ", -main switch added another `main()`";
It's not surprising that such a lightweight implementation doesn't result in world-class ergonomics. It's something I use all the time to test individual modules at the CLI, and I'd much rather have this than nothing. But for bells and whistles I'd look to dub.
In a pinch you could write a dmd wrapper that calls dmd, sees if it gets a linker complaint about main, and if so calls dmd again with -main. An obvious performance hit, probably not that bad in most cases where you would consider this, but now you don't have care about main.
#! /usr/bin/env rdmd
import std.process : execute, spawnProcess, wait;
import std.algorithm : canFind;
import std.stdio : write;
int main(string[] args) {
auto result = execute(["dmd"] ~ args[1..$]);
if (result.status != 0 && result.output.canFind("undefined reference to `main'")) {
return spawnProcess(["dmd", "-main"] ~ args[1..$]).wait;
}
write(result.output);
return result.status;
}
usage:
$ cat nomain.d
unittest {
import std.stdio : writeln;
writeln("no main");
}
$ cat hasmain.d
unittest {
import std.stdio : writeln;
writeln("has main");
}
void main() {}
$ ./automain.d -unittest -run nomain.d
no main
1 modules passed unittests
$ ./automain.d -unittest -run hasmain.d
1 modules passed unittests
has main