1 /** 2 Generator for direct RDMD builds. 3 4 Copyright: © 2013-2013 rejectedsoftware e.K. 5 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 6 Authors: Sönke Ludwig 7 */ 8 module dub.generators.rdmd; 9 10 import dub.compilers.compiler; 11 import dub.generators.generator; 12 import dub.internal.std.process; 13 import dub.internal.utils; 14 import dub.internal.vibecompat.core.file; 15 import dub.internal.vibecompat.core.log; 16 import dub.internal.vibecompat.inet.path; 17 import dub.package_; 18 import dub.packagemanager; 19 import dub.project; 20 21 import std.algorithm; 22 import std.array; 23 import std.conv; 24 import std.exception; 25 import std.file; 26 import std.string; 27 28 29 class RdmdGenerator : ProjectGenerator { 30 private { 31 Project m_project; 32 PackageManager m_pkgMgr; 33 } 34 35 this(Project app, PackageManager mgr) 36 { 37 m_project = app; 38 m_pkgMgr = mgr; 39 } 40 41 void generateProject(GeneratorSettings settings) 42 { 43 //Added check for existance of [AppNameInPackagejson].d 44 //If exists, use that as the starting file. 45 auto mainsrc = getMainSourceFile(m_project); 46 47 auto buildsettings = settings.buildSettings; 48 m_project.addBuildSettings(buildsettings, settings.platform, settings.config); 49 m_project.addBuildTypeSettings(buildsettings, settings.platform, settings.buildType); 50 // do not pass all source files to RDMD, only the main source file 51 buildsettings.sourceFiles = buildsettings.sourceFiles.filter!(s => !s.endsWith(".d"))().array(); 52 settings.compiler.prepareBuildSettings(buildsettings, BuildSetting.commandLine); 53 54 auto generate_binary = !buildsettings.dflags.canFind("-o-"); 55 56 // Create start script, which will be used by the calling bash/cmd script. 57 // build "rdmd --force %DFLAGS% -I%~dp0..\source -Jviews -Isource @deps.txt %LIBS% source\app.d" ~ application arguments 58 // or with "/" instead of "\" 59 Path run_exe_file; 60 if( generate_binary ){ 61 if( settings.run ){ 62 import std.random; 63 auto rnd = to!string(uniform(uint.min, uint.max)) ~ "-"; 64 buildsettings.targetPath = (getTempDir()~".rdmd/source/").toNativeString(); 65 buildsettings.targetName = rnd ~ buildsettings.targetName; 66 run_exe_file = Path(buildsettings.targetPath) ~ getTargetFileName(buildsettings, settings.platform); 67 } 68 settings.compiler.setTarget(buildsettings, settings.platform); 69 } 70 71 logDiagnostic("Application output name is '%s'", getTargetFileName(buildsettings, settings.platform)); 72 73 string[] flags = ["--build-only", "--compiler="~settings.platform.compilerBinary]; 74 flags ~= buildsettings.dflags; 75 flags ~= (mainsrc).toNativeString(); 76 77 prepareGeneration(buildsettings); 78 finalizeGeneration(buildsettings, generate_binary); 79 80 if( buildsettings.preBuildCommands.length ){ 81 logInfo("Running pre-build commands..."); 82 runCommands(buildsettings.preBuildCommands); 83 } 84 85 if( settings.config.length ) logInfo("Building configuration "~settings.config~", build type "~settings.buildType); 86 else logInfo("Building default configuration, build type "~settings.buildType); 87 88 logInfo("Running rdmd..."); 89 logDiagnostic("rdmd %s", join(flags, " ")); 90 auto rdmd_pid = spawnProcess("rdmd" ~ flags); 91 auto result = rdmd_pid.wait(); 92 enforce(result == 0, "Build command failed with exit code "~to!string(result)); 93 94 if( buildsettings.postBuildCommands.length ){ 95 logInfo("Running post-build commands..."); 96 runCommands(buildsettings.postBuildCommands); 97 } 98 99 if (generate_binary && settings.run) { 100 if (buildsettings.targetType == TargetType.executable) { 101 auto cwd = Path(getcwd()); 102 if (buildsettings.workingDirectory.length) { 103 logDiagnostic("Switching to %s", (cwd ~ buildsettings.workingDirectory).toNativeString()); 104 chdir((cwd ~ buildsettings.workingDirectory).toNativeString()); 105 } 106 scope(exit) chdir(cwd.toNativeString()); 107 logInfo("Running %s...", run_exe_file.toNativeString()); 108 auto prg_pid = spawnProcess(run_exe_file.toNativeString() ~ settings.runArgs); 109 result = prg_pid.wait(); 110 remove(run_exe_file.toNativeString()); 111 foreach( f; buildsettings.copyFiles ) 112 remove((run_exe_file.parentPath ~ Path(f).head).toNativeString()); 113 enforce(result == 0, "Program exited with code "~to!string(result)); 114 } else logInfo("Target is a library. Skipping execution."); 115 } 116 } 117 } 118 119 private Path getMainSourceFile(in Project prj) 120 { 121 foreach( f; ["source/app.d", "src/app.d", "source/"~prj.name~".d", "src/"~prj.name~".d"]) 122 if( exists(f) ) 123 return Path(f); 124 return Path("source/app.d"); 125 }