diff options
Diffstat (limited to 'src/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java')
-rw-r--r-- | src/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/src/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java b/src/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java new file mode 100644 index 0000000..9e6072c --- /dev/null +++ b/src/net/sf/antcontrib/cpptasks/devstudio/VisualStudioNETProjectWriter.java @@ -0,0 +1,409 @@ +/* + * + * Copyright 2004-2005 The Ant-Contrib project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.sf.antcontrib.cpptasks.devstudio; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import net.sf.antcontrib.cpptasks.CCTask; +import net.sf.antcontrib.cpptasks.CUtil; +import net.sf.antcontrib.cpptasks.TargetInfo; +import net.sf.antcontrib.cpptasks.compiler.CommandLineCompilerConfiguration; +import net.sf.antcontrib.cpptasks.compiler.CommandLineLinkerConfiguration; +import net.sf.antcontrib.cpptasks.compiler.ProcessorConfiguration; +import net.sf.antcontrib.cpptasks.ide.ProjectDef; +import net.sf.antcontrib.cpptasks.ide.ProjectWriter; + +import org.apache.tools.ant.BuildException; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.Serializer; +import org.apache.xml.serialize.XMLSerializer; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +/** + * Writes a Visual Studio.NET project file. + * (Visual Studio 5 and 6 project writer is substantially more +* complete at this point). + * @author curta + * + */ +public final class VisualStudioNETProjectWriter + implements ProjectWriter { + /** + * Version of VisualStudio.NET. + */ + private String version; + + /** + * Constructor. + * @param versionArg String VisualStudio.NET version + */ + public VisualStudioNETProjectWriter(final String versionArg) { + this.version = versionArg; + } + + /** + * Writes a project definition file. + * + * @param fileName + * project name for file, should has .cbx extension + * @param task + * cc task for which to write project + * @param projectDef + * project element + * @param sources source files + * @param targets compilation targets + * @param linkTarget link target + * @throws IOException if I/O error + * @throws SAXException if XML serialization error + */ + public void writeProject(final File fileName, + final CCTask task, + final ProjectDef projectDef, + final List sources, + final Hashtable targets, + final TargetInfo linkTarget) throws + IOException, + SAXException { + + boolean isDebug = task.getDebug(); + + String projectName = projectDef.getName(); + if (projectName == null) { + projectName = fileName.getName(); + } + + + File dspFile = new File(fileName + ".dsp"); + if (!projectDef.getOverwrite() && dspFile.exists()) { + throw new BuildException("Not allowed to overwrite project file " + + dspFile.toString()); + } + File dswFile = new File(fileName + ".dsw"); + if (!projectDef.getOverwrite() && dswFile.exists()) { + throw new BuildException("Not allowed to overwrite project file " + + dswFile.toString()); + } + + CommandLineCompilerConfiguration compilerConfig = + getBaseCompilerConfiguration(targets); + if (compilerConfig == null) { + throw new BuildException( + "Unable to generate Visual Studio.NET project " + + "when Microsoft C++ is not used."); + } + + OutputStream outStream = new FileOutputStream(fileName + ".vcproj"); + OutputFormat format = new OutputFormat("xml", "UTF-8", true); + Serializer serializer = new XMLSerializer(outStream, format); + ContentHandler content = serializer.asContentHandler(); + String basePath = fileName.getParentFile().getAbsolutePath(); + content.startDocument(); + AttributesImpl emptyAttrs = new AttributesImpl(); + startElement(content, "VisualStudioProject", new String[] {"ProjectType", + "Version", "Name", "SccProjectName", "SccLocalPath"} + , + new String[] {"Visual C++", this.version, projectName, + "", ""}); + content.startElement(null, "Platforms", "Platforms", emptyAttrs); + startElement(content, "Platform", new String[] {"Name"} + , new String[] {"Win32"}); + content.endElement(null, "Platform", "Platform"); + content.endElement(null, "Platforms", "Platforms"); + content.startElement(null, "Configurations", "Configurations", emptyAttrs); + + String[] configValues = new String[] { + "Debug|Win32", + ".\\Debug", + ".\\Debug", + "2", + "0", + "FALSE"}; + if (!isDebug) { + configValues[0] = "Release|Win32"; + } + + startElement(content, "Configuration", + new String[] {"Name", "OutputDirectory", + "IntermediateDirectory", "ConfigurationType", "UseOfMFC", + "ATLMinimizeCRunTimeLibraryUsage"} + , configValues); + String[] clValues = new String[] { + "VCCLCompilerTool", "0", null, null, + "1", "2", ".\\Debug\\testdllproh.pch", ".\\Debug/", + ".\\Debug/", ".\\Debug/", "3", "TRUE", "4"}; + StringBuffer includeDirs = new StringBuffer(); + StringBuffer defines = new StringBuffer(); + String[] args = compilerConfig.getPreArguments(); + for (int i = 0; i < args.length; i++) { + if (args[i].startsWith("/I")) { + includeDirs.append(args[i].substring(2)); + includeDirs.append(';'); + } + if (args[i].startsWith("/D")) { + defines.append(args[i].substring(2)); + defines.append(";"); + } + } + + if (includeDirs.length() > 0) { + includeDirs.setLength(includeDirs.length() - 1); + } + if (defines.length() > 0) { + defines.setLength(defines.length() - 1); + } + clValues[2] = includeDirs.toString(); + clValues[3] = defines.toString(); + + startElement(content, "Tool", + new String[] {"Name", "Optimization", + "AdditionalIncludeDirectories", + "PreprocessorDefinitions", "RuntimeLibrary", + "UsePrecompiledHeaders", "PrecompiledHeaderFile", + "AssemblerListingLocation", "ObjectFile", "WarningLevel", + "SuppressStartupBanner", "DebugInformationFormat"} + , clValues); + content.endElement(null, "Tool", "Tool"); + + + String[] linkerValues = new String[] {"VCLinkerTool", null, + ".\\Debug/testdllproj.dll", "1", + "TRUE", "TRUE", ".\\Debug\\testdllproh.pdb", "2", + ".\\Debug/testdllproj.lib", "1"}; + + if (!isDebug) { + linkerValues[5] = "FALSE"; + } + + ProcessorConfiguration config = linkTarget.getConfiguration(); + if (config instanceof CommandLineLinkerConfiguration) { + CommandLineLinkerConfiguration linkConfig = + (CommandLineLinkerConfiguration) config; + + File[] linkSources = linkTarget.getAllSources(); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < linkSources.length; i++) { + // + // if file was not compiled or otherwise generated + // + if (targets.get(linkSources[i].getName()) == null) { + String relPath = CUtil.getRelativePath(basePath, linkSources[i]); + // + // if path has an embedded space then + // must quote + if (relPath.indexOf(' ') > 0) { + buf.append('\"'); + buf.append(relPath); + buf.append('\"'); + } else { + buf.append(relPath); + } + buf.append(';'); + } + } + if (buf.length() > 0) { + buf.setLength(buf.length() - 1); + linkerValues[1] = buf.toString(); + } + } + + startElement(content, "Tool", + new String[] {"Name", + "AdditionalDependencies", + "OutputFile", + "LinkIncremental", + "SuppressStartupBanner", + "GenerateDebugInformation", + "ProgramDatabaseFile", + "SubSystem", + "ImportLibrary", + "TargetMachine"} + , linkerValues); + content.endElement(null, "Tool", "Tool"); + content.endElement(null, "Configuration", "Configuration"); + content.endElement(null, "Configurations", "Configurations"); + content.startElement(null, "References", "References", emptyAttrs); + content.endElement(null, "References", "References"); + content.startElement(null, "Files", "Files", emptyAttrs); + + + File[] sortedSources = new File[sources.size()]; + sources.toArray(sortedSources); + Arrays.sort(sortedSources, new Comparator() { + public int compare(final Object o1, final Object o2) { + return ((File) o1).getName().compareTo(((File) o2).getName()); + } + }); + + writeFilteredSources("Source Files", + "cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx", + basePath, sortedSources, content); + + writeFilteredSources("Header Files", "h;hpp;hxx;hm;inl;inc;xsd", + basePath, sortedSources, content); + + writeFilteredSources("Resource Files", + "rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx", + basePath, sortedSources, content); + + content.endElement(null, "Files", "Files"); + content.startElement(null, "Globals", "Globals", emptyAttrs); + content.endElement(null, "Globals", "Globals"); + content.endElement(null, "VisualStudioProject", "VisualStudioProject"); + content.endDocument(); + } + + /** + * Writes a cluster of source files to the project. + * @param name name of filter + * @param filter file extensions + * @param basePath base path for files + * @param sortedSources array of source files + * @param content generated project + * @throws SAXException if invalid content + */ + private void writeFilteredSources(final String name, final String filter, + final String basePath, + final File[] sortedSources, + final ContentHandler content) + throws SAXException { + AttributesImpl filterAttrs = new AttributesImpl(); + filterAttrs.addAttribute(null, "Name", "Name", "#PCDATA", name); + filterAttrs.addAttribute(null, "Filter", "Filter", "#PCDATA", filter); + content.startElement(null, "Filter", "Filter", filterAttrs); + + + AttributesImpl fileAttrs = new AttributesImpl(); + fileAttrs.addAttribute(null, "RelativePath", "RelativePath", + "#PCDATA", ""); + + AttributesImpl fileConfigAttrs = new AttributesImpl(); + fileConfigAttrs.addAttribute(null, "Name", "Name", + "#PCDATA", "Debug|Win32"); + + AttributesImpl toolAttrs = new AttributesImpl(); + toolAttrs.addAttribute(null, "Name", "Name", + "#PCDATA", "VCCLCompilerTool"); + toolAttrs.addAttribute(null, "Optimization", "Optimization", + "#PCDATA", "0"); + toolAttrs.addAttribute(null, "PreprocessorDefinitions", + "PreprocessorDefinitions", "#PCDATA", + "WIN32;_DEBUG;_WINDOWS;$(NoInherit}"); + + for (int i = 0; i < sortedSources.length; i++) { + if (isGroupMember(filter, sortedSources[i])) { + String relativePath = CUtil.getRelativePath(basePath, + sortedSources[i]); + fileAttrs.setValue(0, relativePath); + content.startElement(null, "File", "File", fileAttrs); + content.startElement(null, "FileConfiguration", "FileConfiguration", + fileConfigAttrs); + content.startElement(null, "Tool", "Tool", toolAttrs); + content.endElement(null, "Tool", "Tool"); + content.endElement(null, "FileConfiguration", "FileConfiguration"); + content.endElement(null, "File", "File"); + } + } + content.endElement(null, "Filter", "Filter"); + + } + + /** + * Returns true if the file has an extension that appears in the group filter. + * @param filter String group filter + * @param candidate File file + * @return boolean true if member of group + */ + private boolean isGroupMember(final String filter, final File candidate) { + String fileName = candidate.getName(); + int lastDot = fileName.lastIndexOf('.'); + if (lastDot >= 0 && lastDot < fileName.length() - 1) { + String extension = + ";" + fileName.substring(lastDot + 1).toLowerCase() + ";"; + String semiFilter = ";" + filter + ";"; + return semiFilter.indexOf(extension) >= 0; + } + return false; + } + + + /** + * Start an element. + * @param content ContentHandler content handler + * @param tagName String tag name + * @param attributeNames String[] attribute names + * @param attributeValues String[] attribute values + * @throws SAXException if error writing element + */ + private void startElement(final ContentHandler content, + final String tagName, + final String[] attributeNames, + final String[] attributeValues) + throws SAXException { + AttributesImpl attributes = new AttributesImpl(); + for (int i = 0; i < attributeNames.length; i++) { + if (attributeValues[i] != null) { + attributes.addAttribute(null, attributeNames[i], + attributeNames[i], "#PCDATA", attributeValues[i]); + } + } + content.startElement(null, tagName, tagName, attributes); + } + + /** + * Gets the first recognized compiler from the + * compilation targets. + * @param targets compilation targets + * @return representative (hopefully) compiler configuration + */ + private CommandLineCompilerConfiguration + getBaseCompilerConfiguration(final Hashtable targets) { + // + // find first target with an DevStudio C compilation + // + CommandLineCompilerConfiguration compilerConfig = null; + // + // get the first target and assume that it is representative + // + Iterator targetIter = targets.values().iterator(); + while (targetIter.hasNext()) { + TargetInfo targetInfo = (TargetInfo) targetIter.next(); + ProcessorConfiguration config = targetInfo.getConfiguration(); + String identifier = config.getIdentifier(); + // + // for the first cl compiler + // + if (config instanceof CommandLineCompilerConfiguration) { + compilerConfig = (CommandLineCompilerConfiguration) config; + if (compilerConfig.getCompiler() instanceof DevStudioCCompiler) { + return compilerConfig; + } + } + } + return null; + } + +} |