Skip to content

Commit

Permalink
Merge pull request #310 from atilaneves/lazy-reggaefile-dep
Browse files Browse the repository at this point in the history
Only calculate reggaefile import dependencies if needed
  • Loading branch information
atilaneves authored Jun 13, 2024
2 parents a71790b + 2ea1322 commit abb2e18
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 6 deletions.
2 changes: 2 additions & 0 deletions payload/reggae/options.d
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct Options {
bool dubTargetPathAbs;
bool buildReggaefileSingle; // single-threaded build using the binary backend
bool buildReggaefileOptimise; // compile the build description with optimisations
bool forceReggaefileDeps;
string[string] userVars; // must be last

Options dup() @safe pure const nothrow scope {
Expand Down Expand Up @@ -334,6 +335,7 @@ Options getOptions(Options defaultOptions, string[] args) @trusted {
"build-reggaefile-with-dub", "Build the reggaefile with dub instead of the binary backend", &options.buildReggaefileWithDub,
"build-reggaefile-single", "Build the reggaefile using a single thread", &options.buildReggaefileSingle,
"build-reggaefile-release", "Build the reggaefile with optimisations", &options.buildReggaefileOptimise,
"force-reggaefile-deps", "Force calculating reggaefile import dependencies", &options.forceReggaefileDeps,
);

if(helpInfo.helpWanted) {
Expand Down
107 changes: 101 additions & 6 deletions src/reggae/reggae.d
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ struct Binary {


private string compileBuildGenerator(T)(auto ref T output, in Options options) {

import std.algorithm: any, canFind;
import std.typecons: Yes, No;

Expand All @@ -242,7 +241,7 @@ private string compileBuildGenerator(T)(auto ref T output, in Options options) {
return buildGenName;
}

return buildReggaefileWithReggae(options, needsDub);
return buildReggaefileWithReggae(output, options, needsDub);
}

private enum reggaeFileDubSdl =
Expand Down Expand Up @@ -376,6 +375,16 @@ private void calculateReggaeFileDeps(O)(auto ref O output, in Options options) {
import reggae.io: log;
import reggae.build: Build, Target, Command;
import reggae.types: Backend;
import std.file: write, exists, mkdirRecurse;
import std.path: dirName;

// No imports => no dependencies => no need to spend time calculating.
if(!options.forceReggaefileDeps && noExternalImports(options)) {
if(!options.reggaeFileDepFile.dirName.exists)
mkdirRecurse(options.reggaeFileDepFile.dirName);
write(options.reggaeFileDepFile, "reggaefile.o: \\\n " ~ options.reggaeFilePath);
return;
}

// `options.getReggaeFileDependenciesDlang` depends on
// `options.reggaeFileDepFile` existing, which means we need to
Expand All @@ -392,7 +401,7 @@ private void calculateReggaeFileDeps(O)(auto ref O output, in Options options) {
[
options.dCompiler,
options.reggaeFilePath, "-o-", "-makedeps=" ~ options.reggaeFileDepFile,
]
]
~ importPaths(options),
);

Expand All @@ -410,6 +419,88 @@ private void calculateReggaeFileDeps(O)(auto ref O output, in Options options) {
runtimeBuild(newOptions, Build(target), ["--single"]);
}

// If all imports are reggae or phobos. In this common case, we don't
// need to ask the compiler to get the dependencies of the reggaefile
// so that we can compile them as well.
bool noExternalImports(in Options options) {
import std.file: readText;
import std.algorithm: splitter, all;

return extractImports(options.reggaeFilePath.readText)
.map!(i => i.splitter(".").front)
.all!(a => a.among("std", "core", "etc", "reggae"));
}

private string[] extractImports(string code) {
import std.algorithm: startsWith, map, splitter, sort, uniq;
import std.string: indexOf, strip;
import std.array: array;

string[] imports;

size_t pos = 0;
while (pos < code.length) {
// Skip over single-line comments
if (code[pos .. $].startsWith("//")) {
pos = code.indexOf('\n', pos);
if (pos == size_t.max) break;
pos++;
continue;
}
// Skip over multi-line comments
else if (code[pos .. $].startsWith("/*")) {
pos = code.indexOf("*/", pos);
if (pos == size_t.max) break;
pos += 2;
continue;
}
// Skip over nested comments
else if (code[pos .. $].startsWith("/+")) {
int nestedLevel = 1;
pos += 2;
while (nestedLevel > 0 && pos < code.length) {
if (code[pos .. $].startsWith("/+")) {
nestedLevel++;
pos += 2;
} else if (code[pos .. $].startsWith("+/")) {
nestedLevel--;
pos += 2;
} else {
pos++;
}
}
continue;
}

// Find import statements
if (code[pos .. $].startsWith("import ")) {
pos += 7; // Move past "import "
size_t end = code.indexOf(';', pos);
if (end == size_t.max) break;

auto statement = code[pos .. end].strip();
// Split imports by comma
auto modules = statement.splitter(',').map!(s => s.strip);
foreach (mod; modules) {
auto parts = mod.splitter(':').map!(s => s.strip).array;
if (parts.length == 2) {
imports ~= parts[0];
} else {
imports ~= parts[0];
}
}

pos = end + 1;
} else {
pos++;
}
}

// Return sorted and unique imports
return imports.sort.uniq.array;
}



void writeIfDiffers(O)(auto ref O output, const string path, in string contents) @safe {
import reggae.io: log;
Expand Down Expand Up @@ -442,11 +533,14 @@ private imported!"std.json".JSONValue selectionsPkgVersion(string pkg)() @safe p
// Builds the reggaefile custom dub project using reggae itself. I put
// a build system in the build system so it can build system while it
// build systems.
private string buildReggaefileWithReggae(
in imported!"reggae.options".Options options,
imported!"std.typecons".Flag!"needDub" needDub,
private string buildReggaefileWithReggae(O)
(
auto ref O output,
in imported!"reggae.options".Options options,
imported!"std.typecons".Flag!"needDub" needDub,
)
{
import reggae.io: log;
import reggae.rules.dub: dubPackage, DubPath;
import reggae.build: Build;

Expand Down Expand Up @@ -477,6 +571,7 @@ private string buildReggaefileWithReggae(
? ["--single"]
: [];

output.log("Building reggaefile");
runtimeBuild(newOptions, build, extraArgs);

return getBuildGenName(options);
Expand Down

0 comments on commit abb2e18

Please sign in to comment.