Link against the intermediate binary files of dependencies. Fixes #921.
This change causes the build generator to pass the path to the intermediate build directory (e.g. ".dub/build/*/libfoo.a") instead of the final target path. The major consequence is that temporary builds with dependencies now work (they won't copy the intermediate binary to the final target path).
1 parent 875f4dd commit 23b1cb3b9066b3a5fd1766438eed690ac00ac6a6
@Sönke Ludwig Sönke Ludwig authored on 6 Sep 2016
Showing 1 changed file
View
50
source/dub/generators/build.d
settings.buildType, settings.platform.compilerBinary, settings.platform.architecture);
 
bool any_cached = false;
 
Path[string] target_paths;
 
bool[string] visited;
void buildTargetRec(string target)
{
if (target in visited) return;
auto bs = ti.buildSettings.dup;
foreach (ldep; ti.linkDependencies) {
auto dbs = targets[ldep].buildSettings;
if (bs.targetType != TargetType.staticLibrary) {
bs.addSourceFiles(getTargetPath(dbs, settings).toNativeString());
bs.addSourceFiles(target_paths[ldep].toNativeString());
} else {
additional_dep_files ~= getTargetPath(dbs, settings);
additional_dep_files ~= target_paths[ldep];
}
}
if (buildTarget(settings, bs, ti.pack, ti.config, ti.packages, additional_dep_files))
Path tpath;
if (buildTarget(settings, bs, ti.pack, ti.config, ti.packages, additional_dep_files, tpath))
any_cached = true;
target_paths[target] = tpath;
}
 
// build all targets
auto root_ti = targets[m_project.rootPackage.name];
if (settings.rdmd || root_ti.buildSettings.targetType == TargetType.staticLibrary) {
// RDMD always builds everything at once and static libraries don't need their
// dependencies to be built
buildTarget(settings, root_ti.buildSettings.dup, m_project.rootPackage, root_ti.config, root_ti.packages, null);
Path tpath;
buildTarget(settings, root_ti.buildSettings.dup, m_project.rootPackage, root_ti.config, root_ti.packages, null, tpath);
} else {
buildTargetRec(m_project.rootPackage.name);
 
if (any_cached) {
runTarget(exe_file_path, buildsettings, settings.runArgs, settings);
}
}
 
