Наследование: MonoDevelop.D.Projects.AbstractDProject, ICustomDataItem
Пример #1
0
		public static string GetCommandArgs(string baseCommandArgs, string filePath, DProject project, DProjectConfiguration conf)
		{
			var compiler =project.Compiler;
			ProjectBuilder.PrjPathMacroProvider prjPath = new ProjectBuilder.PrjPathMacroProvider {
				slnPath = project.ParentSolution != null ? ProjectBuilder.EnsureCorrectPathSeparators(project.ParentSolution.BaseDirectory) : ""
			};
			
			List<string> includes = new List<string>(project.IncludePaths);
			includes.Add(project.BaseDirectory.FullPath);

			string[] src = {filePath};
			var compilerMacro = new UnittestMacros
			{
				ObjectsStringPattern = compiler.ArgumentPatterns.ObjectFileLinkPattern,
				IncludesStringPattern = compiler.ArgumentPatterns.IncludePathPattern,

				SourceFiles = src,
				Includes = ProjectBuilder.FillInMacros(includes, prjPath),
				Libraries = ProjectBuilder.GetLibraries(conf, compiler),

				HasMain = HasMainMethod(D_Parser.Misc.GlobalParseCache.GetModule(filePath)),
				compilerFlags = conf.ExtraCompilerArguments,
				linkerFlags = conf.ExtraLinkerArguments
			};
			
			return ProjectBuilder.FillInMacros(baseCommandArgs,compilerMacro, prjPath);
		}
Пример #2
0
        public static void Run(string filePath, DProject project, DProjectConfiguration conf)
        {
            if(manager == null)
            {
                manager = new ProgressMonitorManager();
                monitor = manager.GetOutputProgressMonitor("Run Unittest",Stock.RunProgramIcon,true,true);
            }

            Pad pad = manager.GetPadForMonitor(monitor);
            if(pad != null)
                pad.BringToFront();

            monitor.BeginTask("start unittest...",1);

            new System.Threading.Thread(delegate (){

                string[] cmdParts = GetCmdParts(project);
                string args = GetCommandArgs(cmdParts.Length >= 2 ?cmdParts[1] : "",filePath,project,conf);
                string errorOutput;
                string stdOutput;
                string execDir = GetExecDir(project,conf);

                ProjectBuilder.ExecuteCommand(cmdParts[0], args, execDir,monitor,out stdOutput, out errorOutput);

                monitor.Log.WriteLine("unittest done.");
                monitor.EndTask();
            }).Start();
        }
Пример #3
0
        /// <summary>
        /// Builds an array of all global version id definitions.
        /// Used for code completion.
        /// </summary>
        public void UpdateGlobalVersionIdentifiers(DProject prjOverride = null)
        {
            if (prjOverride == null)
            {
                if ((prjOverride = Project) == null)
                {
                    return;
                }
            }

            var cmp = prjOverride.Compiler;

            // Compiler args + cfg args + extra args
            var buildCfg  = cmp.GetOrCreateTargetConfiguration(this.CompileTarget);
            var buildArgs = buildCfg.GetArguments(this.DebugMode);
            var cmpArgs   = (buildArgs.OneStepBuildArguments ?? buildArgs.CompilerArguments) + " " +
                            ExtraCompilerArguments + " " + ExtraLinkerArguments;

            //TODO: Distinguish between D1/D2 and probably later versions?
            var a   = D_Parser.Misc.VersionIdEvaluation.GetVersionIds(cmp.PredefinedVersionConstant, cmpArgs, UnittestMode);
            var res = new string[(a == null ? 0 : a.Length) + (CustomVersionIdentifiers == null ? 0: CustomVersionIdentifiers.Length)];

            if (a != null)
            {
                Array.Copy(a, res, a.Length);
            }
            if (CustomVersionIdentifiers != null)
            {
                Array.Copy(CustomVersionIdentifiers, 0, res, res.Length - CustomVersionIdentifiers.Length, CustomVersionIdentifiers.Length);
            }
            gVersionIds = res;
        }
