0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.cnd.makewizard;
0043:
0044: import java.io.BufferedReader;
0045: import java.io.BufferedWriter;
0046: import java.io.File;
0047: import java.io.FileReader;
0048: import java.io.FileWriter;
0049: import java.io.IOException;
0050: import java.text.DateFormat;
0051: import java.text.MessageFormat;
0052: import java.util.ArrayList;
0053: import java.util.Date;
0054: import java.util.HashMap;
0055: import java.util.HashSet;
0056: import java.util.Iterator;
0057: import java.util.LinkedList;
0058: import java.util.ResourceBundle;
0059: import org.netbeans.modules.cnd.api.utils.FortranParser;
0060: import org.netbeans.modules.cnd.api.utils.IpeUtils;
0061: import org.netbeans.modules.cnd.loaders.FortranDataLoader;
0062: import org.openide.DialogDisplayer;
0063: import org.openide.NotifyDescriptor;
0064: import org.openide.util.NbBundle;
0065:
0066: /**
0067: * Generate a Makefile from a MakefileData. This could have been gathered from
0068: * the MakefileWizard or from a file (the latter isn't currently planned but
0069: * is likely to happen in the future).
0070: */
0071:
0072: public class MakefileGenerator {
0073:
0074: /** The date for the Makefile */
0075: private MakefileData md;
0076:
0077: /** The File of the Makefile */
0078: private File fmakefile;
0079:
0080: /** Write the Makefile from here */
0081: private BufferedWriter out;
0082:
0083: /** Make variable helper tool */
0084: private MakeVarName var;
0085:
0086: /** Tells if things are OK */
0087: private boolean status;
0088:
0089: /** One of the COMPLEX_* types */
0090: private boolean doComplex;
0091:
0092: /** Compiling C */
0093: private boolean doC;
0094:
0095: /** Compiling C++ */
0096: private boolean doCpp;
0097:
0098: /** Compiling Fortran */
0099: private boolean doFortran;
0100:
0101: /** Building X-Designer file */
0102: private boolean doXd;
0103:
0104: /** Have assembly files */
0105: private boolean doAssembly;
0106:
0107: /** Reused buffer */
0108: private StringBuffer buf;
0109:
0110: /** For localized strings */
0111: private ResourceBundle bundle;
0112:
0113: private final static int OK = 0; // return from validation method
0114: private final static int BAD = 1; // return from validation method
0115:
0116: /* LINE1 is the first line of a generated Makefile */
0117: private static final String LINE1 = new String(
0118: "## -*- Makefile -*-"); // NOI18N
0119:
0120: /* BLANKCOMMENT is the second line of a generated Makefile */
0121: private static final String BLANKCOMMENT = new String("##"); // NOI18N
0122:
0123: /* LINE_PREFIX is the start of the 3rd line of a generated Makefile */
0124: private static final String LINE_PREFIX = new String("## "); // NOI18N
0125:
0126: /** Define the suffix list used in make. Only used for Fortran builds */
0127: private static final String SUFFIX_LIST = new String(
0128: ".o .c .c~ .cc .cc~ .y .y~ "
0129: + // NOI18N
0130: ".l .l~ .s .s~ .sh .sh~ .S .S~ .ln .h .h~ .f .f~ .F .F~ "
0131: + // NOI18N
0132: ".p .p~ .r .r~ .f90 .f90~ .ftn .ftn~ .cps .cps~ .C .C~ "
0133: + // NOI18N
0134: ".Y .Y~ .L .L~ .java .java~ .class"); // NOI18N
0135:
0136: /** The constructor MUST be passed the MakefileData */
0137: public MakefileGenerator(MakefileData md) {
0138: this .md = md;
0139: bundle = null;
0140: out = null;
0141: doComplex = false;
0142: doCpp = false;
0143: doC = false;
0144: doFortran = false;
0145: doXd = false;
0146: doAssembly = false;
0147:
0148: buf = new StringBuffer(1024);
0149: var = new MakeVarName();
0150: }
0151:
0152: /**
0153: * Generate the Makefile. This is one of 2 public method of this class. Its
0154: * called to generate a Makefile. The data used to generate the Makefile
0155: * comes from the MakefileData passed to the constructor.
0156: *
0157: * @return Returns true if the MakefileData was valid and the Makefile was
0158: * sucessfully created. Returns false if no Makefile could be
0159: * generated. When false is returned, the MakefileWizard should
0160: * stay up so the user can correct the data and create a Makefile.
0161: * If the wizard was removed the user would need to reenter all of
0162: * the Makefile's data.
0163: */
0164: public boolean generate() {
0165:
0166: status = false;
0167: if (initialize()) {
0168: try {
0169: prolog();
0170: compilerSetup();
0171: generateTargetDirectories();
0172: defaultTarget();
0173:
0174: ArrayList tlist = md.getTargetList();
0175: for (int i = 0; i < tlist.size(); i++) {
0176: generateTarget((TargetData) tlist.get(i));
0177: }
0178:
0179: finale();
0180: } catch (MakefileGenerationException ex) {
0181: return false; // keep wizard up
0182: } catch (IOException ex) {
0183: /*
0184: * This exception means an error occurred writing output to the
0185: * Makefile. By the time code in this if clause is executed the
0186: * Makefile has been opened for writing so we know the error is
0187: * a write error, possibly a full disk.
0188: */
0189: if (IpeUtils.IfdefDiagnostics) {
0190: System.out
0191: .println("Failure in Makefile Generation"); // NOI18N
0192: }
0193: fmakefile.delete(); // remove partial Makefile
0194: String msg = getString("MSG_MakefileOutputError"); // NOI18N
0195: String title = getString("TITLE_MakefileOutputError"); // NOI18N
0196: NotifyDescriptor nd = new NotifyDescriptor(msg, title,
0197: NotifyDescriptor.OK_CANCEL_OPTION,
0198: NotifyDescriptor.ERROR_MESSAGE, new Object[] {
0199: NotifyDescriptor.OK_OPTION,
0200: NotifyDescriptor.CANCEL_OPTION },
0201: NotifyDescriptor.OK_OPTION);
0202: Object ret = DialogDisplayer.getDefault().notify(nd);
0203: if (ret.equals(NotifyDescriptor.OK_OPTION)) {
0204: return false; // keep MakefileWizard up
0205: } else {
0206: return true; // Remove MakefileWizard
0207: }
0208: }
0209: }
0210:
0211: return status;
0212: }
0213:
0214: /**
0215: * Do the initializatios necessary before creating the Makefile. This
0216: * includes:
0217: *
0218: * - Validate the existance of the build directory or create it
0219: * - Validate the existance of the Makefile's directory or creat it
0220: * - Verify the Makefile doesn't exist, or if it exists, that its one
0221: * created by the Makefile wizard (which can be overwritten)
0222: * - Validate each target for completeness
0223: */
0224: private boolean initialize() {
0225: NotifyDescriptor nd;
0226: String msg;
0227: String title;
0228:
0229: if (bundle == null) {
0230: bundle = NbBundle.getBundle(MakefileGenerator.class);
0231: }
0232: title = getString("DLG_ErrorDialogTitle"); // NOI18N
0233:
0234: checkTargetFlags();
0235:
0236: // Do some validation
0237: if (validateOrCreateCwd() != OK
0238: || validateOrCreateMakefileDir() != OK) {
0239: return false;
0240: }
0241:
0242: /*
0243: * Check if the Makefile exists. Don't overwrite a non-generated
0244: * Makefile since thats probably not what the user intended. Go ahead
0245: * and overwrite if its one we've written. Also inform the user if we
0246: * can't overwrite the Makefile.
0247: */
0248: if (fmakefile.exists() && fmakefile.length() > 0) {
0249: if (fmakefile.canRead()) {
0250: msg = null;
0251: if (!generatedMakefile(fmakefile)) {
0252: msg = MessageFormat.format(
0253: getString("MSG_NonGeneratedMakefile"), // NOI18N
0254: new Object[] { md.getMakefileName() });
0255: }
0256: } else {
0257: msg = MessageFormat.format(
0258: getString("MSG_CannotReadMakefile"), // NOI18N
0259: new Object[] { md.getMakefileName() });
0260: }
0261:
0262: if (msg != null) {
0263: nd = new NotifyDescriptor(msg, title,
0264: NotifyDescriptor.DEFAULT_OPTION,
0265: NotifyDescriptor.ERROR_MESSAGE,
0266: new Object[] { NotifyDescriptor.OK_OPTION },
0267: NotifyDescriptor.OK_OPTION);
0268: DialogDisplayer.getDefault().notify(nd);
0269: return false;
0270: }
0271: }
0272:
0273: /*
0274: * Verify that the requested Makefile actualy performs something and
0275: * that all targets are complete. If it isn't complete, inform the user
0276: * but don't generate the Makefile. Let the user fix the specification
0277: * first.
0278: */
0279: if (targetIsIncomplete()) {
0280: msg = MessageFormat.format(
0281: getString("MSG_TargetIsIncomplete"), // NOI18N
0282: new Object[] { md.getMakefileName() });
0283: nd = new NotifyDescriptor(msg, title,
0284: NotifyDescriptor.DEFAULT_OPTION,
0285: NotifyDescriptor.ERROR_MESSAGE,
0286: new Object[] { NotifyDescriptor.OK_OPTION },
0287: NotifyDescriptor.OK_OPTION);
0288: DialogDisplayer.getDefault().notify(nd);
0289: return false;
0290: }
0291:
0292: /*
0293: * The directory exists so we try and create the file by opening an
0294: * output stream. Set the OutputStreamWriter if it succeeds or post
0295: * an error dialog for failure.
0296: */
0297: try {
0298: out = new BufferedWriter(new FileWriter(fmakefile));
0299: } catch (IOException e) {
0300: msg = MessageFormat.format(
0301: getString("MSG_CannotCreateMakefile"), // NOI18N
0302: new Object[] { md.getMakefileName() });
0303:
0304: nd = new NotifyDescriptor(msg, title,
0305: NotifyDescriptor.DEFAULT_OPTION,
0306: NotifyDescriptor.ERROR_MESSAGE,
0307: new Object[] { NotifyDescriptor.OK_OPTION },
0308: NotifyDescriptor.OK_OPTION);
0309: DialogDisplayer.getDefault().notify(nd);
0310: return false;
0311: }
0312:
0313: return true;
0314: }
0315:
0316: /** Emit compiler flags used in the Makefile */
0317: private void compilerSetup() throws IOException {
0318:
0319: if (out != null
0320: && (doC || doXd || doCpp || doFortran || doAssembly)) {
0321: String line = getString("MFG_CompilerFlags"); // NOI18N
0322: out.write(line, 0, line.length());
0323:
0324: /*
0325: * The first section compiler path variables. These are only emitted
0326: * if the user specifies a pathname in the Select Compiler Path
0327: * panel (which implies it must be a Complex Makefile). This is
0328: * not true for X-Designer since the default make.rules file doesn't know
0329: * about XDesigner.
0330: */
0331: if (doC || doXd || doAssembly) {
0332: buf.delete(0, buf.length());
0333: appendToolsetDepMacro("CC", md.getCCompilerSun(), md
0334: .getCCompilerGNU()); // NOI18N
0335: out.write(buf.toString(), 0, buf.length());
0336: }
0337: if (doCpp || doXd) {
0338: buf.delete(0, buf.length());
0339: //appendToolsetDepMacro("CCC", md.getCppCompilerSun(), "CXX", md.getCppCompilerGNU());
0340: appendMacro("CCC", md.getCppCompiler(md.getToolset())); // NOI18N
0341: appendMacro("CXX", md.getCppCompiler(md.getToolset())); // NOI18N
0342: out.write(buf.toString(), 0, buf.length());
0343: }
0344: if (doFortran) {
0345: buf.delete(0, buf.length());
0346: //appendToolsetDepMacro("F90C", md.getFCompilerSun(), "FC", md.getFCompilerGNU());
0347: //appendToolsetDepMacro("FCDRIVER", "$(COMPILE.f90)", "$(COMPILE.f)");
0348: //appendToolsetDepMacro("FLDRIVER", "$(LINK.f90)", "$(LINK.f)");
0349: appendToolsetDepMacro("FC", md.getFCompilerSun(), md
0350: .getFCompilerGNU()); // NOI18N
0351: out.write(buf.toString(), 0, buf.length());
0352: }
0353: if (doAssembly) {
0354: buf.replace(0, buf.length(), "AS="); // NOI18N
0355: buf.append(md.getAsmPath());
0356: buf.append('\n');
0357: out.write(buf.toString(), 0, buf.length());
0358: }
0359:
0360: /*
0361: * Now set some Makefile variables. Some of these (like CFLAGS and
0362: * CCFLAGS) will have target specific counterparts. But since the
0363: * default compiler rules use these we also set them.
0364: */
0365: CompilerFlags copts = md.getCompilerFlags();
0366: if (doC || doCpp || doFortran) {
0367: buf.delete(0, buf.length());
0368: appendToolsetDepMacro("BASICOPTS", copts
0369: .getBasicOptionsSun(), copts
0370: .getBasicOptionsGNU()); // NOI18N
0371: out.write(buf.toString(), 0, buf.length());
0372: }
0373: if (doC) {
0374: buf.delete(0, buf.length());
0375: String flagsSun = copts.getCFlagsSun();// + md.getConformFlagCSun();
0376: String flagsGNU = copts.getCFlagsGNU();// + md.getConformFlagCGNU();
0377: appendToolsetDepMacro("CFLAGS", flagsSun, flagsGNU); // NOI18N
0378: out.write(buf.toString(), 0, buf.length());
0379: }
0380:
0381: if (doCpp) {
0382: buf.delete(0, buf.length());
0383: //String flagsSun = copts.getCcFlagsSun();
0384: //String flagsGNU = copts.getCcFlagsGNU();
0385: String flags = copts.getCcFlags(md.getToolset());
0386: //appendToolsetDepMacro("CCFLAGS", flagsSun, "CXXFLAGS", flagsGNU);
0387: appendMacro("CCFLAGS", flags); // NOI18N
0388: appendMacro("CXXFLAGS", flags); // NOI18N
0389: out.write(buf.toString(), 0, buf.length());
0390:
0391: buf.delete(0, buf.length());
0392: appendToolsetDepMacro("CCADMIN", "CCadmin -clean", "");// NOI18N
0393: out.write(buf.toString(), 0, buf.length());
0394: }
0395:
0396: if (doXd) {
0397: /*
0398: * X-Designer compiles are done from the X-Designer generated Makefile.
0399: * To force the X-Designer Makefile to use the same CFLAGS and CCFLAGS
0400: * we are using we create it with several X resources set to the
0401: * desired CFLAGS/CCFLAGS.
0402: */
0403: buf.replace(0, buf.length(), "XDESIGNER=xdesigner"); // NOI18N
0404: buf
0405: .append(" -xrm \"xdesigner.cDebugFlags: $(CFLAGS)\" "); // NOI18N
0406: buf
0407: .append("-xrm \"xdesigner.cppDebugFlags: $(CCFLAGS)\"\n");// NOI18N
0408: buf.append("XDROOT="); // NOI18N
0409: buf.append(System.getProperty("netbeans.home")); // NOI18N
0410: buf.append("/platform/$(OSVARIANT)/prod"); // NOI18N
0411: buf.append("\nXDFLAGS = $(MAKEFLAGS) "); // NOI18N
0412: buf.append("XDROOT=$(XDROOT) CC=$(CC) CCC=$(CCC) "); // NOI18N
0413: if (md.getConformLevelCppSun() != 0) { // FIXUP ???
0414: buf.append("ABICCFLAGS=-features=no%conststrings"); // NOI18N
0415: }
0416: out.write(buf.toString(), 0, buf.length());
0417: out.newLine();
0418: }
0419:
0420: if (doFortran) {
0421: buf.delete(0, buf.length());
0422: //appendToolsetDepMacro("F90FLAGS", copts.getF90Flags(), "FFLAGS", copts.getF90Flags());
0423: appendMacro("FFLAGS", copts.getF90Flags()); // NOI18N
0424: out.write(buf.toString(), 0, buf.length());
0425: }
0426:
0427: out.newLine();
0428: out.newLine();
0429: }
0430: }
0431:
0432: /**
0433: * The first target in a Makefile is the default target and is the one
0434: * used if no explicit targets are specified. In our generated Makefiles,
0435: * this target is called "all" and depends on all of the targets named in
0436: * the Makfile.
0437: */
0438: private void defaultTarget() throws IOException {
0439:
0440: if (out != null) {
0441: ArrayList tlist = md.getTargetList();
0442:
0443: buf.replace(0, buf.length(), "all:"); // NOI18N
0444: for (int i = 0; i < tlist.size(); i++) {
0445: TargetData t = (TargetData) tlist.get(i);
0446: buf.append(" "); // NOI18N
0447: String dir = getOutputDirectory(t);
0448: if (t.isCompilable() && dir.length() > 0
0449: && !dir.equals(".")) { // NOI18N
0450: var.setTargetName(t.getName());
0451: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
0452: buf.append("/"); // always unix separator // NOI18N
0453: } else {
0454: if (t.getName().compareTo("all") == 0) { // NOI18N
0455: /* Target 'all' is already in the list - nothing to do */
0456: buf.delete(0, buf.length());
0457: return;
0458: }
0459: }
0460: buf.append(t.getName());
0461: }
0462: out.write(buf.toString(), 0, buf.length());
0463:
0464: out.newLine();
0465: out.newLine();
0466: }
0467: }
0468:
0469: /** Emit the prologue portion of the Makefile */
0470: private void prolog() throws IOException {
0471:
0472: if (out != null) {
0473: out.write(LINE1, 0, LINE1.length());
0474: out.newLine();
0475: out.write(BLANKCOMMENT, 0, BLANKCOMMENT.length());
0476: out.newLine();
0477:
0478: buf.replace(0, buf.length(), getString("MFG_User")); // NOI18N
0479: buf.append(getUserName());
0480: buf.append('\n');
0481: out.write(buf.toString(), 0, buf.length());
0482:
0483: buf.replace(0, buf.length(), getString("MFG_Time")); // NOI18N
0484: buf.append(getTimestamp());
0485: buf.append('\n');
0486: out.write(buf.toString(), 0, buf.length());
0487:
0488: buf.replace(0, buf.length(), getString("MFG_CreateMsg")); // NOI18N
0489: out.write(buf.toString(), 0, buf.length());
0490:
0491: out.write(BLANKCOMMENT, 0, BLANKCOMMENT.length());
0492: out.newLine();
0493:
0494: buf.replace(0, buf.length(), getString("MFG_DoNotEditMsg"));// NOI18N
0495: out.write(buf.toString(), 0, buf.length());
0496:
0497: out.write(BLANKCOMMENT, 0, BLANKCOMMENT.length());
0498: out.newLine();
0499:
0500: if (doFortran) {
0501: buf.replace(0, buf.length(),
0502: getString("MFG_SuffixList")); // NOI18N
0503: buf.append(".SUFFIXES\n"); // NOI18N
0504: buf.append(".SUFFIXES: "); // NOI18N
0505: buf.append(SUFFIX_LIST);
0506: out.newLine();
0507: out.write(buf.toString(), 0, buf.length());
0508: out.newLine();
0509: }
0510:
0511: /*
0512: out.newLine();
0513: buf.replace(0, buf.length(), "PLATFORM :sh= uname -p | sed s/i386/x86/\n"); // NOI18N
0514: buf.append("OSVARIANT=$(PLATFORM)-SunOS\n"); // NOI18N
0515: out.newLine();
0516: out.write(buf.toString(), 0, buf.length());
0517: */
0518: // Emit TOOLSET macro only if used
0519: if (md.getToolset() == MakefileData.SUNGNU_TOOLSET_TYPE) {
0520: buf = new StringBuffer(1024);
0521: buf.append("# Type of makefile: SUN, GNU, ...\n"); // NOI18N
0522: buf.append("TOOLSET\t= $(shell echo \"GNU\")\n"); // NOI18N
0523: buf.append("TOOLSET:sh\t= echo `echo \"SUN\"`\n"); // NOI18N
0524: out.newLine();
0525: out.write(buf.toString(), 0, buf.length());
0526: }
0527: ArrayList tlist = md.getTargetList();
0528: boolean usingGenericPlatform = false;
0529: boolean usingSharedLib = false;
0530: for (int i = 0; i < tlist.size(); i++) {
0531: TargetData t = (TargetData) tlist.get(i);
0532: if (t.getOutputDirectory().equals(
0533: getString("OutputDirectoryPlatform"))) {
0534: usingGenericPlatform = true;
0535: }
0536: if (t.getTargetType() == TargetData.SIMPLE_SHAREDLIB
0537: || t.getTargetType() == TargetData.COMPLEX_SHAREDLIB) {
0538: usingSharedLib = true;
0539: }
0540: }
0541: // Emit OS macro only if used
0542: if (usingGenericPlatform
0543: || (usingSharedLib && md.getMakefileOS() == MakefileData.UNIX_OS_TYPE)) {
0544: // OS
0545: buf = new StringBuffer(1024);
0546: buf.append("# OS: SunOS, Linux, ...`\n"); // NOI18N
0547: int toolset = md.getToolset();
0548: if (toolset == MakefileData.GNU_TOOLSET_TYPE
0549: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
0550: buf.append("OS\t\t= $(shell /bin/uname)\n"); // NOI18N
0551: }
0552: if (toolset == MakefileData.SUN_TOOLSET_TYPE
0553: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
0554: buf.append("OS:sh\t\t= echo `/bin/uname`\n"); // NOI18N
0555: }
0556: out.newLine();
0557: out.write(buf.toString(), 0, buf.length());
0558: }
0559: // Emit PROCESSOR and PLATFORM macros only if used
0560: if (usingGenericPlatform) {
0561: // Processor
0562: buf = new StringBuffer(1024);
0563: buf.append("# Processor type: sparc, i686, ...\n"); // NOI18N
0564: int toolset = md.getToolset();
0565: if (toolset == MakefileData.GNU_TOOLSET_TYPE
0566: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
0567: buf.append("PROCESSOR\t= $(shell /bin/uname -p)\n"); // NOI18N
0568: }
0569: if (toolset == MakefileData.SUN_TOOLSET_TYPE
0570: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
0571: buf
0572: .append("PROCESSOR:sh\t= echo `/bin/uname -p``\n"); // NOI18N
0573: }
0574: out.newLine();
0575: out.write(buf.toString(), 0, buf.length());
0576:
0577: // Platform
0578: buf = new StringBuffer(1024);
0579: buf.append("# Platform\n"); // NOI18N
0580: buf.append("PLATFORM\t= $(OS)-$(PROCESSOR)\n"); // NOI18N
0581: out.newLine();
0582: out.write(buf.toString(), 0, buf.length());
0583: }
0584:
0585: out.newLine();
0586: out.newLine();
0587: }
0588: }
0589:
0590: /**
0591: * Emit the variable definitions for the target (output) directories. This
0592: * needs to be done before the targets are defined because target n can
0593: * reference the target directory in target n+1. If the target directory
0594: * isn't defined before target n then the reference has no value.
0595: */
0596: private void generateTargetDirectories() throws IOException {
0597: ArrayList tlist = md.getTargetList();
0598:
0599: if (doC || doXd || doCpp || doFortran || doAssembly) {
0600: String com = getString("MFG_TargetDirectories"); // NOI18N
0601: out.write(com, 0, com.length());
0602: for (int i = 0; i < tlist.size(); i++) {
0603: TargetData t = (TargetData) tlist.get(i);
0604:
0605: if (t.isCompilable()) {
0606: String tdir = getOutputDirectory(t);
0607: String cwd = md
0608: .getBaseDirectory(MakefileData.EXPAND);
0609:
0610: /*
0611: * We always emit a TARGETDIR_* = line. Sometimes we need
0612: * to add a target to create this directory. We do that
0613: * whenever its not "." or the current directory (which is
0614: * the build directory). If we need the create target we
0615: * set a boolean here and create it later.
0616: */
0617: buf.replace(0, buf.length(), "TARGETDIR_"); // NOI18N
0618: buf.append(t.getName());
0619: buf.append("="); // NOI18N
0620: String targetDir = getOutputDirectory(t);
0621: if (targetDir.length() == 0
0622: || targetDir.equals(cwd)
0623: || (targetDir.length() == 1 && targetDir
0624: .charAt(0) == '.')) {
0625: buf.append(new String(".\n")); // NOI18N
0626: } else {
0627: buf.append(targetDir);
0628: buf.append('\n');
0629: }
0630: out.write(buf.toString(), 0, buf.length());
0631: }
0632: }
0633: out.newLine();
0634: out.newLine();
0635: }
0636: }
0637:
0638: /** Emit code for a target */
0639: private void generateTarget(TargetData t) throws IOException,
0640: MakefileGenerationException {
0641:
0642: if (out != null) {
0643: var.setTargetName(t.getName());
0644:
0645: buf.replace(0, buf.length(), getString("MFG_Target")); // NOI18N
0646: buf.append(t.getName());
0647: buf.append('\n');
0648: out.write(buf.toString(), 0, buf.length());
0649:
0650: if (t.isCompilable()) {
0651: // A compilable target
0652: targetSetup(t);
0653: linkOrArchive(t);
0654: explicitRules(t);
0655: } else {
0656: makeTarget(t);
0657: }
0658: }
0659: }
0660:
0661: /**
0662: * Do whatever needs doing to finish the Makefile. This includes:
0663: *
0664: * <UL>
0665: * <LI>Adding targets to create the target directories for each target
0666: * <LI>Creating a clean target which cleans up after each target
0667: * <LI>Optional Solaris dependency information (Makefile will not run
0668: * on non Solaris platfors with this information)
0669: * </UL>
0670: */
0671: private void finale() throws IOException {
0672:
0673: if (out != null) {
0674: ArrayList tlist = md.getTargetList();
0675: String cwd = md.getBaseDirectory(MakefileData.EXPAND);
0676: HashSet mkhash = new HashSet(tlist.size(), 1.0F);
0677: String dir;
0678: StringBuffer cb = new StringBuffer(1024);
0679: boolean wasClean = false;
0680:
0681: for (int i = 0; i < tlist.size(); i++) {
0682: TargetData t = (TargetData) tlist.get(i);
0683: var.setTargetName(t.getName());
0684:
0685: // Build the HashSet used in creating TARGETDIR_<tname> dirs
0686: dir = getOutputDirectory(t);
0687: if (t.isCompilable() && dir.length() > 0
0688: && !dir.equals(".") && !dir.equals(cwd)) { // NOI18N
0689: mkhash.add(t);
0690: }
0691:
0692: // Gather the lines to be be $(RM)'ed by the clean target
0693: if (t.getTargetType() != TargetData.COMPLEX_MAKE_TARGET
0694: && t.getTargetType() != TargetData.COMPLEX_CUSTOM_TARGET) {
0695: cb.append(" \\\n\t\t"); // NOI18N
0696: cb.append(var.makeRef("TARGETDIR_")); // NOI18N
0697: cb.append('/');
0698: cb.append(t.getName());
0699: String[] srcs = t.getSourcesList();
0700: for (int j = 0; j < srcs.length; j++) {
0701: if (!t.isHdrFile(srcs[j])
0702: && !t.isXdFile(srcs[j])) {
0703: String newobj = objectOf(srcs[j]);
0704: if (newobj != null) {
0705: cb.append(" \\\n\t\t"); // NOI18N
0706: cb.append(var.makeRef("TARGETDIR_")); // NOI18N
0707: cb.append('/');
0708: cb.append(newobj);
0709: }
0710: }
0711: }
0712: } else {
0713: if (t.getName().compareTo("clean") == 0) { // NOI18N
0714: /* Target 'clean' is already in the list */
0715: wasClean = true;
0716: }
0717:
0718: }
0719: }
0720:
0721: boolean doClean = false;
0722: if (cb.length() > 0) {
0723: doClean = true;
0724: String com = getString("MFG_CleanTarget"); // NOI18N
0725: out.write(com, 0, com.length());
0726: buf.replace(0, buf.length(), "clean:\n\trm -f"); // NOI18N
0727: out.write(buf.toString(), 0, buf.length());
0728: out.write(cb.toString(), 0, cb.length());
0729: out.write('\n');
0730: }
0731:
0732: if (mkhash.size() > 0) {
0733: if (doClean && doCpp) {
0734: buf.replace(0, buf.length(), "\t$(CCADMIN)\n"); // NOI18N
0735: out.write(buf.toString(), 0, buf.length());
0736: }
0737: cb.delete(0, cb.length());
0738:
0739: if (doClean && doFortran) {
0740: buf.replace(0, buf.length(), "\trm -f *.mod\n"); // NOI18N
0741: out.write(buf.toString(), 0, buf.length());
0742: }
0743:
0744: buf.replace(0, buf.length(),
0745: getString("MFG_CreateTargetDir")); // NOI18N
0746: Iterator iter = mkhash.iterator();
0747:
0748: while (iter.hasNext()) {
0749: TargetData t = (TargetData) iter.next();
0750: var.setTargetName(t.getName());
0751:
0752: // Create a rmdir command the directory
0753: cb.append("\trm -f -r "); // NOI18N
0754: cb.append(var.makeRef("TARGETDIR_")); // NOI18N
0755: cb.append('\n');
0756:
0757: // Create $(TARGETDIR) if its not "." or cwd
0758: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
0759: buf.append(":\n\tmkdir -p "); // NOI18N
0760: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
0761: buf.append("\n"); // NOI18N
0762: }
0763:
0764: // Emit the rmdir commands
0765: if (doClean) {
0766: cb.append("\n\n"); // NOI18N
0767: out.write(cb.toString(), 0, cb.length());
0768: }
0769: buf.append("\n\n"); // NOI18N
0770: out.write(buf.toString(), 0, buf.length());
0771: }
0772: if ((doClean == false) && (wasClean == false)) {
0773: /* Add empty target clean: (for consistency) */
0774: String com = getString("MFG_CleanTarget"); // NOI18N
0775: out.write(com, 0, com.length());
0776: buf.replace(0, buf.length(), "clean:\n\n"); // NOI18N
0777: out.write(buf.toString(), 0, buf.length());
0778: }
0779:
0780: /* Emit the KEEP_STATE stuff */
0781: buf.replace(0, buf.length(), getString("MFG_KeepState")); // NOI18N
0782: buf.append(".KEEP_STATE:\n"); // NOI18N
0783: buf.append(".KEEP_STATE_FILE:.make.state."
0784: + md.defaultOutputDirectory() + "\n"); // NOI18N
0785: buf.append("\n"); // NOI18N
0786: out.write(buf.toString(), 0, buf.length());
0787:
0788: status = true;
0789: out.close();
0790: out = null;
0791: }
0792: }
0793:
0794: /**
0795: * All of the compilable target types need some similar setup code. This
0796: * includes variables for the target directory, cpp flags, and object
0797: * variables.
0798: */
0799: private void targetSetup(TargetData t) throws IOException,
0800: MakefileGenerationException {
0801: String[] srcs;
0802:
0803: if (out != null) {
0804: String tname = t.getName();
0805:
0806: // Generate target flags (like CFLAGS_<target-name>) for each lang
0807: String flags = generateTargetFlags(t);
0808: if (flags.length() > 0) {
0809: out.write(flags, 0, flags.length());
0810: }
0811:
0812: // Generate the includes list in CPPFLAGS_<target-name>
0813: String[] includesList = t.getIncludesList();
0814: if (includesList != null && includesList.length > 0) {
0815: String incs = doList(var.makeName("CPPFLAGS_"), "-I",
0816: includesList); // NOI18N
0817: out.write(incs, 0, incs.length());
0818: }
0819:
0820: /*
0821: * Now emit the OBJS_<target-name> variable. Ignore .xd files (they
0822: * will be handled later).
0823: */
0824: StringBuffer lbuf = new StringBuffer(80);
0825: lbuf.append(" \\\n\t"); // NOI18N
0826: lbuf.append(var.makeRef("TARGETDIR_")); // NOI18N
0827: lbuf.append('/');
0828: String tdir = lbuf.toString();
0829:
0830: buf.replace(0, buf.length(), var.makeName("OBJS_")); // NOI18N
0831: buf.append(" = "); // NOI18N
0832:
0833: if (doFortran && md.isModuleEnabled()) {
0834: srcs = getOrderedSources(t);
0835: } else {
0836: srcs = t.getSourcesList();
0837: }
0838: for (int i = 0; i < srcs.length; i++) {
0839: if (!t.isHdrFile(srcs[i]) && !t.isXdFile(srcs[i])) {
0840: String newobj = objectOf(srcs[i]);
0841: if (newobj != null) {
0842: buf.append(tdir);
0843: buf.append(newobj);
0844: }
0845: }
0846: }
0847: buf.append('\n');
0848: out.write(buf.toString(), 0, buf.length());
0849:
0850: // Now set up the library options
0851: if (t.isLinked() && (t.isComplex() || t.containsXdFiles())) {
0852: boolean needLDLIBS = false;
0853:
0854: String syslibs = getSysLibs(t);
0855: if (syslibs.length() > 0) {
0856: out.write(syslibs, 0, syslibs.length());
0857: needLDLIBS = true;
0858: }
0859:
0860: String userlibs = getUserLibs(t);
0861: if (userlibs.length() > 0) {
0862: out.write(userlibs, 0, userlibs.length());
0863: needLDLIBS = true;
0864: }
0865: String deplibs = getDependLibs(t);
0866: if (deplibs.length() > 0) {
0867: out.write(deplibs, 0, deplibs.length());
0868: }
0869: if (needLDLIBS) {
0870: buf.replace(0, buf.length(), var
0871: .makeName("LDLIBS_")); // NOI18N
0872: buf.append(" = "); // NOI18N
0873: buf.append(var.makeRef("USERLIBS_")); // NOI18N
0874: //buf.append(' ');
0875: //buf.append(var.makeRef("SYSLIBS_")); // NOI18N
0876: buf.append('\n');
0877: out.write(buf.toString(), 0, buf.length());
0878: }
0879: }
0880:
0881: out.newLine();
0882: out.newLine();
0883:
0884: // Do the X-Designer variables
0885: if (t.containsXdFiles()) {
0886: String vtargs = generateXdTargetVars(t);
0887: out.write(vtargs, 0, vtargs.length());
0888: out.newLine();
0889: }
0890: }
0891: }
0892:
0893: /**
0894: * Generate some special make variables for each X-Designer file in a target.
0895: *
0896: * @param t The TargetData
0897: */
0898: private String generateXdTargetVars(TargetData t) {
0899:
0900: buf.replace(0, buf.length(),
0901: getString("MFG_XDesignerTargetVars")); // NOI18N
0902:
0903: String[] srcs = t.getSourcesList();
0904: for (int i = 0; i < srcs.length; i++) {
0905: if (t.isXdFile(srcs[i])) {
0906: xdTargetFile(t, srcs[i]);
0907: }
0908: }
0909: return buf.toString();
0910: }
0911:
0912: /** Emit X-Designer target variables for this file */
0913: private void xdTargetFile(TargetData t, String file) {
0914: String vname = getXdTargetName(t, file);
0915:
0916: buf.append("XDMAKEFILE_"); // NOI18N
0917: buf.append(vname);
0918: buf.append(" = "); // NOI18N
0919: buf.append(vname);
0920: buf.append("_Makefile\nXD_OBJS_FILE_"); // NOI18N
0921: buf.append(vname);
0922: buf.append(" = xd_objs_"); // NOI18N
0923: buf.append(vname);
0924: buf.append("\nXD_OBJS_"); // NOI18N
0925: buf.append(vname);
0926: buf.append(" = `/bin/cat -s "); // NOI18N
0927: buf.append(getOutputDirectory(t));
0928: buf.append("/xd_objs_"); // NOI18N
0929: buf.append(vname);
0930: buf
0931: .append(" | \\\n\tawk 'BEGIN { RS=\" \"} {if (NF > 0) { print \""); // NOI18N
0932: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
0933: buf.append("/\" $$0 }}'`\nXD_LINK_ARGS_FILE_"); // NOI18N
0934: buf.append(vname);
0935: buf.append(" = xd_link_args_"); // NOI18N
0936: buf.append(vname);
0937: buf.append("\nXD_LINK_ARGS_"); // NOI18N
0938: buf.append(vname);
0939: buf.append(" = `/bin/cat -s "); // NOI18N
0940: buf.append(getOutputDirectory(t));
0941: buf.append("/xd_link_args_"); // NOI18N
0942: buf.append(vname);
0943: buf.append("; exit 0`\nXDFLAGS_"); // NOI18N
0944: buf.append(vname);
0945: buf.append(" = -f $(XDMAKEFILE_"); // NOI18N
0946: buf.append(vname);
0947: buf.append(") $(XDFLAGS)\n\n"); // NOI18N
0948: }
0949:
0950: /**
0951: * When generating names related to X-Designer we need to specify a name which
0952: * is unique to both the target and X-Designer file. We do this by concatenating
0953: * some text + target + xd-file-name. For readability, we change any '.'
0954: * characters to '_'.
0955: */
0956:
0957: private String getXdTargetName(TargetData t, String file) {
0958: StringBuffer name = new StringBuffer(256);
0959:
0960: name.append(t.getName());
0961: name.append('_');
0962: for (int i = 0; i < file.length(); i++) {
0963: if (file.charAt(i) == '.' || file.charAt(i) == '/') {
0964: name.append('_');
0965: } else {
0966: name.append(file.charAt(i));
0967: }
0968: }
0969: return name.toString();
0970: }
0971:
0972: /** Emit the link information */
0973: private void linkOrArchive(TargetData t) throws IOException {
0974: int type = t.getTargetType();
0975:
0976: if (out != null && type != TargetData.COMPLEX_MAKE_TARGET
0977: && type != TargetData.COMPLEX_CUSTOM_TARGET) {
0978: out.write(getString("MFG_LinkOrArchive")); // NOI18N
0979:
0980: buf.replace(0, buf.length(), var.makeRef("TARGETDIR_")); // NOI18N
0981: buf.append('/');
0982: buf.append(t.getName());
0983: buf.append(": "); // NOI18N
0984: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
0985: buf.append(' ');
0986: buf.append(var.makeRef("OBJS_")); // NOI18N
0987: if (type == TargetData.COMPLEX_EXECUTABLE
0988: || type == TargetData.COMPLEX_SHAREDLIB) {
0989: buf.append(' ');
0990: buf.append(var.makeRef("DEPLIBS_")); // NOI18N
0991: }
0992: if (t.containsXdFiles()) {
0993: buf.append(xdLinkDependencies(t));
0994: }
0995: buf.append('\n');
0996: buf.append('\t');
0997:
0998: switch (type) {
0999: case TargetData.SIMPLE_EXECUTABLE:
1000: case TargetData.COMPLEX_EXECUTABLE:
1001: // don't care if its SIMPLE_ or COMPLEX_ in this call...
1002: buf.append(linkLine(t, TargetData.SIMPLE_EXECUTABLE));
1003: break;
1004:
1005: case TargetData.SIMPLE_ARCHIVE:
1006: case TargetData.COMPLEX_ARCHIVE:
1007: if (t.containsCppFiles()) {
1008: //buf.append("$(CCC) -xar -o $@ "); // NOI18N
1009: StringBuffer bufx = new StringBuffer(1024);
1010: appendToolsetDepMacro(bufx, "ARCPP",
1011: "$(CCC) -xar -o $@ ",
1012: "$(AR) $(ARFLAGS) $@ "); // NOI18N
1013: out.write(bufx.toString(), 0, bufx.length());
1014: buf.append("$(ARCPP) "); // NOI18N
1015: } else {
1016: buf.append("$(AR) $(ARFLAGS) $@ "); // NOI18N
1017: }
1018: buf.append(var.makeRef("OBJS_")); // NOI18N
1019: buf.append('\n');
1020: break;
1021:
1022: case TargetData.SIMPLE_SHAREDLIB:
1023: case TargetData.COMPLEX_SHAREDLIB:
1024: // don't care if its SIMPLE_ or COMPLEX_ in this call...
1025: buf.append(linkLine(t, type));
1026: break;
1027: }
1028:
1029: out.write(buf.toString(), 0, buf.length());
1030: out.newLine();
1031: out.newLine();
1032: }
1033: }
1034:
1035: private void explicitRules(TargetData t) throws IOException {
1036:
1037: if (out != null) {
1038: int i;
1039:
1040: String msg = getString("MFG_CompileRuleComment"); // NOI18N
1041: out.write(msg, 0, msg.length());
1042:
1043: // Create a compile line for each source file
1044: String[] srcs = t.getSourcesList();
1045: for (i = 0; i < srcs.length; i++) {
1046: compileLine(t, srcs[i]);
1047: }
1048:
1049: out.newLine();
1050: out.newLine();
1051:
1052: if (t.containsXdFiles()) {
1053: msg = getString("MFG_XDesignerCompileRule"); // NOI18N
1054: out.write(msg, 0, msg.length());
1055: buf.delete(0, buf.length());
1056: for (i = 0; i < srcs.length; i++) {
1057: if (t.isXdFile(srcs[i])) {
1058: buf.append(xdCompile(t, srcs[i]));
1059: }
1060: }
1061: out.write(buf.toString(), 0, buf.length());
1062:
1063: out.newLine();
1064: out.newLine();
1065: }
1066: }
1067:
1068: }
1069:
1070: /** Emit the target lines and actions to compile the X-Designer file */
1071: private String xdCompile(TargetData t, String file) {
1072: String vname = getXdTargetName(t, file);
1073:
1074: String l1 = MessageFormat
1075: .format(
1076: "$(TARGETDIR_{0})/$(XDMAKEFILE_{1}): $(TARGETDIR_{0}) {2}\n\t$(XDESIGNER) -m $(TARGETDIR_{0})/$(XDMAKEFILE_{1}) {2}\n\n", // NOI18N
1077: new Object[] { t.getName(), vname, file });
1078: String l2 = MessageFormat
1079: .format(
1080: "$(TARGETDIR_{0})/$(XD_OBJS_FILE_{1}): $(TARGETDIR_{0}) $(TARGETDIR_{0})/$(XDMAKEFILE_{1}) {2}\n\t$(XDESIGNER) -G $(TARGETDIR_{0}) {2}\n", // NOI18N
1081: new Object[] { t.getName(), vname, file });
1082: String l3 = MessageFormat
1083: .format(
1084: "\tcd $(TARGETDIR_{0}); $(MAKE) $(XDFLAGS_{1}) info-objects > $(XD_OBJS_FILE_{1})\n\tcd $(TARGETDIR_{0}); $(MAKE) $(XDFLAGS_{1}) info-link > $(XD_LINK_ARGS_FILE_{1})\n\tcd $(TARGETDIR_{0}); $(MAKE) $(XDFLAGS_{1}) all-objects\ntest::\n\n", // NOI18N
1085: new Object[] { t.getName(), vname, file });
1086: return new StringBuffer(1024).append(l1).append(l2).append(l3)
1087: .toString();
1088: }
1089:
1090: /** Generate the code for COMPLEX_MAKE_TARGETS and COMPLEX_CUSTOM_TARGETS */
1091: private void makeTarget(TargetData t) throws IOException {
1092:
1093: buf.replace(0, buf.length(), t.getName());
1094: /* Why this???
1095: if (t.getName().equals("clean")) { // NOI18N
1096: buf.append(":: "); // NOI18N
1097: } else {
1098: buf.append(": "); // NOI18N
1099: }
1100: */
1101: buf.append(": "); // NOI18N
1102: String dependsOn = t.getDependsOn();
1103: if (dependsOn != null && dependsOn.length() > 0) {
1104: buf.append(dependsOn);
1105: }
1106: buf.append('\n');
1107:
1108: if (t.getTargetType() == TargetData.COMPLEX_MAKE_TARGET) {
1109: String dir = t.getSubdirectory();
1110: if (dir != null && dir.length() > 0) {
1111: buf.append("\tcd "); // NOI18N
1112: buf.append(dir);
1113: buf.append("; $(MAKE) "); // NOI18N
1114: } else {
1115: buf.append("\t$(MAKE) "); // NOI18N
1116: }
1117: String mflags = t.getMakeFlags();
1118: if (mflags != null && mflags.length() > 0) {
1119: buf.append(mflags);
1120: buf.append(' ');
1121: }
1122:
1123: String target = t.getTargetName();
1124: if (target != null && target.length() > 0) {
1125: buf.append(target);
1126: }
1127: buf.append('\n');
1128: } else {
1129: ArrayList actions = t.getActions();
1130: for (int i = 0; i < actions.size(); i++) {
1131: String line = actions.get(i).toString().trim();
1132: if (line.length() == 0) {
1133: break; // stop processing after 1st target
1134: }
1135: buf.append('\t');
1136: buf.append(line);
1137: buf.append('\n');
1138: }
1139: }
1140: buf.append("\n\n"); // NOI18N
1141: out.write(buf.toString(), 0, buf.length());
1142: }
1143:
1144: /**
1145: * Generate a compile line for a source file.
1146: *
1147: * @param t The TargetData
1148: * @param src The source file to be compiled
1149: */
1150: private void compileLine(TargetData t, String src)
1151: throws IOException {
1152: String compiler;
1153: String flagBase;
1154:
1155: // First, see what language we are generating
1156: if (t.isCppFile(src)) {
1157: compiler = "$(COMPILE.cc)"; // NOI18N
1158: flagBase = "CCFLAGS_"; // NOI18N
1159: } else if (t.isCFile(src)) {
1160: compiler = "$(COMPILE.c)"; // NOI18N
1161: flagBase = "CFLAGS_"; // NOI18N
1162: } else if (t.isFortranFile(src)) {
1163: compiler = "$(COMPILE.f)"; // NOI18N
1164: flagBase = "FFLAGS_"; // NOI18N
1165: } else if (t.isHdrFile(src)) {
1166: return; // don't try and compile .h files
1167: } else if (t.isXdFile(src)) {
1168: return; // do X-Designer files in separate section
1169: } else if (t.isAssemblyFile(src)) {
1170: compiler = "$(AS)"; // NOI18N
1171: flagBase = "ASFLAGS_"; // NOI18N
1172: } else {
1173: if (IpeUtils.IfdefDiagnostics) {
1174: System.out
1175: .println("Generator: Can't determine language of "
1176: + src); // NOI18N
1177: }
1178: return;
1179: }
1180:
1181: String newobj = objectOf(src);
1182: if (newobj == null) {
1183: return;
1184: }
1185:
1186: // Now generate the target line
1187: buf.replace(0, buf.length(), var.makeRef("TARGETDIR_")); // NOI18N
1188: buf.append('/');
1189: buf.append(newobj);
1190: buf.append(": "); // NOI18N
1191: buf.append(var.makeRef("TARGETDIR_")); // NOI18N
1192: buf.append(' ');
1193: buf.append(src);
1194: buf.append("\n\t"); // NOI18N
1195: buf.append(compiler);
1196: buf.append(' ');
1197: buf.append(var.makeRef(flagBase));
1198: buf.append(' ');
1199: buf.append(var.makeRef("CPPFLAGS_")); // NOI18N
1200: buf.append(" -o $@ "); // NOI18N
1201: buf.append(src);
1202: buf.append("\n\n"); // NOI18N
1203:
1204: out.write(buf.toString(), 0, buf.length());
1205: }
1206:
1207: /** Reorder the sources list based on Fortran module dependencies */
1208: private String[] getOrderedSources(TargetData t)
1209: throws MakefileGenerationException {
1210: String[] old = t.getSourcesList();
1211: ArrayList neu = new ArrayList();
1212: LinkedList flist = new LinkedList();
1213: String options = md.getCompilerFlags().getF90Flags();
1214: HashMap moduleList = new HashMap();
1215: boolean firstTime = true;
1216: int nidx = 0;
1217:
1218: // First pass: Go through all the sources and put all non-fortran sources in the
1219: // neu list. The fortran source files go in flist to be reordered and added later.
1220: for (int i = 0; i < old.length; i++) {
1221: String file = old[i];
1222:
1223: if (isFortranFile(file)) {
1224:
1225: if (file.charAt(0) != '/') {
1226: file = md.getBaseDirectory() + File.separator
1227: + file;
1228: }
1229: FortranParser parser = new FortranParser(file, options,
1230: true, true);
1231: ArrayList list = parser.parser();
1232:
1233: if (list == null) {
1234: if (firstTime) {
1235: firstTime = false;
1236: String title = getString("DLG_ErrorDialogTitle"); // NOI18N
1237: String msg = getString("MSG_ModuleDependencyError"); // NOI18N
1238: NotifyDescriptor nd = new NotifyDescriptor(
1239: msg,
1240: title,
1241: NotifyDescriptor.DEFAULT_OPTION,
1242: NotifyDescriptor.ERROR_MESSAGE,
1243: new Object[] { NotifyDescriptor.OK_OPTION },
1244: NotifyDescriptor.OK_OPTION);
1245:
1246: // Post the Error Window
1247: DialogDisplayer.getDefault().notify(nd);
1248: }
1249: return old;
1250: } else if (list.size() == 0) {
1251: // Fortran files which do not define/use modules
1252: neu.add(file);
1253: } else {
1254: // Fortran files which DO define and/or use modules
1255: flist.add(new FortranFile(file, list));
1256:
1257: for (int j = 0; j < list.size(); j++) {
1258: String entry = list.get(j).toString();
1259:
1260: // Add all module definitions to the module list. Verify its not a
1261: // duplicate definition (which would be an error).
1262: if (entry.charAt(0) == 'M') {
1263: Object o = moduleList.get(entry
1264: .substring(1));
1265: if (o != null) {
1266: if (firstTime) {
1267: firstTime = false;
1268: String title, msg;
1269:
1270: title = getString("DLG_ErrorDialogTitle"); // NOI18N
1271: msg = MessageFormat
1272: .format(
1273: getString("MSG_DuplicateModuleError"), // NOI18N
1274: new Object[] {
1275: entry
1276: .substring(1), // module name
1277: t.getName(), // target name
1278: file, // 2nd file name
1279: o
1280: .toString() // 1st file path
1281: });
1282: NotifyDescriptor nd = new NotifyDescriptor(
1283: msg,
1284: title,
1285: NotifyDescriptor.DEFAULT_OPTION,
1286: NotifyDescriptor.ERROR_MESSAGE,
1287: new Object[] { NotifyDescriptor.OK_OPTION },
1288: NotifyDescriptor.OK_OPTION);
1289:
1290: // Post the Error Window
1291: DialogDisplayer.getDefault()
1292: .notify(nd);
1293: throw new MakefileGenerationException();
1294: }
1295: } else {
1296: moduleList
1297: .put(entry.substring(1), file);
1298: }
1299: }
1300: }
1301: }
1302: } else {
1303: // non-Fortran sources go to the head of the list
1304: neu.add(file);
1305: }
1306: }
1307:
1308: // Second stage: Visit each entry in flist and create the dependsOn list
1309: Iterator iter = flist.iterator();
1310: while (iter.hasNext()) {
1311: FortranFile file = (FortranFile) iter.next();
1312: ArrayList list = file.getRawList();
1313:
1314: for (int j = 0; j < list.size(); j++) {
1315: String entry = list.get(j).toString();
1316:
1317: if (entry.charAt(0) == 'U') {
1318: String dep = (String) moduleList.get(entry
1319: .substring(1));
1320:
1321: if (dep != null && !dep.equals(file.getName())) {
1322: file.addDependsOn(dep);
1323: }
1324: }
1325: }
1326: }
1327:
1328: /*
1329: * Third stage: Order the files based on the dependency graph.
1330: */
1331: while (flist.size() > 0) {
1332: boolean foundOne = false;
1333:
1334: iter = flist.iterator();
1335: while (iter.hasNext()) {
1336: FortranFile file = (FortranFile) iter.next();
1337:
1338: if (file.getDependsOn() == null) {
1339: neu.add(file.getName());
1340: iter.remove();
1341: remove(flist.iterator(), file.getName());
1342: foundOne = true;
1343: break;
1344: }
1345: }
1346:
1347: if (foundOne == false) {
1348: // We only have circular dependencies left
1349:
1350: if (firstTime) {
1351: firstTime = false;
1352: String title = getString("DLG_ErrorDialogTitle"); // NOI18N
1353: String msg = getString("MSG_CircularDependency"); // NOI18N
1354: NotifyDescriptor nd = new NotifyDescriptor(
1355: msg,
1356: title,
1357: NotifyDescriptor.DEFAULT_OPTION,
1358: NotifyDescriptor.ERROR_MESSAGE,
1359: new Object[] { NotifyDescriptor.OK_OPTION },
1360: NotifyDescriptor.OK_OPTION);
1361:
1362: // Post the Error Window
1363: DialogDisplayer.getDefault().notify(nd);
1364: }
1365:
1366: // Arbitrarily remove a dependsOn and see if this breaks the logjam
1367: iter = flist.iterator();
1368: FortranFile file = (FortranFile) iter.next();
1369: remove(flist.iterator(), null);
1370: }
1371: }
1372:
1373: return (String[]) neu.toArray(new String[neu.size()]);
1374: }
1375:
1376: /** Remove references to this file from all dependsOn lists */
1377: private void remove(Iterator iter, String name) {
1378:
1379: while (iter.hasNext()) {
1380: FortranFile file = (FortranFile) iter.next();
1381:
1382: ArrayList deps = file.getDependsOn();
1383: if (deps != null) {
1384: for (int i = 0; i < deps.size(); i++) {
1385: if (name == null || name.equals(deps.get(i))) {
1386: deps.remove(i);
1387: if (deps.size() == 0) {
1388: file.setDependsOn(null);
1389: }
1390: break;
1391: }
1392: }
1393: }
1394: }
1395: }
1396:
1397: /** Check to see if file is a fortran file (just looking at the extension) */
1398: private boolean isFortranFile(String file) {
1399: return FortranDataLoader.getInstance().getExtensions()
1400: .isRegistered(file);
1401: }
1402:
1403: /** A class holding module definition and use information for a Fortran file */
1404: private class FortranFile {
1405:
1406: /** The file name of a Fortran 90 file */
1407: private String name;
1408:
1409: /** The raw module/use information returned by FortranParser.parser() */
1410: private ArrayList rawList;
1411:
1412: /** The (possibly null) list of modules this file uses (depends on) */
1413: private ArrayList dependsOn;
1414:
1415: /** Create one of these for each Fortran file */
1416: public FortranFile(String name, ArrayList rawList) {
1417: this .name = new String(name);
1418: this .rawList = rawList;
1419: dependsOn = null;
1420: }
1421:
1422: /** Add a use record to this file */
1423: public final void addDependsOn(String dep) {
1424:
1425: if (dependsOn == null) {
1426: dependsOn = new ArrayList();
1427: }
1428:
1429: for (int i = 0; i < dependsOn.size(); i++) {
1430: if (dep.equals(dependsOn.get(i).toString())) {
1431: return; // already in the list
1432: }
1433: }
1434: dependsOn.add(dep);
1435: }
1436:
1437: /** Get the dependsOn of this file */
1438: public final ArrayList getDependsOn() {
1439: return dependsOn;
1440: }
1441:
1442: /** Set the dependsOn of this file */
1443: public final void setDependsOn(ArrayList dependsOn) {
1444: this .dependsOn = dependsOn;
1445: }
1446:
1447: /** Getter for the name */
1448: public final String getName() {
1449: return name;
1450: }
1451:
1452: /** Get the raw data list */
1453: public final ArrayList getRawList() {
1454: return rawList;
1455: }
1456: }
1457:
1458: /**
1459: * Remove the suffix of a src file and replace it with 'o'. Also
1460: * remove any leading directory information. The object file will
1461: * be generated in the OBJS_<target> directory.
1462: *
1463: * @param file The source filename
1464: * @return The object file name
1465: */
1466: private String objectOf(String file) {
1467: StringBuffer obj = new StringBuffer(80);
1468: int start = file.lastIndexOf('/') + 1;
1469: int dot = file.substring(start).lastIndexOf('.');
1470:
1471: if (dot >= 0) {
1472: obj.append(file.substring(start, start + dot + 1));
1473: obj.append('o');
1474: return obj.toString();
1475: } else {
1476: return null;
1477: }
1478: }
1479:
1480: private void sharedLibFlags(TargetData t) throws IOException {
1481: StringBuffer bufx = new StringBuffer(1024);
1482: appendOSDepMacro(bufx, var.makeName("SHAREDLIB_FLAGS_"),
1483: "-G -norunpath -h " + t.getName() + " ", "-shared ",
1484: "-dynamiclib -install_name " + t.getName()); // NOI18N
1485: out.write(bufx.toString(), 0, bufx.length());
1486: }
1487:
1488: /**
1489: * Build a link line for either an executable or shared library.
1490: *
1491: * @param t The TargetData
1492: * @param type The type (Executable or SharedLib)
1493: */
1494: private String linkLine(TargetData t, int type) throws IOException {
1495: StringBuffer lbuf = new StringBuffer(256);
1496: String linker;
1497: String flags;
1498:
1499: // Set compiler and flags
1500: if (t.containsCppFiles()) {
1501: linker = "$(LINK.cc) "; // NOI18N
1502: flags = "CCFLAGS_"; // NOI18N
1503: } else if (t.containsFortranFiles()) {
1504: linker = "$(LINK.f) "; // NOI18N
1505: flags = "FFLAGS_"; // NOI18N
1506: } else {
1507: linker = "$(LINK.c) "; // NOI18N
1508: flags = "CFLAGS_"; // NOI18N
1509: }
1510:
1511: // Now start emiting the link line
1512: lbuf.append(linker);
1513: lbuf.append(var.makeRef(flags));
1514: lbuf.append(' ');
1515: lbuf.append(var.makeRef("CPPFLAGS_")); // NOI18N
1516: lbuf.append(" -o $@ "); // NOI18N
1517: lbuf.append(var.makeRef("OBJS_")); // NOI18N
1518: lbuf.append(' ');
1519:
1520: if (type == TargetData.SIMPLE_SHAREDLIB
1521: || type == TargetData.COMPLEX_SHAREDLIB) {
1522: // Add the Shared Library flags
1523: sharedLibFlags(t);
1524: lbuf.append("$(" + var.makeName("SHAREDLIB_FLAGS_") + ") "); // NOI18N
1525: }
1526:
1527: lbuf.append(var.makeRef("LDLIBS_")); // NOI18N
1528: if (t.containsXdFiles()) {
1529: lbuf.append(xdLinkMagic(t));
1530: }
1531: lbuf.append('\n');
1532:
1533: return lbuf.toString();
1534: }
1535:
1536: /**
1537: * Emit X-Designer link library magic. The mogic is needed because the X-Designer link
1538: * line comes from the X-Designer generated Makefile so the Makefile we are
1539: * creating doesn't know about it. To get around this, we extract the
1540: * information into files and create variables which read these files
1541: * during the compile.
1542: */
1543: private String xdLinkMagic(TargetData t) {
1544: StringBuffer lbuf = new StringBuffer(256);
1545:
1546: String[] srcs = t.getSourcesList();
1547: for (int i = 0; i < srcs.length; i++) {
1548: String file = srcs[i];
1549:
1550: if (t.isXdFile(srcs[i])) {
1551: String vname = getXdTargetName(t, file);
1552:
1553: lbuf.append(" \\\n\t\t"); // NOI18N
1554: lbuf.append("$(XD_OBJS_"); // NOI18N
1555: lbuf.append(vname);
1556: lbuf.append(") $(XD_LINK_ARGS_"); // NOI18N
1557: lbuf.append(vname);
1558: lbuf.append(')');
1559: }
1560: }
1561: return lbuf.toString();
1562: }
1563:
1564: /**
1565: * Gather special Xd link depenencies
1566: */
1567: private String xdLinkDependencies(TargetData t) {
1568: StringBuffer lbuf = new StringBuffer(256);
1569:
1570: String[] srcs = t.getSourcesList();
1571: for (int i = 0; i < srcs.length; i++) {
1572: String file = srcs[i];
1573:
1574: if (t.isXdFile(srcs[i])) {
1575: String vname = getXdTargetName(t, file);
1576:
1577: lbuf.append(" \\\n\t\t"); // NOI18N
1578: lbuf.append(var.makeRef("TARGETDIR_")); // NOI18N
1579: lbuf.append("/$(XD_OBJS_FILE_"); // NOI18N
1580: lbuf.append(vname);
1581: lbuf.append(") $(TARGETDIR_"); // NOI18N
1582: lbuf.append(t.getName());
1583: lbuf.append(")/$(XD_LINK_ARGS_FILE_"); // NOI18N
1584: lbuf.append(vname);
1585: lbuf.append(')');
1586: }
1587: }
1588: return lbuf.toString();
1589: }
1590:
1591: /**
1592: * Gather the system libraries specified on the Standard Libs panel.
1593: *
1594: * @param t The TargetData for this target
1595: * @return String containing all specified libraries
1596: */
1597: private String getSysLibs(TargetData t) {
1598: StdLibFlags flags = t.getStdLibFlags();
1599:
1600: buf.delete(0, buf.length());
1601: buf.append(flags.getSysLibFlags(md.getToolset(), md
1602: .getMakefileOS(), md.getCompilerFlags().is64Bit(), t));
1603: /*
1604: if (flags.getLinkType() == StdLibFlags.DYNAMIC_LINK_TYPE) {
1605: if (md.getToolset() == MakefileData.SUN_TOOLSET_TYPE) {
1606: //buf.append("-Bdynamic "); // NOI18N
1607: ; // nothing
1608: }
1609: else {
1610: ; // nothing
1611: }
1612: } else if (flags.getLinkType() == StdLibFlags.STATIC_LINK_TYPE) {
1613: if (md.getToolset() == MakefileData.SUN_TOOLSET_TYPE) {
1614: buf.append("-Bstatic "); // NOI18N
1615: }
1616: else {
1617: buf.append("-static "); // NOI18N
1618: }
1619: }
1620:
1621: // X-Designer will supply these libraries another way
1622: if (flags.isMotifLibs() && !t.containsXdFiles()) {
1623: CompilerFlags cflags = md.getCompilerFlags();
1624:
1625: if (md.getMakefileOS() == MakefileData.SOLARIS_OS_TYPE) {
1626: if (cflags.is64Bit()) {
1627: buf.append("-L/usr/openwin/lib/sparcv9 "); // NOI18N
1628: buf.append("-L/usr/dt/lib/sparcv9 "); // NOI18N
1629: buf.append("-R/usr/openwin/lib/sparcv9 "); // NOI18N
1630: buf.append("-R/usr/dt/lib/sparcv9 "); // NOI18N
1631: } else {
1632: buf.append("-L/usr/openwin/lib -L/usr/dt/lib "); // NOI18N
1633: buf.append("-R/usr/openwin/lib -R/usr/dt/lib "); // NOI18N
1634: }
1635: }
1636: else if (md.getMakefileOS() == MakefileData.LINUX_OS_TYPE) {
1637: if (cflags.is64Bit()) {
1638: // ???
1639: buf.append("-L/usr/X11R6/lib "); // NOI18N
1640: }
1641: else {
1642: buf.append("-L/usr/X11R6/lib "); // NOI18N
1643: }
1644: }
1645: else {
1646: ; // FIXUP - error
1647: }
1648: }
1649:
1650: StdLib[] stdLibs;
1651: if (md.getMakefileOS() == MakefileData.SOLARIS_OS_TYPE) {
1652: stdLibs = t.getStdLibFlags().getSolarisStdLibs();
1653: }
1654: else {
1655: stdLibs = t.getStdLibFlags().getLinuxStdLibs();
1656: }
1657:
1658: // Unset certain libs if x-designer
1659: if (t.containsXdFiles()) {
1660: flags.motif.setUsed(false);
1661: flags.socketnsl.setUsed(false);
1662: flags.genlib.setUsed(false);
1663: }
1664:
1665: for (int i = 0; i < stdLibs.length; i++) {
1666: if (stdLibs[i].isUsed())
1667: buf.append(stdLibs[i].getCmd());
1668: }
1669: */
1670:
1671: if (buf.length() > 0) {
1672: buf.insert(0, " = "); // NOI18N
1673: buf.insert(0, var.makeName("SYSLIBS_")); // NOI18N
1674: buf.append('\n');
1675: }
1676: return buf.toString();
1677: }
1678:
1679: /**
1680: * Put the user libraries into a usable format and return the caller.
1681: *
1682: * @param t The TargetData for this target
1683: * @return String containing all user libraries
1684: */
1685: private String getUserLibs(TargetData t) {
1686: String[] ulibs = t.getUserLibsList();
1687:
1688: buf.delete(0, buf.length());
1689: if (ulibs != null) {
1690: for (int i = 0; i < ulibs.length; i++) {
1691: String lib = ulibs[i];
1692: buf.append(lib);
1693: buf.append(' ');
1694: }
1695: }
1696:
1697: if (buf.length() > 0) {
1698: buf.insert(0, " = "); // NOI18N
1699: buf.insert(0, var.makeName("USERLIBS_")); // NOI18N
1700: buf.append('\n');
1701: }
1702: return buf.toString();
1703: }
1704:
1705: /**
1706: * The user libraries can be either libraries developed by the user or
1707: * system libraries which are not in the Standard Libraries panel. The
1708: * libraries developed by the user should be used as dependencies for the
1709: * link step. This method tries to determine which user libraries should
1710: * be used as dependencies. In general, we will generate a dependency for
1711: * all user libraries specified as a pathname.
1712: *
1713: * @param t The TargetData for this target
1714: * @return String containing all dependent libraries
1715: */
1716: private String getDependLibs(TargetData t) {
1717: String[] ulibs = t.getUserLibsList();
1718:
1719: buf.delete(0, buf.length());
1720: if (ulibs != null) {
1721: for (int i = 0; i < ulibs.length; i++) {
1722: String lib = ulibs[i];
1723:
1724: if (lib.charAt(0) != '-'
1725: && lib.charAt(0) != '/'
1726: && (lib.endsWith(".a") || lib.endsWith(".so")
1727: || lib.endsWith(".dylib") || lib
1728: .endsWith(".dll"))) { // NOI18N
1729: buf.append(lib);
1730: buf.append(' ');
1731: }
1732: buf.append(' ');
1733: }
1734: }
1735:
1736: if (buf.length() > 0) {
1737: buf.insert(0, " = "); // NOI18N
1738: buf.insert(0, var.makeName("DEPLIBS_")); // NOI18N
1739: buf.append('\n');
1740: }
1741: return buf.toString();
1742: }
1743:
1744: /**
1745: * Thie doList method is used to generate Makefile variables with a list
1746: * of values. The variable name will be on its own line with each item in
1747: * the list of a following line with a tab indent.
1748: *
1749: * @param var The Make variable name
1750: * @param prefix An optional String to prepend each item
1751: * @param list An array of Strings, where each String is a list item
1752: */
1753: private String doList(String var, String prefix, String[] list) {
1754: StringBuffer lbuf = new StringBuffer(256);
1755:
1756: if (prefix == null) {
1757: prefix = " \\\n\t"; // NOI18N
1758: } else {
1759: prefix = new StringBuffer(" \\\n\t").append(prefix)
1760: .toString(); // NOI18N
1761: }
1762:
1763: lbuf.append(var);
1764: lbuf.append(" ="); // NOI18N
1765: for (int i = 0; i < list.length; i++) {
1766: lbuf.append(prefix);
1767: lbuf.append(list[i]);
1768: }
1769: lbuf.append('\n');
1770: return lbuf.toString();
1771: }
1772:
1773: /** Generate target-specific flag variables for each language needing one */
1774: private String generateTargetFlags(TargetData t) {
1775: StringBuffer flagsSun = new StringBuffer(80);
1776:
1777: /*
1778: * See if we have shared per-target flags (these are flags which are
1779: * needed on a per-target basis for each language used in this
1780: * Makefile).
1781: */
1782: if (t.getTargetType() == TargetData.COMPLEX_SHAREDLIB
1783: || t.getTargetType() == TargetData.SIMPLE_SHAREDLIB) {
1784: flagsSun.append("-Kpic "); // NOI18N
1785: }
1786:
1787: buf.delete(0, buf.length());
1788: if (flagsSun.length() > 0) {
1789: int toolset = md.getToolset();
1790:
1791: // Check for CFLAGS_<target-name> first
1792: if (t.containsCFiles()) {
1793: appendToolsetDepMacro(var.makeName("CFLAGS_"), flagsSun
1794: .toString(), ""); // NOI18N
1795: }
1796:
1797: // Check for CCFLAGS_<target-name> first
1798: if (t.containsCppFiles()) {
1799: appendToolsetDepMacro(var.makeName("CCFLAGS_"),
1800: flagsSun.toString(), ""); // NOI18N
1801: }
1802:
1803: // Check for FFLAGS_<target-name> first
1804: if (t.containsFortranFiles()) {
1805: appendToolsetDepMacro(var.makeName("FFLAGS_"), flagsSun
1806: .toString(), ""); // NOI18N
1807: }
1808: }
1809: return buf.toString();
1810: }
1811:
1812: /**
1813: * Given a list of source files, replace the suffix with ".o" and return
1814: * a list of object files.
1815: *
1816: * @param srcs A String[] of source files
1817: * @return A String[] of object files
1818: */
1819: private String[] getObjectList(String[] srcs) {
1820: String[] objs = new String[srcs.length];
1821:
1822: for (int i = 0; i < srcs.length; i++) {
1823: int dot = srcs[i].lastIndexOf('.');
1824: if (dot >= 0) {
1825: StringBuffer obj = new StringBuffer(srcs[i].substring(
1826: 0, dot + 1));
1827: obj.append('o');
1828: objs[i] = new String(obj);
1829: }
1830: }
1831: return objs;
1832: }
1833:
1834: /**
1835: * Check for situations where one of the Makefile's targets is incomplete.
1836: * Currently we only check compilable targets for source files. This may
1837: * change in the future.
1838: */
1839: private boolean targetIsIncomplete() {
1840: ArrayList tlist = md.getTargetList();
1841:
1842: for (int i = 0; i < tlist.size(); i++) {
1843: TargetData t = (TargetData) tlist.get(i);
1844:
1845: if (t.isCompilable()
1846: && (t.getSourcesList() == null || t
1847: .getSourcesList().length == 0)) {
1848: return true;
1849: }
1850: }
1851: return false;
1852: }
1853:
1854: /**
1855: * Traverse each target and set some of the fields which need setting before
1856: * code can be generated.
1857: */
1858: private void completeTargets() {
1859: ArrayList tlist = md.getTargetList();
1860:
1861: for (int i = 0; i < tlist.size(); i++) {
1862: }
1863: }
1864:
1865: /**
1866: * Test the given file to see if its a Makefile we generated. We won't
1867: * overwrite a Makefile we did not generate.
1868: */
1869: public static boolean generatedMakefile(File mf) {
1870: String[] line = new String[3];
1871: int i = 0;
1872:
1873: try {
1874: BufferedReader in = new BufferedReader(new FileReader(mf));
1875: line[i++] = in.readLine();
1876: line[i++] = in.readLine();
1877: line[i++] = in.readLine();
1878: in.close();
1879: } catch (IOException ex) {
1880: return false;
1881: }
1882:
1883: if (line[2] != null && line[0].equals(LINE1)
1884: && line[1].equals(BLANKCOMMENT)
1885: && line[2].startsWith(LINE_PREFIX)) {
1886: return true;
1887: } else {
1888: return false;
1889: }
1890: }
1891:
1892: /** Validate or create the Current build directory */
1893: private int validateOrCreateCwd() {
1894: String cwd = md.getBaseDirectory(MakefileData.EXPAND);
1895: File fcwd = new File(cwd);
1896:
1897: return validateOrCreateDir(cwd, fcwd,
1898: getString("MSG_CwdNotDir")); // NOI18N
1899: }
1900:
1901: /** Validate or create the directory the Makefile will be generated in */
1902: private int validateOrCreateMakefileDir() {
1903: String makefile = md.getMakefileName();
1904:
1905: if (makefile.charAt(0) == File.separatorChar) {
1906: fmakefile = new File(makefile);
1907: } else {
1908: fmakefile = new File(md
1909: .getBaseDirectory(MakefileData.EXPAND), makefile);
1910: }
1911:
1912: String parent = fmakefile.getParent();
1913: File fparent = fmakefile.getParentFile();
1914:
1915: return validateOrCreateDir(parent, fparent,
1916: getString("MSG_MakefileDirNotDir")); // NOI18N
1917: }
1918:
1919: /**
1920: * Validate the given directory. If it doesn't exist try and create it.
1921: * Perform several validation tests and post dialogs if they fail. If the
1922: * requested directory doesn't exist try and create it. Post an error if
1923: * it cannot be created.
1924: *
1925: * @param dir The directory to validate/create in String form
1926: * @param fdir The directory to validate/create in File form
1927: * @param msg The message to post if dir exists but is not a directory
1928: *
1929: * @return OK if the directory exists or was successfully created
1930: */
1931: private int validateOrCreateDir(String dir, File fdir, String msg) {
1932: NotifyDescriptor nd;
1933: String s;
1934: String title;
1935:
1936: if (fdir.exists() && !fdir.isDirectory()) {
1937: s = MessageFormat.format(msg, new Object[] { dir });
1938: title = getString("DLG_ErrorDialogTitle"); // NOI18N
1939: nd = new NotifyDescriptor(s, title,
1940: NotifyDescriptor.DEFAULT_OPTION,
1941: NotifyDescriptor.ERROR_MESSAGE,
1942: new Object[] { NotifyDescriptor.OK_OPTION },
1943: NotifyDescriptor.OK_OPTION);
1944:
1945: // Post the Error Window
1946: DialogDisplayer.getDefault().notify(nd);
1947: return BAD;
1948: }
1949:
1950: if (!fdir.exists()) {
1951: s = MessageFormat.format(getString("MSG_CreateDirectory"), // NOI18N
1952: new Object[] { dir });
1953: title = getString("DLG_QuestionDialogTitle"); // NOI18N
1954: nd = new NotifyDescriptor(s, title,
1955: NotifyDescriptor.YES_NO_OPTION,
1956: NotifyDescriptor.QUESTION_MESSAGE, null,
1957: NotifyDescriptor.YES_OPTION);
1958:
1959: // Post the Question Window. Try and create directory if requested
1960: Object ret = DialogDisplayer.getDefault().notify(nd);
1961: if (ret == NotifyDescriptor.NO_OPTION || !mkdirs(dir, fdir)) {
1962: return BAD;
1963: }
1964: }
1965:
1966: return OK;
1967: }
1968:
1969: /** Get a timestamp in the current locale */
1970: private String getTimestamp() {
1971: Date date = new Date();
1972: StringBuffer timestamp = new StringBuffer(80);
1973:
1974: timestamp.append(DateFormat.getDateInstance().format(date));
1975: timestamp.append(" "); // NOI18N
1976: timestamp.append(DateFormat.getTimeInstance().format(date));
1977:
1978: return timestamp.toString();
1979: }
1980:
1981: /** Get the user name from the Unix environment */
1982: private String getUserName() {
1983:
1984: String user = System.getProperty("Env-USER"); // NOI18N
1985: if (user == null) {
1986: user = System.getProperty("Env-LOGNAME"); // NOI18N
1987: if (user == null) {
1988: user = System.getProperty("user.name"); // NOI18N
1989: if (user == null) {
1990: user = getString("UNKNOWN_USER"); // NOI18N
1991: }
1992: }
1993: }
1994:
1995: return user;
1996: }
1997:
1998: /** Try and make the directory. Post an error dialog if this fails */
1999: private boolean mkdirs(String name, File file) {
2000:
2001: if (file.mkdirs() == false) {
2002: String msg = MessageFormat.format(
2003: getString("MSG_CannotCreateDirectory"), // NOI18N
2004: new Object[] { name });
2005: String title = getString("DLG_ErrorDialogTitle"); // NOI18N
2006: NotifyDescriptor nd = new NotifyDescriptor(msg, title,
2007: NotifyDescriptor.DEFAULT_OPTION,
2008: NotifyDescriptor.ERROR_MESSAGE,
2009: new Object[] { NotifyDescriptor.OK_OPTION },
2010: NotifyDescriptor.OK_OPTION);
2011:
2012: // Post the Error Window
2013: DialogDisplayer.getDefault().notify(nd);
2014: return false;
2015: } else {
2016: return true;
2017: }
2018: }
2019:
2020: /** Iterate through the target list and see which languages are used */
2021: private void checkTargetFlags() {
2022: ArrayList tlist = md.getTargetList();
2023:
2024: for (int i = 0; i < tlist.size(); i++) {
2025: TargetData t = (TargetData) tlist.get(i);
2026: if (t.isComplex()) {
2027: doComplex = true;
2028: }
2029: if (t.containsCppFiles()) {
2030: doCpp = true;
2031: }
2032: if (t.containsCFiles()) {
2033: doC = true;
2034: }
2035: if (t.containsFortranFiles()) {
2036: doFortran = true;
2037: }
2038: if (t.containsXdFiles()) {
2039: doXd = true;
2040: doC = true; // since X-Designer can generate C
2041: doCpp = true; // since X-Designer can generate C++
2042: }
2043: if (t.containsAssemblyFiles()) {
2044: doAssembly = true;
2045: }
2046: }
2047: }
2048:
2049: /** Helper method for getting a string from a bundle */
2050: protected String getString(String s) {
2051: return bundle.getString(s);
2052: }
2053:
2054: /**
2055: * We need to emit lots of make variables of the form "$(foo_bar)", where
2056: * "foo" is the related to the variable we want to creat and "bar" is
2057: * related to the current target. This class is a helper class which
2058: * creates these names for us. To cut down on object creation its intended
2059: * to be reused with different variables and targets.
2060: */
2061: private final class MakeVarName {
2062:
2063: private String targetName; // this gets appended to name
2064: private StringBuffer lastName; // save the last name created
2065: private StringBuffer lastRef; // save the last ref created
2066: private StringBuffer lastSuffix; // check if same as last call
2067:
2068: private StringBuffer buffer = new StringBuffer(80);
2069:
2070: public MakeVarName() {
2071: targetName = null;
2072: lastName = new StringBuffer(80);
2073: lastRef = new StringBuffer(80);
2074: lastSuffix = new StringBuffer(20);
2075: }
2076:
2077: /**
2078: * Change the targetName so we can reuse this same object with another
2079: * target.
2080: */
2081: public void setTargetName(String targetName) {
2082: this .targetName = targetName;
2083:
2084: lastName.delete(0, lastName.length());
2085: lastRef.delete(0, lastRef.length());
2086: lastSuffix.delete(0, lastSuffix.length());
2087: }
2088:
2089: /**
2090: * Return a string with the desired name. Cache the last suffix and
2091: * returned string so we don't need to recreate it if we match the
2092: * last call. This should happen fairly often.
2093: */
2094: public String makeName(String suffix) {
2095:
2096: if (suffix.equals(lastSuffix.toString())) {
2097: return lastName.toString();
2098: } else {
2099: buffer.replace(0, buffer.length(), suffix);
2100: buffer.append(targetName);
2101: lastName.replace(0, lastName.length(), buffer
2102: .toString());
2103: return buffer.toString();
2104: }
2105: }
2106:
2107: /**
2108: * Return a string with the desired name. This flavor allows an extra
2109: * string to be appended to the name.
2110: */
2111: public String makeName(String suffix, String extra) {
2112:
2113: if (suffix.equals(lastSuffix.toString())) {
2114: return lastName.toString();
2115: } else {
2116: buffer.replace(0, buffer.length(), suffix);
2117: buffer.append(targetName);
2118: buffer.append("_"); // NOI18N
2119: buffer.append(extra);
2120: lastName.replace(0, lastName.length(), buffer
2121: .toString());
2122: return buffer.toString();
2123: }
2124: }
2125:
2126: /**
2127: * Return a string with the desired variable reference. Cache the last
2128: * suffix and returned string so we don't need to recreate it if we
2129: * match the last call. This should happen fairly often.
2130: */
2131: public String makeRef(String suffix) {
2132:
2133: if (suffix.equals(lastSuffix.toString())) {
2134: return lastRef.toString();
2135: } else {
2136: buffer.replace(0, buffer.length(), "$("); // NOI18N
2137: buffer.append(suffix);
2138: buffer.append(targetName);
2139: buffer.append(")"); // NOI18N
2140: lastRef.replace(0, lastRef.length(), buffer.toString());
2141: return buffer.toString();
2142: }
2143: }
2144:
2145: /**
2146: * Return a string with the desired variable reference. This flavor
2147: * allows an extra string to be appended to the name.
2148: */
2149: public String makeRef(String suffix, String extra) {
2150:
2151: if (suffix.equals(lastSuffix.toString())) {
2152: return lastRef.toString();
2153: } else {
2154: buffer.replace(0, buffer.length(), "$("); // NOI18N
2155: buffer.append(suffix);
2156: buffer.append(targetName);
2157: buffer.append("_"); // NOI18N
2158: buffer.append(extra);
2159: buffer.append(")"); // NOI18N
2160: lastRef.replace(0, lastRef.length(), buffer.toString());
2161: return buffer.toString();
2162: }
2163: }
2164:
2165: /** Return the last name we created */
2166: public String lastName() {
2167: return lastName.toString();
2168: }
2169:
2170: /** Return the last variable reference we created */
2171: public String lastRef() {
2172: return lastRef.toString();
2173: }
2174: }
2175:
2176: private final class MakefileGenerationException extends Exception {
2177:
2178: public MakefileGenerationException() {
2179: super ();
2180: }
2181:
2182: public MakefileGenerationException(String s) {
2183: super (s);
2184: }
2185: }
2186:
2187: /**
2188: * Get the output directory. If it is of the form <platform>, return
2189: * a macro value, othervise return the value.
2190: */
2191: private String getOutputDirectory(TargetData t) {
2192: String outputDirectory = t.getOutputDirectory();
2193: if (outputDirectory
2194: .equals(getString("OutputDirectoryPlatform"))) // NOI18N
2195: return "$(PLATFORM)"; // NOI18N
2196: else
2197: return outputDirectory;
2198: }
2199:
2200: /**
2201: * Append an toolset dependent macro to the global stringbuffer buf.
2202: */
2203: private void appendToolsetDepMacro(String macro, String sunVal,
2204: String gnuVal) {
2205: appendToolsetDepMacro(buf, macro, sunVal, gnuVal);
2206: }
2207:
2208: /**
2209: * Append an toolset dependent macro to the stringbuffer sbuf.
2210: */
2211: private void appendToolsetDepMacro(StringBuffer sbuf, String macro,
2212: String sunVal, String gnuVal) {
2213: int toolset = md.getToolset();
2214: if (toolset == MakefileData.SUN_TOOLSET_TYPE) {
2215: sbuf.append(macro);
2216: sbuf.append(" = "); // NOI18N
2217: sbuf.append(sunVal);
2218: sbuf.append('\n'); // NOI18N
2219: } else if (toolset == MakefileData.GNU_TOOLSET_TYPE) {
2220: sbuf.append(macro);
2221: sbuf.append(" = "); // NOI18N
2222: sbuf.append(gnuVal);
2223: sbuf.append('\n'); // NOI18N
2224: } else if (toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
2225: sbuf.append(macro + "-SUN"); // NOI18N
2226: sbuf.append(" = "); // NOI18N
2227: sbuf.append(sunVal);
2228: sbuf.append('\n');
2229: sbuf.append(macro + "-GNU"); // NOI18N
2230: sbuf.append(" = "); // NOI18N
2231: sbuf.append(gnuVal);
2232: sbuf.append('\n');
2233: sbuf.append(macro + " = $(" + macro + "-$(TOOLSET))"); // NOI18N
2234: sbuf.append('\n');
2235: } else {
2236: ; // FIXUP - error
2237: }
2238: }
2239:
2240: /**
2241: * Append an toolset dependent macro to the global stringbuffer buf.
2242: */
2243: private void appendToolsetDepMacro(String sunMacro, String sunVal,
2244: String gnuMacro, String gnuVal) {
2245: appendToolsetDepMacro(buf, sunMacro, sunVal, gnuMacro, gnuVal);
2246: }
2247:
2248: /**
2249: * Append an toolset dependent macro to the stringbuffer sbuf.
2250: */
2251: private void appendToolsetDepMacro(StringBuffer sbuf,
2252: String sunMacro, String sunVal, String gnuMacro,
2253: String gnuVal) {
2254: int toolset = md.getToolset();
2255: if (toolset == MakefileData.SUN_TOOLSET_TYPE
2256: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
2257: sbuf.append(sunMacro);
2258: sbuf.append(" = "); // NOI18N
2259: sbuf.append(sunVal);
2260: sbuf.append('\n'); // NOI18N
2261: }
2262: if (toolset == MakefileData.GNU_TOOLSET_TYPE
2263: || toolset == MakefileData.SUNGNU_TOOLSET_TYPE) {
2264: sbuf.append(gnuMacro);
2265: sbuf.append(" = "); // NOI18N
2266: sbuf.append(gnuVal);
2267: sbuf.append('\n'); // NOI18N
2268: }
2269: }
2270:
2271: /**
2272: * Append a macro
2273: */
2274: private void appendMacro(String macro, String val) {
2275: appendMacro(buf, macro, val);
2276: }
2277:
2278: /**
2279: * Append a macro
2280: */
2281: private void appendMacro(StringBuffer sbuf, String macro, String val) {
2282: sbuf.append(macro);
2283: sbuf.append(" = "); // NOI18N
2284: sbuf.append(val);
2285: sbuf.append('\n'); // NOI18N
2286: }
2287:
2288: /**
2289: * Append an OS dependent macro to the global stringbuffer buf.
2290: */
2291: private void appendOSDepMacro(String macro, String sunVal,
2292: String gnuVal, String macosxVal) {
2293: appendOSDepMacro(buf, macro, sunVal, gnuVal, macosxVal);
2294: }
2295:
2296: /**
2297: * Append an OS dependent macro to the stringbuffer sbuf.
2298: */
2299: private void appendOSDepMacro(StringBuffer sbuf, String macro,
2300: String sunVal, String gnuVal, String macosxVal) {
2301: int os = md.getMakefileOS();
2302: if (os == MakefileData.SOLARIS_OS_TYPE) {
2303: sbuf.append(macro);
2304: sbuf.append(" = "); // NOI18N
2305: sbuf.append(sunVal);
2306: sbuf.append('\n'); // NOI18N
2307: } else if (os == MakefileData.LINUX_OS_TYPE) {
2308: sbuf.append(macro);
2309: sbuf.append(" = "); // NOI18N
2310: sbuf.append(gnuVal);
2311: sbuf.append('\n'); // NOI18N
2312: } else if (os == MakefileData.MACOSX_OS_TYPE) {
2313: sbuf.append(macro);
2314: sbuf.append(" = "); // NOI18N
2315: sbuf.append(macosxVal);
2316: sbuf.append('\n'); // NOI18N
2317: } else if (os == MakefileData.UNIX_OS_TYPE) {
2318: sbuf.append(macro + "-SunOS"); // NOI18N
2319: sbuf.append(" = "); // NOI18N
2320: sbuf.append(sunVal);
2321: sbuf.append('\n');
2322: sbuf.append(macro + "-Linux"); // NOI18N
2323: sbuf.append(" = "); // NOI18N
2324: sbuf.append(gnuVal);
2325: sbuf.append('\n');
2326: sbuf.append(macro + " = $(" + macro + "-$(OS))"); // NOI18N
2327: sbuf.append('\n');
2328: } else {
2329: ; // FIXUP - error
2330: }
2331: }
2332: }
|