private bool buildTarget(GeneratorSettings settings, BuildSettings buildsettings, in Package pack, string config, in Package[] packages, in Path[] additional_dep_files)
private bool buildTarget(GeneratorSettings settings, BuildSettings buildsettings, in Package pack, string config, in Package[] packages, in Path[] additional_dep_files, out Path target_path)
{
auto cwd = Path(getcwd());
bool generate_binary = !(buildsettings.options & BuildOption.syntaxOnly);
 
foreach (ref p; buildsettings.stringImportPaths) p = makeRelative(p);
 
// perform the actual build
bool cached = false;
if (settings.rdmd) performRDMDBuild(settings, buildsettings, pack, config);
else if (settings.direct || !generate_binary) performDirectBuild(settings, buildsettings, pack, config);
else cached = performCachedBuild(settings, buildsettings, pack, config, build_id, packages, additional_dep_files);
if (settings.rdmd) performRDMDBuild(settings, buildsettings, pack, config, target_path);
else if (settings.direct || !generate_binary) performDirectBuild(settings, buildsettings, pack, config, target_path);
else cached = performCachedBuild(settings, buildsettings, pack, config, build_id, packages, additional_dep_files, target_path);
 
// HACK: cleanup dummy doc files, we shouldn't specialize on buildType
// here and the compiler shouldn't need dummy doc ouput.
if (settings.buildType == "ddox") {
 
return cached;
}
 
private bool performCachedBuild(GeneratorSettings settings, BuildSettings buildsettings, in Package pack, string config, string build_id, in Package[] packages, in Path[] additional_dep_files)
private bool performCachedBuild(GeneratorSettings settings, BuildSettings buildsettings, in Package pack, string config,
string build_id, in Package[] packages, in Path[] additional_dep_files, out Path target_binary_path)
{
auto cwd = Path(getcwd());
 
Path target_path;
 
if (!settings.force && isUpToDate(target_path, buildsettings, settings, pack, packages, additional_dep_files)) {
logInfo("%s %s: target for configuration \"%s\" is up to date.", pack.name, pack.version_, config);
logDiagnostic("Using existing build in %s.", target_path.toNativeString());
copyTargetFile(target_path, buildsettings, settings);
target_binary_path = target_path ~ settings.compiler.getTargetFileName(buildsettings, settings.platform);
if (!settings.tempBuild)
copyTargetFile(target_path, buildsettings, settings);
return true;
}
 
if (!isWritableDir(target_path, true)) {
if (!settings.tempBuild)
logInfo("Build directory %s is not writable. Falling back to direct build in the system's temp folder.", target_path.relativeTo(cwd).toNativeString());
performDirectBuild(settings, buildsettings, pack, config);
performDirectBuild(settings, buildsettings, pack, config, target_path);
return false;
}
 
// determine basic build properties
// override target path
auto cbuildsettings = buildsettings;
cbuildsettings.targetPath = target_path.relativeTo(cwd).toNativeString();
buildWithCompiler(settings, cbuildsettings);
target_binary_path = getTargetPath(cbuildsettings, settings);
 
if (!settings.tempBuild)
copyTargetFile(target_path, buildsettings, settings);
 
return false;
}
 
private void performRDMDBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config)
private void performRDMDBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config, out Path target_path)
{
auto cwd = Path(getcwd());
//Added check for existance of [AppNameInPackagejson].d
//If exists, use that as the starting file.
 
// Create start script, which will be used by the calling bash/cmd script.
// build "rdmd --force %DFLAGS% -I%~dp0..\source -Jviews -Isource @deps.txt %LIBS% source\app.d" ~ application arguments
// or with "/" instead of "\"
Path exe_file_path;
bool tmp_target = false;
if (generate_binary) {
if (settings.tempBuild || (settings.run && !isWritableDir(Path(buildsettings.targetPath), true))) {
import std.random;
buildsettings.targetName = rnd ~ buildsettings.targetName;
m_temporaryFiles ~= tmpdir;
tmp_target = true;
}
exe_file_path = getTargetPath(buildsettings, settings);
target_path = getTargetPath(buildsettings, settings);
settings.compiler.setTarget(buildsettings, settings.platform);
}
 
logDiagnostic("Application output name is '%s'", settings.compiler.getTargetFileName(buildsettings, settings.platform));
auto result = rdmd_pid.wait();
enforce(result == 0, "Build command failed with exit code "~to!string(result));
 
if (tmp_target) {
m_temporaryFiles ~= exe_file_path;
m_temporaryFiles ~= target_path;
foreach (f; buildsettings.copyFiles)
m_temporaryFiles ~= Path(buildsettings.targetPath).parentPath ~ Path(f).head;
}
}
 
private void performDirectBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config)
private void performDirectBuild(GeneratorSettings settings, ref BuildSettings buildsettings, in Package pack, string config, out Path target_path)
{
auto cwd = Path(getcwd());
 
auto generate_binary = !(buildsettings.options & BuildOption.syntaxOnly);
buildsettings.targetPath = makeRelative(buildsettings.targetPath);
foreach (ref p; buildsettings.importPaths) p = makeRelative(p);
foreach (ref p; buildsettings.stringImportPaths) p = makeRelative(p);
 
Path exe_file_path;
bool is_temp_target = false;
if (generate_binary) {
if (settings.tempBuild || (settings.run && !isWritableDir(Path(buildsettings.targetPath), true))) {
import std.random;
buildsettings.targetPath = tmppath.toNativeString();
m_temporaryFiles ~= tmppath;
is_temp_target = true;
}
exe_file_path = getTargetPath(buildsettings, settings);
target_path = getTargetPath(buildsettings, settings);
}
 
if( buildsettings.preBuildCommands.length ){
logInfo("Running pre-build commands...");
 
buildWithCompiler(settings, buildsettings);
 
if (is_temp_target) {
m_temporaryFiles ~= exe_file_path;
m_temporaryFiles ~= target_path;
foreach (f; buildsettings.copyFiles)
m_temporaryFiles ~= Path(buildsettings.targetPath).parentPath ~ Path(f).head;
}
}