Пример #4
0
        /// <summary>
        /// Builds an array of all global version id definitions.
        /// Used for code completion.
        /// </summary>
        public void UpdateGlobalVersionIdentifiers(DProject prjOverride = null)
        {
            if (prjOverride == null)
            {
                if ((prjOverride = Project) == null)
                {
                    return;
                }
            }

            var cmp = prjOverride.Compiler;

            // Compiler args + cfg args + extra args
            var cmpArgs = ProjectBuilder.BuildOneStepBuildString(prjOverride, new string[0], Selector);

            //TODO: Distinguish between D1/D2 and probably later versions?
            gVersionIds /*var a*/ = D_Parser.Misc.VersionIdEvaluation.GetVersionIds(cmp.PredefinedVersionConstant, cmpArgs, UnittestMode);

            /*var res = new string[(a== null ? 0 : a.Length) + (CustomVersionIdentifiers == null ? 0: CustomVersionIdentifiers.Length)];
             * if(a!=null)
             *      Array.Copy(a,res,a.Length);
             * if(CustomVersionIdentifiers!=null)
             *      Array.Copy(CustomVersionIdentifiers,0,res,res.Length - CustomVersionIdentifiers.Length,CustomVersionIdentifiers.Length);
             * gVersionIds = res;*/
        }
		public DefaultDReferencesCollection(DProject prj, bool initDepCollection = true)
			: base(prj)
		{
			if(initDepCollection)
			{
				ProjectDependencies = new ObservableCollection<string>();
				ProjectDependencies.CollectionChanged+=OnProjectDepChanged;
			}
		}
Пример #6
0
 public DefaultDReferencesCollection(DProject prj, bool initDepCollection = true)
     : base(prj)
 {
     if (initDepCollection)
     {
         ProjectDependencies = new ObservableCollection <string>();
         ProjectDependencies.CollectionChanged += OnProjectDepChanged;
     }
 }
Пример #7
0
		public static void RunExternal(string filePath, DProject project, DProjectConfiguration conf)
		{
			if(console == null)
				console = ExternalConsoleFactory.Instance.CreateConsole(false);
				
			string args = GetCommandArgs(UnittestSettings.UnittestCommand, filePath, project, conf);
			//string execDir = GetExecDir(project, conf);
				
			//Runtime.ProcessService.StartConsoleProcess(cmdParts[0],args,execDir,console,null);
		}
Пример #8
0
        public static void RunExternal(string filePath, DProject project, DProjectConfiguration conf)
        {
            if(console == null)
                console = ExternalConsoleFactory.Instance.CreateConsole(false);

            string[] cmdParts = GetCmdParts(project);
            string args = GetCommandArgs(cmdParts.Length >= 2 ?cmdParts[1] : "",filePath,project,conf);
            string execDir = GetExecDir(project, conf);

            Runtime.ProcessService.StartConsoleProcess(cmdParts[0],args,execDir,console,null);
        }
