Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 75 additions & 40 deletions rdmd.d
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ int main(string[] args)
assert(programPos > 0);
auto argsBeforeProgram = args[0 .. programPos];

/* Catch -main and handle it like --main. This needs to be done, because
rdmd compiles the root file independently from the dependencies, but -main
must be present in only one of the calls to dmd. */
foreach (ref arg; argsBeforeProgram)
{
if (arg == "-main") arg = "--main";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like that trick 👍 (I filtered for it for the additional source compilation)

}

bool bailout; // bailout set by functions called in getopt if
// program should exit
string[] loop; // set by --loop
Expand Down Expand Up @@ -234,7 +242,8 @@ int main(string[] args)
}

// Fetch dependencies
const myDeps = getDependencies(root, workDir, objDir, compilerFlags);
const myDeps = compileRootAndGetDeps(root, workDir, objDir, compilerFlags,
addStubMain);

// --makedepend mode. Just print dependencies and exit.
if (makeDepend)
Expand Down Expand Up @@ -292,7 +301,7 @@ int main(string[] args)
if (chain(root.only, myDeps.byKey).array.anyNewerThan(lastBuildTime))
{
immutable result = rebuild(root, exe, workDir, objDir,
myDeps, compilerFlags, addStubMain);
myDeps, compilerFlags);
if (result)
return result;

Expand Down Expand Up @@ -437,13 +446,13 @@ private void unlockWorkPath()
}
}

// Rebuild the executable fullExe starting from modules in myDeps
// Rebuild the executable fullExe from root and myDeps,
// passing the compiler flags compilerFlags. Generates one large
// object file.
// object file for the dependencies.

private int rebuild(string root, string fullExe,
string workDir, string objDir, in string[string] myDeps,
string[] compilerFlags, bool addStubMain)
string[] compilerFlags)
{
version (Windows)
fullExe = fullExe.defaultExtension(".exe");
Expand All @@ -470,46 +479,59 @@ private int rebuild(string root, string fullExe,
}
}

auto fullExeTemp = fullExe ~ ".tmp";
immutable fullExeTemp = fullExe ~ ".tmp";
immutable rootObj = buildPath(objDir, root.baseName(".d") ~ objExt);
immutable depsObj = buildPath(objDir,
root.baseName(".d") ~ ".deps" ~ objExt);

string[] buildTodo()
assert(dryRun || std.file.exists(rootObj),
"should have been created by compileRootAndGetDeps");

int result = 0;
string[] objs = [ rootObj ];

// compile dependencies
if (myDeps.byValue.any!(o => o !is null))
// if there is any source dependency at all
{
auto todo = compilerFlags
~ [ "-of"~fullExeTemp ]
~ [ "-od"~objDir ]
~ [ "-I"~dirName(root) ]
~ [ root ];
auto todo = compilerFlags ~ [
"-c",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah that's the spirit

"-of" ~ depsObj,
"-I" ~ dirName(root),
];
foreach (k, objectFile; myDeps) {
if(objectFile !is null)
todo ~= [ k ];
}
// Need to add void main(){}?
if (addStubMain)

// Different shells and OS functions have different limits,
// but 1024 seems to be the smallest maximum outside of MS-DOS.
enum maxLength = 1024;
auto commandLength = escapeShellCommand(todo).length;
if (commandLength + compiler.length >= maxLength)
{
auto stubMain = buildPath(myOwnTmpDir, "stubmain.d");
std.file.write(stubMain, "void main(){}");
todo ~= [ stubMain ];
auto rspName = buildPath(workDir, "rdmd.rsp");

// DMD uses Windows-style command-line parsing in response files
// regardless of the operating system it's running on.
std.file.write(rspName,
array(map!escapeWindowsArgument(todo)).join(" "));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm, this reminds me we should have a write that takes a range

Copy link
Contributor

@AndrejMitrovic AndrejMitrovic Aug 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use each? Something like:

todo.map!escapeWindowsArgument.joiner(" ").each!(line => std.file.append(rspName, line)));

Pseudocoding here. Edit: Update example

Copy link
Member

@CyberShadow CyberShadow Aug 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm, this reminds me we should have a write that takes a range

We do!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous page is sending you to an invalid url (http:///home/vladimir/work/aconfmgr/README.html).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, link fixed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's use it!!!


todo = [ "@" ~ rspName ];
}
return todo;

result = run([ compiler ] ~ todo);
Copy link
Contributor

@wilzbach wilzbach Aug 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the base version (see a couple of lines below) removes the temporary build files if an error occurs

edit: It might make also sense to remove/clean rdmd.root on this build error too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the base version (see a couple of lines below) removes the temporary build files if an error occurs

edit: It might make also sense to remove/clean rdmd.root on this build error too.

I'm not sure what you mean by "base version".
As far as I see, the current rdmd only removes object files on success. So I'd stick with that for now.

objs ~= depsObj;
}
auto todo = buildTodo();

