Dub: Make determineDefaultCompiler configurable
By making it an idempotent (albeit not pure) function,
we allow other classes to override it with their own logic.
One such example would be returning an hardcoded path every time.
1 parent 7bc731d commit 21e999ed5aab4abf087e0bd4539d0eadfa1f5f32
@Mathias Lang Mathias Lang authored on 19 Dec 2023
The Dlang Bot committed on 22 Dec 2023
Showing 1 changed file
View
107
source/dub/dub.d
private void init()
{
this.m_dirs = SpecialDirs.make();
this.loadConfig();
this.determineDefaultCompiler();
this.m_defaultCompiler = this.determineDefaultCompiler();
}
 
/**
* Load user configuration for this instance
 
return settings;
}
 
private void determineDefaultCompiler()
/**
* Determine the default compiler to use for this instance
*
* The default compiler will be used unless --compiler is specified.
* The environment variable `DC` will take precedence over anything,
* followed by the configuration. If nothing is found, the folder in
* which `dub` is installed will be searched, and if nothing is found,
* the $PATH will be searched.
* In the majority of cases, as we distribute `dub` alongside the compiler,
* it will be found once the directory in which dub reside is searched.
*
* Returns: The value to use for the default compiler.
*/
protected string determineDefaultCompiler() const
{
import std.file : thisExePath;
import std.path : buildPath, dirName, expandTilde, isAbsolute, isDirSeparator;
import std.range : front;
 
// Env takes precedence
string result;
if (auto envCompiler = environment.get("DC"))
m_defaultCompiler = envCompiler;
result = envCompiler;
else
m_defaultCompiler = m_config.defaultCompiler.expandTilde;
if (m_defaultCompiler.length && m_defaultCompiler.isAbsolute)
return;
result = this.m_config.defaultCompiler.expandTilde;
if (result.length && result.isAbsolute)
return result;
 
static immutable BinaryPrefix = `$DUB_BINARY_PATH`;
if(m_defaultCompiler.startsWith(BinaryPrefix))
{
m_defaultCompiler = thisExePath().dirName() ~ m_defaultCompiler[BinaryPrefix.length .. $];
return;
}
 
if (!find!isDirSeparator(m_defaultCompiler).empty)
throw new Exception("defaultCompiler specified in a DUB config file cannot use an unqualified relative path:\n\n" ~ m_defaultCompiler ~
if (result.startsWith(BinaryPrefix))
return thisExePath().dirName() ~ result[BinaryPrefix.length .. $];
 
if (!find!isDirSeparator(result).empty)
throw new Exception("defaultCompiler specified in a DUB config file cannot use an unqualified relative path:\n\n" ~ result ~
"\n\nUse \"$DUB_BINARY_PATH/../path/you/want\" instead.");
 
version (Windows) enum sep = ";", exe = ".exe";
version (Posix) enum sep = ":", exe = "";
 
auto compilers = ["dmd", "gdc", "gdmd", "ldc2", "ldmd2"];
// If a compiler name is specified, look for it next to dub.
// Otherwise, look for any of the common compilers adjacent to dub.
if (m_defaultCompiler.length)
if (result.length)
{
string compilerPath = buildPath(thisExePath().dirName(), m_defaultCompiler ~ exe);
string compilerPath = buildPath(thisExePath().dirName(), result ~ exe);
if (existsFile(compilerPath))
{
m_defaultCompiler = compilerPath;
return;
}
return compilerPath;
}
else
{
auto nextFound = compilers.find!(bin => existsFile(buildPath(thisExePath().dirName(), bin ~ exe)));
if (!nextFound.empty)
{
m_defaultCompiler = buildPath(thisExePath().dirName(), nextFound.front ~ exe);
return;
}
return buildPath(thisExePath().dirName(), nextFound.front ~ exe);
}
 
// If nothing found next to dub, search the user's PATH, starting
// with the compiler name from their DUB config file, if specified.
auto paths = environment.get("PATH", "").splitter(sep).map!NativePath;
if (m_defaultCompiler.length && paths.canFind!(p => existsFile(p ~ (m_defaultCompiler~exe))))
return;
if (result.length && paths.canFind!(p => existsFile(p ~ (result ~ exe))))
return result;
foreach (p; paths) {
auto res = compilers.find!(bin => existsFile(p ~ (bin~exe)));
if (!res.empty) {
m_defaultCompiler = res.front;
return;
}
}
m_defaultCompiler = compilers[0];
if (!res.empty)
return res.front;
}
return compilers[0];
}
 
unittest
{
std.file.write(dmdbin, null);
std.file.write(ldcbin, null);
 
environment["DC"] = dmdbin.absolutePath();
dub.determineDefaultCompiler();
assert(dub.m_defaultCompiler == dmdbin.absolutePath());
assert(dub.determineDefaultCompiler() == dmdbin.absolutePath());
 
environment["DC"] = "dmd";
environment["PATH"] = dmdpath ~ sep ~ ldcpath;
dub.determineDefaultCompiler();
assert(dub.m_defaultCompiler == "dmd");
assert(dub.determineDefaultCompiler() == "dmd");
 
environment["DC"] = "ldc2";
environment["PATH"] = dmdpath ~ sep ~ ldcpath;
dub.determineDefaultCompiler();
assert(dub.m_defaultCompiler == "ldc2");
assert(dub.determineDefaultCompiler() == "ldc2");
 
environment.remove("DC");
environment["PATH"] = ldcpath ~ sep ~ dmdpath;
dub.determineDefaultCompiler();
assert(dub.m_defaultCompiler == "ldc2");
assert(dub.determineDefaultCompiler() == "ldc2");
}
 
private NativePath makeAbsolute(NativePath p) const { return p.absolute ? p : m_rootPath ~ p; }
private NativePath makeAbsolute(string p) const { return makeAbsolute(NativePath(p)); }