Пример #9
0
        public void Load(DProject proj, DProjectConfiguration config)
        {
            project = proj;
            configuration = config;

            cbUseDefaultCompiler.Active = proj.UseDefaultCompilerVendor;
            cbIsUnittestConfig.Active = config.UnittestMode;
            cbPreferOneStepCompilation.Active = proj.PreferOneStepBuild;

            OnUseDefaultCompilerChanged ();
            Gtk.TreeIter iter;
            if (cmbCompiler.Model.GetIterFirst (out iter))
                do {
                    if (proj.UsedCompilerVendor == cmbCompiler.Model.GetValue (iter, 0) as string) {
                        cmbCompiler.SetActiveIter (iter);
                        break;
                    }
                } while (cmbCompiler.Model.IterNext (ref iter));

            extraCompilerTextView.Buffer.Text = config.ExtraCompilerArguments;
            extraLinkerTextView.Buffer.Text = config.ExtraLinkerArguments;

            check_LinkThirdPartyLibs.Active = configuration.LinkinThirdPartyLibraries;

            text_BinDirectory.Text = proj.GetRelativeChildPath(config.OutputDirectory);
            text_TargetFile.Text = config.Output;
            text_ObjectsDirectory.Text = config.ObjectDirectory;
            text_DDocDir.Text = config.DDocDirectory;

            if(config.CustomDebugIdentifiers==null)
                text_debugConstants.Text = "";
            else
                text_debugConstants.Text = string.Join(";",config.CustomDebugIdentifiers);
            if(config.CustomVersionIdentifiers == null)
                text_versionConstants.Text = "";
            else
                text_versionConstants.Text = string.Join(";", config.CustomVersionIdentifiers);
            spin_debugLevel.Value = (double)config.DebugLevel;

            // Disable debug-specific fields on non-debug configurations
            text_debugConstants.Sensitive = spin_debugLevel.Sensitive = config.DebugMode;

            if (model_compileTarget.GetIterFirst (out iter))
                do {
                    if (config.CompileTarget == (DCompileTarget)model_compileTarget.GetValue (iter, 1)) {
                        combo_ProjectType.SetActiveIter (iter);
                        break;
                    }
                } while (model_compileTarget.IterNext (ref iter));

            text_Libraries.Buffer.Text = string.Join ("\n", config.ExtraLibraries);
        }
Пример #10
0
		/// <summary>
		/// Compiles a D project.
		/// </summary>
		public BuildResult Build (DProject Project, ConfigurationSelector BuildConfigurationSelector)
		{
			this.Project = Project;
			BuildConfig = Project.GetConfiguration (BuildConfigurationSelector) as DProjectConfiguration;

			if(Ide.IdeApp.Workbench == null)
				_currentConfig = BuildConfig.Selector;

			if (BuildConfig.Project != Project)
				throw new InvalidOperationException ("Wrong project configuration");
			commonMacros = new PrjPathMacroProvider {
				slnPath = Project.ParentSolution != null ? EnsureCorrectPathSeparators(Project.ParentSolution.BaseDirectory) : ""
			};
			BuiltObjects.Clear ();

			if (Compiler == null) {
				var targetBuildResult = new BuildResult ();

				targetBuildResult.AddError ("Project compiler \"" + Project.UsedCompilerVendor + "\" not found");
				targetBuildResult.FailedBuildCount++;

				_currentConfig = null;
				return targetBuildResult;
			}

			var absDir = AbsoluteObjectDirectory (BuildConfig);
			if (!Directory.Exists (absDir))
				Directory.CreateDirectory (absDir);

			BuildResult result;
			if (CanDoOneStepBuild)
				result = DoOneStepBuild ();
			else
				result = DoStepByStepBuild ();

			_currentConfig = null;
			return result;
		}
Пример #11
0
        public static string BuildOneStepBuildString(DProject prj, IEnumerable<string> builtObjects, ConfigurationSelector sel)
        {
            var cfg = prj.GetConfiguration (sel) as DProjectConfiguration;
            var target = prj.GetOutputFileName (sel);

            var rawArgumentString = new StringBuilder();
            var s = GenAdditionalAttributes (prj.Compiler, cfg);
            if(!string.IsNullOrWhiteSpace(s) )
                rawArgumentString.Append(s.Trim()).Append(' ');
            rawArgumentString.Append(BuildArguments(cfg).OneStepBuildArguments.Trim());
            if(!string.IsNullOrEmpty(cfg.ExtraCompilerArguments))
                rawArgumentString.Append(' ').Append(cfg.ExtraCompilerArguments.Trim());
            if (!string.IsNullOrEmpty(cfg.ExtraLinkerArguments))
                rawArgumentString.Append(' ').Append(PrefixedExtraLinkerFlags(cfg));

            var commonMacros = new PrjPathMacroProvider {
                slnPath = prj.ParentSolution != null ? EnsureCorrectPathSeparators(prj.ParentSolution.BaseDirectory) : ""
            };

            var res = FillInMacros(rawArgumentString.ToString(),
                new OneStepBuildArgumentMacroProvider
                {
                    ObjectsStringPattern = prj.Compiler.ArgumentPatterns.ObjectFileLinkPattern,
                    IncludesStringPattern = prj.Compiler.ArgumentPatterns.IncludePathPattern,

                    SourceFiles = builtObjects,
                    Includes = FillInMacros(prj.IncludePaths,commonMacros),
                    Libraries = GetLibraries(cfg, prj.Compiler),

                    RelativeTargetDirectory = cfg.OutputDirectory.ToRelative(prj.BaseDirectory),
                    ObjectsDirectory = ObjectDirectory(cfg),
                    TargetFile = target,
                }, commonMacros);

            return res;
        }