// Different shells and OS functions have different limits,
// but 1024 seems to be the smallest maximum outside of MS-DOS.
enum maxLength = 1024;
auto commandLength = escapeShellCommand(todo).length;
if (commandLength + compiler.length >= maxLength)
// link
if (!result)
{
auto rspName = buildPath(workDir, "rdmd.rsp");

// DMD uses Windows-style command-line parsing in response files
// regardless of the operating system it's running on.
std.file.write(rspName, array(map!escapeWindowsArgument(todo)).join(" "));

todo = [ "@"~rspName ];
string[] cmd = [ compiler ] ~ compilerFlags ~
[ "-of" ~ fullExeTemp, "-od" ~ objDir ] ~ objs;
result = run(cmd);
}

immutable result = run([ compiler ] ~ todo);
if (result)
Copy link
Contributor

@wilzbach wilzbach Aug 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just you else here, but maybe it's even clearer if the blocks are swapped:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can just you else here, but maybe it's even clearer if the blocks are swapped:

No, the block above may change the value of result.

{
// build failed
Expand Down Expand Up @@ -571,13 +593,13 @@ private int exec(string[] args)
return run(args, null, true);
}

// Given module rootModule, returns a mapping of all dependees .d
// source filenames to their corresponding .o files sitting in
// Given module rootModule, compiles it to rdmd.root.o and returns a mapping of
// all dependees .d source filenames to their corresponding .o files sitting in
// directory workDir. The mapping is obtained by running dmd -v against
// rootModule.

private string[string] getDependencies(string rootModule, string workDir,
string objDir, string[] compilerFlags)
private string[string] compileRootAndGetDeps(string rootModule, string workDir,
string objDir, string[] compilerFlags, bool addStubMain)
{
immutable depsFilename = buildPath(workDir, "rdmd.deps");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unrelated, but this could also be the cause of the slight runtime difference. At line 640 we can use a ctRegex

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> #196


Expand Down Expand Up @@ -694,10 +716,23 @@ private string[string] getDependencies(string rootModule, string workDir,
immutable rootDir = dirName(rootModule);

// Collect dependencies
auto depsGetter =
// "cd "~shellQuote(rootDir)~" && "
[ compiler ] ~ compilerFlags ~
["-v", "-o-", rootModule, "-I"~rootDir];
auto depsGetter = [ compiler ] ~ compilerFlags ~ [
"-v",
"-c",
"-of" ~ buildPath(objDir, rootModule.baseName(".d") ~ objExt),
rootModule,
"-I" ~ rootDir
];

// Need to add void main(){}?
if (addStubMain)
{
/* TODO: Can be simplified to `depsGetter ~= "-main";` when issue 16440
is fixed. */
auto stubMain = buildPath(myOwnTmpDir, "stubmain.d");
std.file.write(stubMain, "void main(){}");
depsGetter ~= [ stubMain ];
}

scope(failure)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While run can throw (e.g. writing the output file), it just returns an exit code if the spawned process fails.
In rebuild errors are handled by just checking for the exit code.

Expand Down