Hi Gert,
Not sure if my last mail with some more <solution> task updates came through. I got an auto-response from the list saying my mail was a little big and awaiting moderator approval so not sure if it made it to the list...
Anyway, since sending those updates I've done a bit more testing and found a couple of bugs with my changes or the latest mainline. Attached is a revised set of updates that seem to work correctly for me. The changes are in unified diff format and are upto date with the latest mainline.
Let me know if there are more updates you'd like me to make...
Regards,
Simon
diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\ClTask.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\ClTask.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\ClTask.cs Sun Aug 01 20:42:24 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\ClTask.cs Tue Oct 26 17:49:20 2004 @@ -89,7 +89,7 @@ /// </summary> [TaskAttribute("pchfile")] public string PchFile { - get { return (_pchFile != null) ? Path.Combine(OutputDir.FullName, _pchFile) : null; } + get { return (_pchFile != null) ? Path.Combine(OutputDir.Parent.FullName, _pchFile) : null; } set { _pchFile = StringUtils.ConvertEmptyToNull(value); } } @@ -332,11 +332,6 @@ Path.AltDirectorySeparatorChar); writer.WriteLine("/Fo\"{0}{1}\"", OutputDir.FullName, Path.AltDirectorySeparatorChar); - - // specify pch file, if user specified one - if (PchFile != null) { - writer.WriteLine("/Fp\"{0}\"", PchFile); - } // write each of the filenames foreach (string filename in Sources.FileNames) { diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\LibTask.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\LibTask.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\LibTask.cs Fri Jul 16 03:52:02 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\LibTask.cs Sat Nov 20 19:17:12 2004 @@ -158,7 +158,9 @@ // write each of the libdirs foreach (string libdir in LibDirs.DirectoryNames) { + if (libdir.Length > 0) { writer.WriteLine("/LIBPATH:\"{0}\"", libdir); + } } // suppresses display of the sign-on banner diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\LinkTask.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\LinkTask.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VisualCpp\Tasks\LinkTask.cs Fri Jul 16 03:52:02 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VisualCpp\Tasks\LinkTask.cs Sat Nov 20 19:17:54 2004 @@ -186,7 +186,9 @@ // write each of the libdirs foreach (string libdir in LibDirs.DirectoryNames) { + if (libdir.Length > 0) { writer.WriteLine("/LIBPATH:\"{0}\"", libdir); + } } // suppresses display of the sign-on banner diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ConfigurationBase.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ConfigurationBase.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ConfigurationBase.cs Sun Nov 14 23:43:48 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ConfigurationBase.cs Tue Nov 23 23:12:24 2004 @@ -175,6 +175,8 @@ protected internal virtual string ExpandMacro(string macro) { // perform case-insensitive expansion of macros switch (macro.ToLower(CultureInfo.InvariantCulture)) { + case "noinherit": + return ""; case "outdir": // E.g. bin\Debug\ return RelativeOutputDir; case "configurationname": // E.g. Debug diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ProjectBase.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ProjectBase.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ProjectBase.cs Fri Nov 19 04:28:22 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ProjectBase.cs Tue Nov 23 23:13:38 2004 @@ -45,6 +45,7 @@ _projectConfigurations = CollectionsUtil.CreateCaseInsensitiveHashtable(); _buildConfigurations = CollectionsUtil.CreateCaseInsensitiveHashtable(); _extraOutputFiles = CollectionsUtil.CreateCaseInsensitiveHashtable(); + _projectDependencies = new ArrayList(); _solutionTask = solutionTask; _temporaryFiles = temporaryFiles; _outputDir = outputDir; @@ -175,6 +176,11 @@ get { return _extraOutputFiles; } } + + public ArrayList ProjectDependencies { + get { return _projectDependencies; } + } + #endregion Public Instance Properties #region Protected Instance Properties @@ -487,6 +493,7 @@ private GacCache _gacCache; private ReferencesResolver _refResolver; private Hashtable _extraOutputFiles; + private ArrayList _projectDependencies; #endregion Private Instance Fields } diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ProjectReference.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ProjectReference.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\ProjectReference.cs Sun Nov 14 23:43:48 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\ProjectReference.cs Fri Nov 26 15:21:46 2004 @@ -25,6 +25,7 @@ using System.Globalization; using System.IO; using System.Xml; +using System.CodeDom.Compiler; using NAnt.Core; using NAnt.Core.Util; @@ -42,10 +43,6 @@ throw new ArgumentNullException("gacCache"); } - if (projectSettings == null) { - throw new ArgumentNullException("projectSettings"); - } - if (solution == null) { throw new BuildException("Project reference found, but no solution" + " was specified.", Location.UnknownLocation); @@ -57,14 +54,25 @@ _isPrivate = bool.Parse(privateAttribute.Value); } + string referencedProjectGuid = xmlDefinition.GetAttribute("Project"); + if (referencedProjectGuid == null || referencedProjectGuid.Length == 0) { + referencedProjectGuid = xmlDefinition.GetAttribute("ReferencedProjectIdentifier"); + } // determine path of project file string projectFile = solution.GetProjectFileFromGuid( - xmlDefinition.GetAttribute("Project")); + referencedProjectGuid); + + TempFileCollection temporaryFiles; + if (projectSettings != null) { + temporaryFiles = projectSettings.TemporaryFiles; + } else { + temporaryFiles = parent.TemporaryFiles; + } // load referenced project Log(Level.Verbose, "Loading referenced project '{0}'.", projectFile); _project = ProjectFactory.LoadProject(solution, - SolutionTask, projectSettings.TemporaryFiles, gacCache, + SolutionTask, temporaryFiles, gacCache, ReferencesResolver, outputDir, projectFile); } diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\SolutionBase.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\SolutionBase.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\SolutionBase.cs Sun Nov 14 23:43:48 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\SolutionBase.cs Tue Nov 23 22:57:20 2004 @@ -494,6 +494,17 @@ } } } + + // Now go through all the project dependencies and store them in + // the project so they are available for later use (such as link time). + string[] dependencies = GetProjectDependencies(projectGuid); + + foreach (string dependency in dependencies) { + ProjectBase dependencyProject = GetProjectFromGuid(dependency); + if (dependencyProject != null) { + project.ProjectDependencies.Add(dependencyProject); + } + } } } diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcArgumentMap.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcArgumentMap.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcArgumentMap.cs Sun Oct 24 23:03:26 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcArgumentMap.cs Tue Nov 23 22:24:04 2004 @@ -66,34 +66,34 @@ public static VcArgumentMap CreateCLArgumentMap() { VcArgumentMap map = new VcArgumentMap(); - map.AddEnum("AssemblerOutput", null, null, "FA", "FAcs", "FAc", "FAs"); - map.AddBool("BufferSecurityCheck", "GS"); - map.AddEnum("CompileAs", null, null, "TC", "TP"); - map.AddEnum("DebugInformationFormat", null, null, "Z7", "Zd", "Zi", "ZI"); - map.AddBool("EnableFunctionLevelLinking", "Gy"); - map.AddBool("EnableIntrinsicFunctions", "Oi"); - map.AddBool("ExceptionHandling", "EHsc"); - map.AddBool("RuntimeTypeInfo", "GR"); - map.AddEnum("FavorSizeOrSpeed", null, null, "Ot", "Os"); - map.AddBool("GlobalOptimizations", "Og"); - map.AddEnum("InlineFunctionExpansion", null, "Ob0", "Ob1", "Ob2"); - map.AddBool("OmitFramePointers", "Oy"); - map.AddEnum("Optimization", null, "Od", "O1", "O2", "Ox"); - map.AddEnum("RuntimeLibrary", null, "MT", "MTd", "MD", "MDd", "ML", "MLd"); - map.AddBool("StringPooling", "GF"); - map.AddEnum("StructMemberAlignment", null, null, "Zp1", "Zp2", "Zp4", "Zp8", "Zp16"); - map.AddEnum("UsePrecompiledHeader", null, null, "Yc", "YX", "Yu"); - map.AddEnum("WarningLevel", null, "W0", "W1", "W2", "W3", "W4"); + map.AddEnum("AssemblerOutput", null, null, "/FA", "/FAcs", "/FAc", "/FAs"); + map.AddBool("BufferSecurityCheck", "/GS"); + map.AddEnum("CompileAs", null, null, "/TC", "/TP"); + map.AddEnum("DebugInformationFormat", null, null, "/Z7", "/Zd", "/Zi", "/ZI"); + map.AddBool("EnableFunctionLevelLinking", "/Gy"); + map.AddBool("EnableIntrinsicFunctions", "/Oi"); + map.AddBool("ExceptionHandling", "/EHsc"); + map.AddBool("RuntimeTypeInfo", "/GR"); + map.AddEnum("FavorSizeOrSpeed", null, null, "/Ot", "/Os"); + map.AddBool("GlobalOptimizations", "/Og"); + map.AddEnum("InlineFunctionExpansion", null, "/Ob0", "/Ob1", "/Ob2"); + map.AddBool("OmitFramePointers", "/Oy"); + map.AddEnum("Optimization", null, "/Od", "/O1", "/O2", "/Ox"); + map.AddEnum("RuntimeLibrary", null, "/MT", "/MTd", "/MD", "/MDd", "/ML", "/MLd"); + map.AddBool("StringPooling", "/GF"); + map.AddEnum("StructMemberAlignment", null, null, "/Zp1", "/Zp2", "/Zp4", "/Zp8", "/Zp16"); + map.AddEnum("UsePrecompiledHeader", null, "", "/Yc", "/YX", "/Yu"); + map.AddEnum("WarningLevel", null, "/W0", "/W1", "/W2", "/W3", "/W4"); return map; } public static VcArgumentMap CreateLinkerArgumentMap() { VcArgumentMap map = new VcArgumentMap(); - map.AddBool("GenerateDebugInformation", "DEBUG"); - map.AddEnum("LinkIncremental", null, null, "INCREMENTAL:NO", "INCREMENTAL"); - map.AddString("ModuleDefinitionFile", "DEF:"); - map.AddEnum("OptimizeForWindows98", "OPT:", null, "NOWIN98", "WIN98"); - map.AddEnum("SubSystem", "SUBSYSTEM:", null, "CONSOLE", "WINDOWS"); + map.AddBool("GenerateDebugInformation", "/DEBUG"); + map.AddEnum("LinkIncremental", null, null, "/INCREMENTAL:NO", "/INCREMENTAL"); + map.AddString("ModuleDefinitionFile", "/DEF:"); + map.AddEnum("OptimizeForWindows98", "/OPT:", null, "NOWIN98", "WIN98"); + map.AddEnum("SubSystem", "/SUBSYSTEM:", null, "CONSOLE", "WINDOWS"); return map; } @@ -116,9 +116,9 @@ protected string FormatOption(string value) { if (_name == null) { - return "/" + value; + return value; } - return "/" + _name + value; + return _name + value; } } diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcConfiguration.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcConfiguration.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcConfiguration.cs Mon Nov 15 00:11:40 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcConfiguration.cs Tue Nov 23 22:26:44 2004 @@ -152,12 +152,12 @@ get { string linkOutput = GetToolSetting("VCLinkerTool", "OutputFile"); if (linkOutput != null) { - return Path.Combine(OutputDir.FullName, linkOutput); + return Path.Combine(ProjectDir.FullName, linkOutput); } string librarianOutput = GetToolSetting("VCLibrarianTool", "OutputFile"); if (librarianOutput != null) { - return Path.Combine(OutputDir.FullName, librarianOutput); + return Path.Combine(ProjectDir.FullName, librarianOutput); } return OutputDir.Name; diff -u -w -r c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcProject.cs c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcProject.cs --- c:\nant-0.85-nightly-2004-11-22\src\NAnt.VSNet\VcProject.cs Mon Nov 15 00:11:40 2004 +++ c:\nant-0.85-nightly-2004-11-22-changes\src\NAnt.VSNet\VcProject.cs Wed Nov 24 23:17:56 2004 @@ -42,7 +42,6 @@ #region Public Instance Constructors public VcProject(SolutionBase solution, string projectPath, XmlElement xmlDefinition, SolutionTask solutionTask, TempFileCollection tfc, GacCache gacCache, ReferencesResolver refResolver, DirectoryInfo outputDir) : base(solutionTask, tfc, gacCache, refResolver, outputDir) { - // ensure the specified project is actually supported by this class if (!IsSupported(xmlDefinition)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Project '{0}' is not a valid Visual C++ project.", ProjectPath), @@ -56,7 +55,6 @@ if (xmlDefinition == null) { throw new ArgumentNullException("xmlDefinition"); } - _htPlatformConfigurations = CollectionsUtil.CreateCaseInsensitiveHashtable(); _htFiles = CollectionsUtil.CreateCaseInsensitiveHashtable(); _references = new ArrayList(); @@ -218,9 +216,31 @@ return true; } - foreach (VcConfiguration buildConfig in buildConfigs.Keys) { - BuildCPPFiles((ArrayList) buildConfigs[buildConfig], baseConfig, - buildConfig); + + VcConfiguration stdafxConfig = null; + + // If VC project uses precompiled headers then the precompiled header + // output (.pch file) must be generated before compiling any other + // source files. + foreach (VcConfiguration vcConfig in buildConfigs.Keys) { + const string compilerTool = "VCCLCompilerTool"; + Hashtable compilerArgs = vcConfig.GetToolArguments(compilerTool, _clArgMap); + + object o = compilerArgs["UsePrecompiledHeader"]; + + if (o != null) { + string arg = o as string; + if (arg.Equals("/Yc")) { + BuildCPPFiles((ArrayList) buildConfigs[vcConfig], baseConfig, vcConfig); + stdafxConfig = vcConfig; + } + } + } + + foreach (VcConfiguration vcConfig in buildConfigs.Keys) { + if (vcConfig != stdafxConfig) { + BuildCPPFiles((ArrayList) buildConfigs[vcConfig], baseConfig, vcConfig); + } } string libOutput = baseConfig.GetToolSetting("VCLibrarianTool", "OutputFile"); @@ -363,7 +383,7 @@ } } - string metadataDirs = fileConfig.GetToolSetting(compilerTool, "AdditionalUsingDirectories"); + string metadataDirs = MergeCompilerToolSetting(baseConfig, fileConfig, "AdditionalUsingDirectories"); if (!StringUtils.IsNullOrEmpty(metadataDirs)) { foreach (string metadataDir in metadataDirs.Split(';')) { clTask.MetaDataIncludeDirs.DirectoryNames.Add( @@ -401,7 +421,7 @@ Path.GetFileNameWithoutExtension(fileName) + ".obj")); } - string preprocessorDefs = MergePreprocessorDefinitions(baseConfig, fileConfig); + string preprocessorDefs = MergeCompilerToolSetting(baseConfig, fileConfig, "PreprocessorDefinitions"); if (!StringUtils.IsNullOrEmpty(preprocessorDefs)) { foreach (string def in preprocessorDefs.Split(';', ',')) { if (def.Length != 0) { @@ -411,6 +431,34 @@ } } + string undefinePreprocessorDefs = fileConfig.GetToolSetting(compilerTool, "UndefinePreprocessorDefinitions"); + if (!StringUtils.IsNullOrEmpty(undefinePreprocessorDefs)) { + foreach (string def in undefinePreprocessorDefs.Split(';', ',')) { + clTask.Arguments.Add(new Argument("/U")); + clTask.Arguments.Add(new Argument(def)); + } + } + + + string addOptions = baseConfig.GetToolSetting(compilerTool, "AdditionalOptions"); + if (addOptions != null) { + StringReader reader = new StringReader(addOptions); + string addOptionsLine = reader.ReadLine(); + while (addOptionsLine != null) { + foreach(string addOption in addOptionsLine.Split(' ')) { + clTask.Arguments.Add(new Argument(addOption)); + } + + addOptionsLine = reader.ReadLine(); + } + } + + string exceptionHandling = baseConfig.GetToolSetting(compilerTool, "ExceptionHandling"); + if (exceptionHandling == null || exceptionHandling.ToUpper().Equals("TRUE")) { + clTask.Arguments.Add(new Argument("/EHsc")); + } + + if (IsOutputDll(fileConfig)) { clTask.Arguments.Add(new Argument("/D")); clTask.Arguments.Add(new Argument("_WINDLL")); @@ -429,6 +477,11 @@ // with the "UsePrecompiledHeader" argument break; case "UsePrecompiledHeader": + string arg = compilerArgs["UsePrecompiledHeader"] as string; + + // if arg.length == 0 then this configuration explicitly turns + // OFF use of precompiled headers - even if parent config uses it. + if (arg == null || arg.Length > 0) { string headerThrough = compilerArgs["PrecompiledHeaderThrough"] as string; if (headerThrough == null) { headerThrough = "StdAfx.h"; @@ -441,6 +494,7 @@ } clTask.Arguments.Add(new Argument("/Fp\"" + headerFile + "\"")); + } break; default: clTask.Arguments.Add(new Argument((string) compilerArgs[key])); @@ -559,6 +613,19 @@ linkTask.Sources.FileNames.Add(objFile); } + foreach (ProjectBase dependency in ProjectDependencies) { + if (dependency is VcProject) { + VcConfiguration vcConfig = dependency.ProjectConfigurations[baseConfig.Name] as VcConfiguration; + + string libraryName = vcConfig.GetToolSetting("VCLibrarianTool", "OutputFile"); + if (libraryName != null) { + string libOutFile = new FileInfo(Path.Combine( + dependency.ProjectDirectory.FullName, libraryName)).FullName; + linkTask.Sources.FileNames.Add(libOutFile); + } + } + } + string addDeps = baseConfig.ExpandMacros(baseConfig.GetToolSetting(linkerTool, "AdditionalDependencies")); if (addDeps != null) { foreach (string addDep in addDeps.Split(' ')) { @@ -584,9 +651,15 @@ string addOptions = baseConfig.GetToolSetting(linkerTool, "AdditionalOptions"); if (addOptions != null) { - foreach(string addOption in addOptions.Split(' ')) { + StringReader reader = new StringReader(addOptions); + string addOptionsLine = reader.ReadLine(); + while (addOptionsLine != null) { + foreach(string addOption in addOptionsLine.Split(' ')) { linkTask.Arguments.Add(new Argument(addOption)); } + + addOptionsLine = reader.ReadLine(); + } } if (baseConfig.WholeProgramOptimization) { @@ -625,25 +698,28 @@ } /// <summary> - /// Merges the preprocessor definitions of <paramref name="baseConfig" /> + /// Merges the specified tool setting of <paramref name="baseConfig" /> /// with <paramref name="fileConfig" />. /// </summary> /// <remarks> - /// The merge is uppresses when the flag $(noinherit) is defined in + /// The merge is suppressed when the flag $(noinherit) is defined in /// <paramref name="fileConfig" />. /// </remarks> - private string MergePreprocessorDefinitions(VcConfiguration baseConfig, VcConfiguration fileConfig) { + private string MergeCompilerToolSetting(VcConfiguration baseConfig, VcConfiguration fileConfig, string setting) { const string compilerTool = "VCCLCompilerTool"; const string noinherit = "$(noinherit)"; - string preprocessorDefs = fileConfig.GetToolSetting(compilerTool, - "PreprocessorDefinitions"); - if (preprocessorDefs.ToLower(CultureInfo.InvariantCulture).IndexOf(noinherit) == -1) { - preprocessorDefs += ";" + baseConfig.GetToolSetting(compilerTool, - "PreprocessorDefinitions"); + string settingValue = fileConfig.GetToolSetting(compilerTool, setting); + + if (settingValue == null) { + return baseConfig.GetToolSetting(compilerTool, setting); + } + + if (settingValue.ToLower(CultureInfo.InvariantCulture).IndexOf(noinherit) == -1) { + settingValue += ";" + baseConfig.GetToolSetting(compilerTool, setting); } else { - preprocessorDefs = preprocessorDefs.Remove(preprocessorDefs.ToLower(CultureInfo.InvariantCulture).IndexOf(noinherit), noinherit.Length); + settingValue = settingValue.Remove(settingValue.ToLower(CultureInfo.InvariantCulture).IndexOf(noinherit), noinherit.Length); } - return preprocessorDefs; + return settingValue; } #endregion Private Instance Methods