Пример #12
0
        static string GetCommandArgs(string baseCommandArgs, string filePath, DProject project, DProjectConfiguration conf)
        {
            var compiler =project.Compiler;
            ProjectBuilder.PrjPathMacroProvider prjPath = new ProjectBuilder.PrjPathMacroProvider {
                slnPath = project.ParentSolution != null ? ProjectBuilder.EnsureCorrectPathSeparators(project.ParentSolution.BaseDirectory) : ""
            };

            List<string> includes = new List<string>(project.IncludePaths);
            includes.Add(project.BaseDirectory.FullPath);

            string[] src = {filePath};
            OneStepBuildArgumentMacroProvider compilerMacro = new OneStepBuildArgumentMacroProvider
            {
                ObjectsStringPattern = compiler.ArgumentPatterns.ObjectFileLinkPattern,
                IncludesStringPattern = compiler.ArgumentPatterns.IncludePathPattern,

                SourceFiles = src,
                Includes = ProjectBuilder.FillInMacros(includes, prjPath),
                Libraries = ProjectBuilder.GetLibraries(conf, compiler),

            };

            return ProjectBuilder.FillInMacros(baseCommandArgs,compilerMacro, prjPath);
        }
Пример #13
0
        /// <summary>
        /// Returns dependent projects in a topological order (from least to most dependent)
        /// </summary>
        public static List<DProject> GetSortedProjectDependencies(DProject p)
        {
            var l = new List<DProject>();

            var r = new List<DProject>(p.DependingProjects);
            var skippedItems = new List<int>();

            for(int i = r.Count - 1; i >= 0; i--)
                if(r[i].ProjectDependencies.Count == 0)
                {
                    l.Add(r[i]);
                    r.RemoveAt(i);
                }

            // If l.count == 0, there is at least one cycle..

            while(r.Count != 0)
            {
                for(int i = r.Count -1 ; i>=0; i--)
                {
                    bool hasNotYetEnlistedChild = true;
                    foreach(var ch in r[i].DependingProjects)
                        if(!l.Contains(ch))
                        {
                            hasNotYetEnlistedChild = false;
                            break;
                        }

                    if(!hasNotYetEnlistedChild){

                        if(skippedItems.Contains(i))
                            return new List<DProject>();
                        skippedItems.Add(i);
                        continue;
                    }

                    l.Add(r[i]);
                    r.RemoveAt(i);
                }
            }

            return l;
        }
Пример #14
0
		/// <summary>
		/// Builds an array of all global version id definitions.
		/// Used for code completion.
		/// </summary>
		public void UpdateGlobalVersionIdentifiers(DProject prjOverride = null)
		{
			if (prjOverride == null)
				if ((prjOverride = Project) == null)
					return;

			var cmp = prjOverride.Compiler;

			// Compiler args + cfg args + extra args
			var cmpArgs = ProjectBuilder.BuildOneStepBuildString(prjOverride, new string[0], Selector);

			//TODO: Distinguish between D1/D2 and probably later versions?
			gVersionIds /*var a*/ = D_Parser.Misc.VersionIdEvaluation.GetVersionIds(cmp.PredefinedVersionConstant,cmpArgs, UnittestMode);
			/*var res = new string[(a== null ? 0 : a.Length) + (CustomVersionIdentifiers == null ? 0: CustomVersionIdentifiers.Length)];
			if(a!=null)
				Array.Copy(a,res,a.Length);
			if(CustomVersionIdentifiers!=null)
				Array.Copy(CustomVersionIdentifiers,0,res,res.Length - CustomVersionIdentifiers.Length,CustomVersionIdentifiers.Length);
			gVersionIds = res;*/
		}
