diff --git a/source/app.d b/source/app.d index b22c236..1efa085 100644 --- a/source/app.d +++ b/source/app.d @@ -178,12 +178,12 @@ dub.loadPackageFromCwd(); - string ide; - if( cmd == "run" || cmd == "build" ) ide = "rdmd"; + string generator; + if( cmd == "run" || cmd == "build" ) generator = "rdmd"; else { - if( args.length >= 2 ) ide = args[1]; - if(ide.empty) { - logInfo("Usage: dub generate "); + if( args.length >= 2 ) generator = args[1]; + if(generator.empty) { + logInfo("Usage: dub generate "); return 1; } } @@ -223,7 +223,8 @@ gensettings.run = cmd == "run"; gensettings.runArgs = args[1 .. $]; - dub.generateProject("rdmd", gensettings); + logDebug("Generating using %s", generator); + dub.generateProject(generator, gensettings); break; } @@ -260,7 +261,8 @@ Adds a local package directory (e.g. a git repository) remove-local Removes a local package directory list-locals Prints a list of all locals - generate Generates project files for a specified IDE. + generate Generates project files using the specified generator: + VisualD, MonoD, build, rdmd General options: --annotate Do not execute dependency installations, just print diff --git a/source/dub/compilers/compiler.d b/source/dub/compilers/compiler.d index b066ab7..79b54eb 100644 --- a/source/dub/compilers/compiler.d +++ b/source/dub/compilers/compiler.d @@ -14,6 +14,7 @@ import std.algorithm; import std.array; import vibe.data.json; +import vibe.inet.path; static this() @@ -50,6 +51,9 @@ /// Replaces high level fields with low level fields and converts /// dmd flags to compiler-specific flags void prepareBuildSettings(ref BuildSettings settings, BuildSetting supported_fields = BuildSetting.all); + + /// Adds the appropriate flag to set a target path + void setTarget(ref BuildSettings settings, Path binary_path); } @@ -77,14 +81,14 @@ addStringImportDirs(getPlatformField(root, "stringImportPaths", platform)); } - void addDFlags(string[] value) { add(dflags, value); } - void addLFlags(string[] value) { add(lflags, value); } - void addLibs(string[] value) { add(libs, value); } - void addFiles(string[] value) { add(files, value); } - void addCopyFiles(string[] value) { add(copyFiles, value); } - void addVersions(string[] value) { add(versions, value); } - void addImportDirs(string[] value) { add(importPaths, value); } - void addStringImportDirs(string[] value) { add(stringImportPaths, value); } + void addDFlags(string[] value...) { add(dflags, value); } + void addLFlags(string[] value...) { add(lflags, value); } + void addLibs(string[] value...) { add(libs, value); } + void addFiles(string[] value...) { add(files, value); } + void addCopyFiles(string[] value...) { add(copyFiles, value); } + void addVersions(string[] value...) { add(versions, value); } + void addImportDirs(string[] value...) { add(importPaths, value); } + void addStringImportDirs(string[] value...) { add(stringImportPaths, value); } // Adds vals to arr without adding duplicates. private void add(ref string[] arr, string[] vals) diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index 307b93f..086e412 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -15,6 +15,7 @@ import std.exception; import stdx.process; import vibe.core.log; +import vibe.inet.path; class DmdCompiler : Compiler { @@ -65,4 +66,9 @@ assert(fields & BuildSetting.dflags); assert(fields & BuildSetting.copyFiles); } + + void setTarget(ref BuildSettings settings, Path binary_path) + { + settings.addDFlags("-of"~binary_path.toNativeString()); + } } diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index 01aad25..3c51ff5 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -15,6 +15,7 @@ import std.exception; import stdx.process; import vibe.core.log; +import vibe.inet.path; class GdcCompiler : Compiler { @@ -117,4 +118,9 @@ assert(fields & BuildSetting.dflags); assert(fields & BuildSetting.copyFiles); } + + void setTarget(ref BuildSettings settings, Path binary_path) + { + settings.addDFlags("-o", binary_path.toNativeString()); + } } diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index 6c3e77e..49f8973 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -15,6 +15,7 @@ import std.exception; import stdx.process; import vibe.core.log; +import vibe.inet.path; class LdcCompiler : Compiler { @@ -73,4 +74,9 @@ assert(fields & BuildSetting.dflags); assert(fields & BuildSetting.copyFiles); } + + void setTarget(ref BuildSettings settings, Path binary_path) + { + settings.addDFlags("-of"~binary_path.toNativeString()); + } } diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d new file mode 100644 index 0000000..ab1b2fe --- /dev/null +++ b/source/dub/generators/build.d @@ -0,0 +1,148 @@ +/** + Generator for direct compiler builds. + + Copyright: © 2013 rejectedsoftware e.K. + License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. + Authors: Sönke Ludwig +*/ +module dub.generators.build; + +import dub.compilers.compiler; +import dub.generators.generator; +import dub.package_; +import dub.packagemanager; +import dub.project; + +import std.algorithm; +import std.array; +import std.conv; +import std.exception; +import std.file; +import std.string; +import stdx.process; + +import vibe.core.file; +import vibe.core.log; +import vibe.inet.path; + + +class BuildGenerator : ProjectGenerator { + private { + Project m_app; + PackageManager m_pkgMgr; + } + + this(Project app, PackageManager mgr) + { + m_app = app; + m_pkgMgr = mgr; + } + + void generateProject(GeneratorSettings settings) + { + + //Added check for existance of [AppNameInPackagejson].d + //If exists, use that as the starting file. + auto outfile = getBinName(m_app); + auto mainsrc = getMainSourceFile(m_app); + + logDebug("Application output name is '%s'", outfile); + + auto buildsettings = m_app.getBuildSettings(settings.platform, settings.config); + buildsettings.addDFlags(["-w"/*, "-property"*/]); + string dflags = environment.get("DFLAGS"); + if( dflags ){ + settings.buildType = "$DFLAGS"; + } else { + switch(settings.buildType){ + default: throw new Exception("Unknown build configuration: "~settings.buildType); + case "plain": dflags = ""; break; + case "debug": dflags = "-g -debug"; break; + case "release": dflags = "-release -O -inline"; break; + case "unittest": dflags = "-g -unittest"; break; + case "profile": dflags = "-g -O -inline -profile"; break; + case "docs": assert(false, "docgen not implemented"); + } + } + buildsettings.addDFlags(dflags.split()); + + // add all .d files + void addPackageFiles(in Package pack){ + foreach(s; pack.sources){ + if( pack !is m_app.mainPackage && s == Path("source/app.d") ) + continue; + auto relpath = (pack.path ~ s).relativeTo(m_app.mainPackage.path); + buildsettings.addFiles(relpath.toNativeString()); + } + } + addPackageFiles(m_app.mainPackage); + foreach(dep; m_app.installedPackages) + addPackageFiles(dep); + + // setup for command line + settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); + + Path run_exe_file; + if( !settings.run ){ + settings.compiler.setTarget(buildsettings, m_app.binaryPath~outfile); + } else { + import std.random; + auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-"; + auto tmp = environment.get("TEMP"); + if( !tmp.length ) tmp = environment.get("TMP"); + if( !tmp.length ){ + version(Posix) tmp = "/tmp"; + else tmp = "."; + } + run_exe_file = Path(tmp~"/.rdmd/source/"~rnd~outfile); + settings.compiler.setTarget(buildsettings, run_exe_file); + } + + string[] flags = buildsettings.dflags; + + if( settings.config.length ) logInfo("Building configuration "~settings.config~", build type "~settings.buildType); + else logInfo("Building default configuration, build type "~settings.buildType); + + logInfo("Running %s", settings.compilerBinary ~ " " ~ join(flags, " ")); + auto compiler_pid = spawnProcess(settings.compilerBinary, flags); + auto result = compiler_pid.wait(); + enforce(result == 0, "Build command failed with exit code "~to!string(result)); + + // TODO: move to a common place - this is not generator specific + if( buildsettings.copyFiles.length ){ + logInfo("Copying files..."); + foreach( f; buildsettings.copyFiles ){ + auto src = Path(f); + auto dst = (run_exe_file.empty ? m_app.binaryPath : run_exe_file.parentPath) ~ Path(f).head; + logDebug(" %s to %s", src.toNativeString(), dst.toNativeString()); + try copyFile(src, dst, true); + catch logWarn("Failed to copy to %s", dst.toNativeString()); + } + } + + if( settings.run ){ + auto prg_pid = spawnProcess(run_exe_file.toNativeString(), settings.runArgs); + result = prg_pid.wait(); + remove(run_exe_file.toNativeString()); + foreach( f; buildsettings.copyFiles ) + remove((run_exe_file.parentPath ~ Path(f).head).toNativeString()); + enforce(result == 0, "Program exited with code "~to!string(result)); + } + } +} + +private string getBinName(in Project prj) +{ + // take the project name as the base or fall back to "app" + string ret = prj.name; + if( ret.length == 0 ) ret ="app"; + version(Windows) { ret ~= ".exe"; } + return ret; +} + +private Path getMainSourceFile(in Project prj) +{ + auto p = Path("source") ~ (prj.name ~ ".d"); + return existsFile(p) ? p : Path("source/app.d"); +} + diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index e42d5b6..3a1fd41 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -8,6 +8,7 @@ module dub.generators.generator; import dub.compilers.compiler; +import dub.generators.build; import dub.generators.monod; import dub.generators.rdmd; import dub.generators.visuald; @@ -51,6 +52,9 @@ switch(generator_type) { default: throw new Exception("Unknown project generator: "~generator_type); + case "build": + logTrace("Generating build generator."); + return new BuildGenerator(app, mgr); case "rdmd": logTrace("Generating rdmd generator."); return new RdmdGenerator(app, mgr);