summaryrefslogtreecommitdiff
path: root/src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java')
-rw-r--r--src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java574
1 files changed, 574 insertions, 0 deletions
diff --git a/src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java b/src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java
new file mode 100644
index 0000000..7f21bec
--- /dev/null
+++ b/src/main/java/net/sf/antcontrib/cpptasks/apple/XcodeProjectWriter.java
@@ -0,0 +1,574 @@
+/*
+ *
+ * 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.apple;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+
+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.gcc.GccCCompiler;
+import net.sf.antcontrib.cpptasks.ide.ProjectDef;
+import net.sf.antcontrib.cpptasks.ide.ProjectWriter;
+
+/**
+ * Writes a Apple Xcode project directory.
+ *
+ * Status: Collects file list but does not pick up libraries and settings from
+ * project.
+ *
+ * @author curta
+ */
+public final class XcodeProjectWriter
+ implements ProjectWriter {
+
+ /**
+ * Next object identifier for project file.
+ */
+ private int nextID = 0x08FB7796;
+
+ /**
+ * Constructor.
+ *
+ */
+ public XcodeProjectWriter() {
+ }
+
+ /**
+ * Get next unique ID.
+ * @return unique ID
+ */
+ private String getUniqueID() {
+ return Integer.toString(nextID++, 16) + "FE84155DC02AAC07";
+ }
+
+ /**
+ * Writes a project definition file.
+ *
+ * @param fileName
+ * File name base, writer may append appropriate extension
+ * @param task
+ * cc task for which to write project
+ * @param projectDef
+ * project element
+ * @param targets
+ * compilation targets
+ * @param linkTarget
+ * link target
+ * @throws IOException
+ * if error writing project file
+ */
+ public void writeProject(final File fileName,
+ final CCTask task,
+ final ProjectDef projectDef,
+ final List sources,
+ final Hashtable targets,
+ final TargetInfo linkTarget) throws IOException {
+
+ File xcodeDir = new File(fileName + ".xcode");
+ if (!projectDef.getOverwrite() && xcodeDir.exists()) {
+ throw new BuildException("Not allowed to overwrite project file "
+ + xcodeDir.toString());
+ }
+
+ CommandLineCompilerConfiguration compilerConfig =
+ getBaseCompilerConfiguration(targets);
+ if (compilerConfig == null) {
+ throw new BuildException(
+ "Unable to find compilation target using GNU C++ compiler");
+ }
+
+ String projectName = projectDef.getName();
+ if (projectName == null) {
+ projectName = fileName.getName();
+ }
+ final String basePath = fileName.getAbsoluteFile().getParent();
+
+ xcodeDir.mkdir();
+
+ File xcodeProj = new File(xcodeDir, "project.pbxproj");
+
+ //
+ // assume that all C++ compiles can use the
+ // same settings
+ //
+ CommandLineCompilerConfiguration gccConfig = null;
+
+ Vector sourceList = new Vector(targets.size());
+ Iterator targetIter = targets.values().iterator();
+ while (targetIter.hasNext()) {
+ TargetInfo info = (TargetInfo) targetIter.next();
+ File[] targetsources = info.getSources();
+ for (int i = 0; i < targetsources.length; i++) {
+ sourceList.addElement(new SourceEntry(targetsources[i],
+ getUniqueID(), getUniqueID()));
+ }
+ ProcessorConfiguration procConfig = info.getConfiguration();
+ if (procConfig instanceof CommandLineCompilerConfiguration
+ && gccConfig == null) {
+ gccConfig = (CommandLineCompilerConfiguration) procConfig;
+ }
+ }
+ SourceEntry[] sortedSources = new SourceEntry[sourceList.size()];
+ sourceList.copyInto(sortedSources);
+ Arrays.sort(sortedSources, new Comparator() {
+ public int compare(final Object o1, final Object o2) {
+ return ( (SourceEntry) o1).getFile().getName().compareTo( ( (
+ SourceEntry) o2).getFile().getName());
+ }
+ });
+ File outFile = task.getOutfile();
+
+ Writer writer = new BufferedWriter(new FileWriter(xcodeProj));
+
+ writer.write("// !$*UTF8*$!\n");
+ writer.write(" {\n");
+ writer.write(" archiveVersion = 1;\n");
+ writer.write(" classes = {\n");
+ writer.write(" };\n");
+ writer.write(" objectVersion = 39;\n");
+ writer.write(" objects = {\n");
+ writer.write(" 014CEA520018CE5811CA2923 = {\n");
+ writer.write(" buildRules = (\n");
+ writer.write(" );\n");
+ writer.write(" buildSettings = {\n");
+ writer.write(" COPY_PHASE_STRIP = NO;\n");
+ writer.write(" DEBUGGING_SYMBOLS = YES;\n");
+ writer.write(" GCC_DYNAMIC_NO_PIC = NO;\n");
+ writer.write(" GCC_ENABLE_FIX_AND_CONTINUE = YES;\n");
+ writer.write(" GCC_GENERATE_DEBUGGING_SYMBOLS = YES;\n");
+ writer.write(" GCC_OPTIMIZATION_LEVEL = 0;\n");
+ writer.write(" OPTIMIZATION_CFLAGS = \"-O0\";\n");
+ writer.write(" ZERO_LINK = YES;\n");
+ writer.write(" };\n");
+ writer.write(" isa = PBXBuildStyle;\n");
+ writer.write(" name = Development;\n");
+ writer.write(" };\n");
+ writer.write(" 014CEA530018CE5811CA2923 = {\n");
+ writer.write(" buildRules = (\n");
+ writer.write(" );\n");
+ writer.write(" buildSettings = {\n");
+ writer.write(" COPY_PHASE_STRIP = YES;\n");
+ writer.write(" GCC_ENABLE_FIX_AND_CONTINUE = NO;\n");
+ writer.write(" ZERO_LINK = NO;\n");
+ writer.write(" };\n");
+ writer.write(" isa = PBXBuildStyle;\n");
+ writer.write(" name = Deployment;\n");
+ writer.write(" };\n");
+ writer.write("// 010\n");
+ writer.write("// 011\n");
+ writer.write("// 012\n");
+ writer.write("// 013\n");
+ writer.write("// 014\n");
+ writer.write("// 080\n");
+ writer.write("// 081\n");
+ writer.write("// 082\n");
+ writer.write("// 083\n");
+ writer.write("// 084\n");
+ writer.write(" 08FB7793FE84155DC02AAC07 = {\n");
+ writer.write(" buildSettings = {\n");
+ writer.write(" };\n");
+ writer.write(" buildStyles = (\n");
+ writer.write(" 014CEA520018CE5811CA2923,\n");
+ writer.write(" 014CEA530018CE5811CA2923,\n");
+ writer.write(" );\n");
+ writer.write(" hasScannedForEncodings = 1;\n");
+ writer.write(" isa = PBXProject;\n");
+ writer.write(" mainGroup = 08FB7794FE84155DC02AAC07;\n");
+ writer.write(" projectDirPath = \"\";\n");
+ writer.write(" targets = (\n");
+ writer.write(" D2AAC0620554660B00DB518D,\n");
+ writer.write(" );\n");
+ writer.write(" };\n");
+ writer.write(" 08FB7794FE84155DC02AAC07 = {\n");
+ writer.write(" children = (\n");
+ writer.write(" 08FB7795FE84155DC02AAC07,\n");
+ writer.write(" 1AB674ADFE9D54B511CA2CBB,\n");
+ writer.write(" );\n");
+ writer.write(" isa = PBXGroup;\n");
+ writer.write(" name = ");
+ writer.write(outFile.getName());
+ writer.write(";\n");
+ writer.write(" refType = 4;\n");
+ writer.write(" sourceTree = \"<group>\";\n");
+ writer.write(" };\n");
+ writer.write(" 08FB7795FE84155DC02AAC07 = {\n");
+ writer.write(" children = (\n");
+
+ //
+ // source ID's go here
+ //
+ for (int i = 0; i < sortedSources.length; i++) {
+ writer.write(" ");
+ writer.write(sortedSources[i].getSourceID());
+ writer.write(",\n");
+ }
+
+ writer.write(" );\n");
+ writer.write(" isa = PBXGroup;\n");
+ writer.write(" name = Source;\n");
+ writer.write(" refType = 4;\n");
+ writer.write(" sourceTree = \"<group>\";\n");
+ writer.write(" };\n");
+
+ for (int i = 0; i < sortedSources.length; i++) {
+ //
+ // source definition
+ //
+ SourceEntry entry = sortedSources[i];
+ writer.write(" ");
+ writer.write(entry.getSourceID());
+ writer.write(" = {\n");
+ writer.write(" fileEncoding = 4;\n");
+ writer.write(" isa = PBXFileReference;\n");
+ String sourceName = entry.getFile().getName();
+ if (sourceName.endsWith(".c")) {
+ writer.write(" lastKnownFileType = sourcecode.c.c;\n");
+ } else {
+ writer.write(" lastKnownFileType = sourcecode.cpp.cpp;\n");
+ }
+
+ String relativePath = CUtil.getRelativePath(basePath, entry.getFile());
+ if (!relativePath.equals(sourceName)) {
+ writer.write(" name = ");
+ writer.write(sourceName);
+ writer.write(";\n");
+ }
+ writer.write(" path = ");
+ writer.write(relativePath);
+ writer.write(";\n");
+ writer.write(" refType = 4;\n");
+ writer.write(" sourceTree = \"<group>\";\n");
+ writer.write(" };\n");
+
+ //
+ // build definition
+ //
+ writer.write(" ");
+ writer.write(entry.getBuildID());
+ writer.write(" = {\n");
+ writer.write(" fileRef = ");
+ writer.write(entry.getSourceID());
+ writer.write(";\n");
+ writer.write(" isa = PBXBuildFile;\n");
+ writer.write(" settings = {\n");
+ writer.write(" };\n");
+ writer.write(" };\n");
+
+ }
+ writer.write("// 080\n");
+ writer.write("// 081\n");
+ writer.write("// 082\n");
+ writer.write("// 083\n");
+ writer.write("// 084\n");
+ writer.write("// 1A0\n");
+ writer.write("// 1A1\n");
+ writer.write("// 1A2\n");
+ writer.write("// 1A3\n");
+ writer.write("// 1A4\n");
+ writer.write(" 1AB674ADFE9D54B511CA2CBB = {\n");
+ writer.write(" children = (\n");
+ writer.write(" D2AAC0630554660B00DB518D,\n");
+ writer.write(" );\n");
+ writer.write(" isa = PBXGroup;\n");
+ writer.write(" name = Products;\n");
+ writer.write(" refType = 4;\n");
+ writer.write(" sourceTree = \"<group>\";\n");
+ writer.write(" };\n");
+ writer.write("// 1A0\n");
+ writer.write("// 1A1\n");
+ writer.write("// 1A2\n");
+ writer.write("// 1A3\n");
+ writer.write("// 1A4\n");
+ writer.write("// D20\n");
+ writer.write("// D21\n");
+ writer.write("// D22\n");
+ writer.write("// D23\n");
+ writer.write("// D24\n");
+ writer.write(" D2AAC0600554660B00DB518D = {\n");
+ writer.write(" buildActionMask = 2147483647;\n");
+ writer.write(" files = (\n");
+ writer.write(" );\n");
+ writer.write(" isa = PBXHeadersBuildPhase;\n");
+ writer.write(" runOnlyForDeploymentPostprocessing = 0;\n");
+ writer.write(" };\n");
+ writer.write(" D2AAC0610554660B00DB518D = {\n");
+ writer.write(" buildActionMask = 2147483647;\n");
+ writer.write(" files = (\n");
+
+ //
+ // build ID's
+ //
+ for (int i = 0; i < sortedSources.length; i++) {
+ writer.write(" ");
+ writer.write(sortedSources[i].getBuildID());
+ writer.write(",\n");
+ }
+ writer.write(" );\n");
+ writer.write(" isa = PBXSourcesBuildPhase;\n");
+ writer.write(" runOnlyForDeploymentPostprocessing = 0;\n");
+ writer.write(" };\n");
+ writer.write(" D2AAC0620554660B00DB518D = {\n");
+ writer.write(" buildPhases = (\n");
+ writer.write(" D2AAC0600554660B00DB518D,\n");
+ writer.write(" D2AAC0610554660B00DB518D,\n");
+ writer.write(" );\n");
+ writer.write(" buildRules = (\n");
+ writer.write(" );\n");
+ writer.write(" buildSettings = {\n");
+ writer.write(" DYLIB_COMPATIBILITY_VERSION = 1;\n");
+ writer.write(" DYLIB_CURRENT_VERSION = 1;\n");
+ //
+ // write preprocessor macros
+ //
+ if (gccConfig != null) {
+ String[] options = gccConfig.getPreArguments();
+ boolean hasD = false;
+ for (int i = 0; i < options.length; i++) {
+ if (options[i].startsWith("-D")) {
+ if (!hasD) {
+ writer.write(" GCC_PREPROCESSOR_DEFINITIONS = \"");
+ hasD = true;
+ } else {
+ writer.write(" ");
+ }
+ writer.write(options[i].substring(2));
+ }
+ }
+ if (hasD) {
+ writer.write("\";\n");
+ }
+ }
+ writer.write(" GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;\n");
+ writer.write(" GCC_WARN_UNKNOWN_PRAGMAS = NO;\n");
+ if (gccConfig != null) {
+ File[] includes = gccConfig.getIncludePath();
+ if (includes.length > 0) {
+ writer.write(" HEADER_SEARCH_PATHS = \"");
+ for (int i = 0; i < includes.length; i++) {
+ if (i > 0) {
+ writer.write(" ");
+ }
+ writer.write(CUtil.getRelativePath(basePath, includes[i]));
+ }
+ writer.write("\";\n");
+ }
+ }
+
+
+ String[] linkerArgs = null;
+ ProcessorConfiguration linkConfig = linkTarget.getConfiguration();
+ if (linkConfig instanceof CommandLineLinkerConfiguration) {
+ linkerArgs = ((CommandLineLinkerConfiguration) linkConfig).getPreArguments();
+ }
+
+
+ writer.write(" INSTALL_PATH = /usr/local/lib;\n");
+ if (linkerArgs != null) {
+ boolean hasLibPath = false;
+ for (int i = 0; i < linkerArgs.length; i++) {
+ if (linkerArgs[i].startsWith("-L")) {
+ if (!hasLibPath) {
+ writer.write(" LIBRARY_SEARCH_PATHS = \"");
+ hasLibPath = true;
+ } else {
+ writer.write(" ");
+ }
+ writer.write(linkerArgs[i].substring(2));
+ }
+ }
+ if (hasLibPath) {
+ writer.write("\";\n");
+ }
+ }
+ writer.write(" LIBRARY_STYLE = DYNAMIC;\n");
+ writer.write(" OTHER_CFLAGS = \"\";\n");
+ writer.write(" OTHER_LDFLAGS = \"");
+ if (linkerArgs != null) {
+ String prepend = "";
+ for (int i = 0; i < linkerArgs.length; i++) {
+ if (!linkerArgs[i].startsWith("-L")) {
+ writer.write(prepend);
+ writer.write(linkerArgs[i]);
+ prepend = " ";
+ }
+ }
+ }
+ writer.write("\";\n");
+ writer.write(" OTHER_REZFLAGS = \"\";\n");
+ writer.write(" PRODUCT_NAME = testbsd;\n");
+ writer.write(" SECTORDER_FLAGS = \"\";\n");
+ writer.write(" WARNING_CFLAGS = \"-Wmost\";\n");
+ writer.write(" };\n");
+ writer.write(" dependencies = (\n");
+ writer.write(" );\n");
+ writer.write(" isa = PBXNativeTarget;\n");
+
+ writer.write(" name = ");
+ writer.write(outFile.getName());
+ writer.write(";\n");
+ writer.write(" productName = ");
+ writer.write(outFile.getName());
+ writer.write(";\n");
+ writer.write(" productReference = D2AAC0630554660B00DB518D;\n");
+
+ String productType = "com.apple.product-type.library.dynamic";
+ String prefix = "lib";
+ String suffix = ".dylib";
+ String explicitFileType = "compiled.mach-o.dylib";
+ String outType = task.getOuttype();
+ if ("executable".equals(outType)) {
+ productType = "com.apple.product-type.tool";
+ prefix = "";
+ suffix = "";
+ explicitFileType = "compiled.mach-o.executable";
+ } else if ("static".equals(outType)) {
+ productType = "com.apple.product-type.library.static";
+ suffix = ".a";
+ explicitFileType = "archive.ar";
+ }
+ writer.write(" productType = \"");
+ writer.write(productType);
+ writer.write("\";\n");
+ writer.write(" };\n");
+ writer.write(" D2AAC0630554660B00DB518D = {\n");
+
+ writer.write(" explicitFileType = \"");
+ writer.write(explicitFileType);
+ writer.write("\";\n");
+ writer.write(" includeInIndex = 0;\n");
+ writer.write(" isa = PBXFileReference;\n");
+ writer.write(" path = ");
+ writer.write(outFile.getName());
+ writer.write(suffix);
+ writer.write(";\n");
+ writer.write(" refType = 3;\n");
+ writer.write(" sourceTree = BUILT_PRODUCTS_DIR;\n");
+ writer.write(" };\n");
+ writer.write(" };\n");
+ writer.write(" rootObject = 08FB7793FE84155DC02AAC07;\n");
+ writer.write(" }\n");
+
+ writer.close();
+ }
+
+ /**
+ * Gets the first recognized compiler from the
+ * compilation targets.
+ * @param targets compilation targets
+ * @return representative (hopefully) compiler configuration
+ */
+ private CommandLineCompilerConfiguration
+ getBaseCompilerConfiguration(Hashtable targets) {
+ //
+ // find first target with an GNU 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 GccCCompiler) {
+ return compilerConfig;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Source file with 96-bit source and build ID's.
+ */
+ private static final class SourceEntry {
+ /**
+ * Source file.
+ */
+ private final File file;
+
+ /**
+ * Source ID.
+ */
+ private final String sourceID;
+
+ /**
+ * Build step ID.
+ */
+ private final String buildID;
+
+ /**
+ * Constructor.
+ * @param fileArg source file
+ * @param sourceIDArg source ID
+ * @param buildIDArg build step ID
+ */
+ public SourceEntry(final File fileArg,
+ final String sourceIDArg,
+ final String buildIDArg) {
+ file = fileArg;
+ sourceID = sourceIDArg;
+ buildID = buildIDArg;
+ }
+
+ /**
+ * Get source file.
+ * @return source file
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Get source ID.
+ * @return source ID
+ */
+ public String getSourceID() {
+ return sourceID;
+ }
+
+ /**
+ * Get build step ID.
+ * @return build step ID
+ */
+ public String getBuildID() {
+ return buildID;
+ }
+ }
+}