Пример #15
0
        public static string TraceLogFile(DProject project)
        {
            if(project == null)
                return null;

            var config = project.GetConfiguration(Ide.IdeApp.Workspace.ActiveConfiguration) as DProjectConfiguration;

            if (config == null ||
                config.CompileTarget != DCompileTarget.Executable ||
                !project.Compiler.HasProfilerSupport)
            {
                return null;
            }

            string file = Path.Combine(config.OutputDirectory, "trace.log");
            if (!File.Exists (file))
                return null;
            return file;
        }
Пример #16
0
        public void Parse(DProject project)
        {
            string file = TraceLogFile(project);
            if(file == null)
            {
                profilerPadWidget.AddTracedFunction(0,0,0,0,new DVariable{Name = "trace.log not found.."});
                return;
            }

            lastProfiledProject = project;
            profilerPadWidget.ClearTracedFunctions();

            var ctxt = ResolutionContext.Create(Resolver.DResolverWrapper.CreateCacheList(lastProfiledProject), null, null);

            StreamReader reader = File.OpenText(file);
            string line;
            while ((line = reader.ReadLine()) != null) {
                var m = traceFuncRegex.Match(line);

                if (m.Success)
                {
                    var symName = m.Groups[5].Value;

                    if(symName.StartsWith("="))
                        continue;

                    bool mightBeLegalUnresolvableSymbol;
                    var dn = ExamTraceSymbol(symName, ctxt, out mightBeLegalUnresolvableSymbol);

                    if(dn != null || mightBeLegalUnresolvableSymbol)
                        profilerPadWidget.AddTracedFunction(long.Parse(m.Groups[1].Value), long.Parse(m.Groups[2].Value),
                                                            long.Parse(m.Groups[3].Value), long.Parse(m.Groups[4].Value), dn ?? new DVariable{Name = symName});
                }
            }
        }
Пример #17
0
        public void Load(DProject proj, DProjectConfiguration config)
        {
            project = proj;
            configuration = config;

            cbUseDefaultCompiler.Active = proj.UseDefaultCompilerVendor;
            cbIsUnittestConfig.Active = config.UnittestMode;
            cbPreferOneStepCompilation.Active = proj.PreferOneStepBuild;

            OnUseDefaultCompilerChanged ();
            Gtk.TreeIter iter;
            if (cmbCompiler.Model.GetIterFirst (out iter))
                do {
                    if (proj.UsedCompilerVendor == cmbCompiler.Model.GetValue (iter, 0) as string) {
                        cmbCompiler.SetActiveIter (iter);
                        break;
                    }
                } while (cmbCompiler.Model.IterNext (ref iter));

            extraCompilerTextView.Buffer.Text = config.ExtraCompilerArguments;
            extraLinkerTextView.Buffer.Text = config.ExtraLinkerArguments;

            check_LinkThirdPartyLibs.Active = configuration.LinkinThirdPartyLibraries;

            text_BinDirectory.Text = proj.GetRelativeChildPath(config.OutputDirectory);
            text_TargetFile.Text = config.Output;
            text_ObjectsDirectory.Text = config.ObjectDirectory;
            text_DDocDir.Text = config.DDocDirectory;

            if(config.CustomDebugIdentifiers==null)
                text_debugConstants.Text = "";
            else
                text_debugConstants.Text = string.Join(";",config.CustomDebugIdentifiers);
            if(config.CustomVersionIdentifiers == null)
                text_versionConstants.Text = "";
            else
                text_versionConstants.Text = string.Join(";", config.CustomVersionIdentifiers);
            spin_debugLevel.Value = (double)config.DebugLevel;

            // Disable debug-specific fields on non-debug configurations
            text_debugConstants.Sensitive = spin_debugLevel.Sensitive = config.DebugMode;

            if (model_compileTarget.GetIterFirst (out iter))
                do {
                    if (config.CompileTarget == (DCompileTarget)model_compileTarget.GetValue (iter, 1)) {
                        combo_ProjectType.SetActiveIter (iter);
                        break;
                    }
                } while (model_compileTarget.IterNext (ref iter));

            text_Libraries.Buffer.Text = string.Join ("\n", config.ExtraLibraries);

            model_Platforms.Clear();
            var blackListed = new List<string>();
            foreach (var cfg in proj.Configurations)
                if (cfg.Name == config.Name && cfg.Platform != config.Platform)
                    blackListed.Add(cfg.Platform.ToLower());

            var platform_lower = config.Platform.ToLower();
            foreach (var platform in proj.SupportedPlatforms)
            {
                // Skip already taken platforms
                if(blackListed.Contains(platform.ToLower()))
                    continue;

                var it = model_Platforms.Append();
                if (platform_lower == platform.ToLower())
                    combo_Platform.SetActiveIter(it);
                model_Platforms.SetValue(it, 0, platform);
            }
        }
Пример #18
0
        /// <summary>
        /// Builds an array of all global version id definitions.
        /// Used for code completion.
        /// </summary>
        public void UpdateGlobalVersionIdentifiers(DProject prjOverride = null)
        {
            if (prjOverride == null)
                if ((prjOverride = Project) == null)
                    return;

            var cmp = prjOverride.Compiler;

            // Compiler args + cfg args + extra args
            var buildCfg = cmp.GetOrCreateTargetConfiguration(this.CompileTarget);
            var buildArgs = buildCfg.GetArguments(this.DebugMode);
            var cmpArgs = (buildArgs.OneStepBuildArguments ?? buildArgs.CompilerArguments) + " " +
                ExtraCompilerArguments + " " + ExtraLinkerArguments;

            //TODO: Distinguish between D1/D2 and probably later versions?
            var a = D_Parser.Misc.VersionIdEvaluation.GetVersionIds(cmp.PredefinedVersionConstant,cmpArgs, UnittestMode);
            var res = new string[(a== null ? 0 : a.Length) + (CustomVersionIdentifiers == null ? 0: CustomVersionIdentifiers.Length)];
            if(a!=null)
                Array.Copy(a,res,a.Length);
            if(CustomVersionIdentifiers!=null)
                Array.Copy(CustomVersionIdentifiers,0,res,res.Length - CustomVersionIdentifiers.Length,CustomVersionIdentifiers.Length);
            gVersionIds = res;
        }
Пример #19
0
 public void AnalyseTraceFile(DProject project)
 {
     TraceParser.Clear();
     if(ProfilerModeHandler.IsProfilerMode)
         TraceParser.Parse(project);
 }
Пример #20
0
 static string GetExecDir(DProject project, DProjectConfiguration conf)
 {
     string execDir = conf.OutputDirectory.FullPath;
     if (!Directory.Exists (execDir))
         execDir = project.BaseDirectory.FullPath;
     return execDir;
 }
Пример #21
0
 static string[] GetCmdParts(DProject project)
 {
     return UnittestSettings.UnittestCommand.Split(new string[]{" "}, 2 , StringSplitOptions.RemoveEmptyEntries);
 }
Пример #22
0
        /// <summary>
        /// Compiles a D project.
        /// </summary>
        public BuildResult Build(DProject Project, ConfigurationSelector BuildConfigurationSelector)
        {
            this.Project = Project;
            BuildConfig = Project.GetConfiguration (BuildConfigurationSelector) as DProjectConfiguration;
            commonMacros = new PrjPathMacroProvider {
                slnPath = Project.ParentSolution != null ? EnsureCorrectPathSeparators(Project.ParentSolution.BaseDirectory) : ""
            };
            BuiltObjects.Clear ();

            if (Compiler == null) {
                var targetBuildResult = new BuildResult ();

                targetBuildResult.AddError ("Project compiler \"" + Project.UsedCompilerVendor + "\" not found");
                targetBuildResult.FailedBuildCount++;

                return targetBuildResult;
            }

            if (!Directory.Exists (AbsoluteObjectDirectory))
                Directory.CreateDirectory (AbsoluteObjectDirectory);

            if (CanDoOneStepBuild)
                return DoOneStepBuild ();
            else
                return DoStepByStepBuild ();
        }
Пример #23
0
        public static void GenerateMakefile(DProject prj, DProjectConfiguration cfg, ref string file)
        {
            if (string.IsNullOrEmpty(file))
                file = prj.BaseDirectory.Combine("makefile");

            var code = GenerateMakeCode(prj, cfg);

            File.WriteAllText(file, code);
        }
Пример #24
0
 public static BuildResult CompileProject(IProgressMonitor ProgressMonitor, DProject Project, ConfigurationSelector BuildConfigurationSelector)
 {
     return new ProjectBuilder (ProgressMonitor).Build (Project, BuildConfigurationSelector);
 }
Пример #25
0
        public static string GenerateMakeCode(DProject Project, DProjectConfiguration cfg)
        {
            var compiler = Project.Compiler;

            var s = new StringBuilder();

            // Constants
            var buildCommands = compiler.GetOrCreateTargetConfiguration(cfg.CompileTarget);
            var Arguments = buildCommands.GetArguments(cfg.DebugMode);

            s.AppendLine("compiler=" + compiler.SourceCompilerCommand);
            s.AppendLine("linker=" + buildCommands.Linker);
            s.AppendLine();
            s.AppendLine("target="+ cfg.OutputDirectory.Combine(cfg.CompiledOutputName).ToRelative(Project.BaseDirectory));

            var srcObjPairs = new Dictionary<string, string>();
            var objs= new List<string>();

            foreach (var pf in Project.Files)
            {
                if (pf.BuildAction != BuildAction.Compile)
                    continue;

                var obj = ProjectBuilder.GetRelativeObjectFileName(ProjectBuilder.EnsureCorrectPathSeparators(cfg.ObjectDirectory), pf, DCompilerService.ObjectExtension);

                objs.Add(obj);
                srcObjPairs[pf.FilePath.ToRelative(Project.BaseDirectory)] = obj;
            }

            s.AppendLine("objects = "+ string.Join(" ",objs));
            s.AppendLine();
            s.AppendLine();
            s.AppendLine("all: $(target)");

            // Linker
            s.AppendLine();
            s.AppendLine("$(target): $(objects)");

            var linkArgs = ProjectBuilder.FillInMacros (
                ProjectBuilder.GenAdditionalAttributes(compiler, cfg) +
                Arguments.LinkerArguments + " " + cfg.ExtraLinkerArguments,
                new DLinkerMacroProvider
                {
                    ObjectsStringPattern = "{0}",
                    Objects = new[]{"$(objects)"},
                    TargetFile = "$@",
                    RelativeTargetDirectory = cfg.OutputDirectory.ToRelative (Project.BaseDirectory),
                    Libraries = ProjectBuilder.GetLibraries(cfg, compiler)
                });

            s.AppendLine("\t@echo Linking...");
            s.AppendLine("\t$(linker) "+ linkArgs.Trim());

            // Compiler
            s.AppendLine();

            var compilerCommand = "\t$(compiler) "+ ProjectBuilder.FillInMacros(
                Arguments.CompilerArguments + " " + cfg.ExtraCompilerArguments,
                new DCompilerMacroProvider{
                    IncludePathConcatPattern = compiler.ArgumentPatterns.IncludePathPattern,
                    Includes = Project.IncludePaths,
                    ObjectFile = "$@", SourceFile = "$?"
                })
                // Replace "$?" by $? because the $? macro appends one ' ' (space)
                // to the name which obstructs the source file names
                .Replace("\"$?\"","$?");

            foreach(var kv in srcObjPairs)
            {
                s.AppendLine(kv.Value + " : "+ kv.Key);
                s.AppendLine(compilerCommand);
                s.AppendLine();
            }

            // Clean up
            s.AppendLine("clean:");
            s.AppendLine("\t"+(OS.IsWindows?"del /Q":"$(RM)")+" \"$(target)\" $(objects)");

            return s.ToString();
        }