View Javadoc

1   /*
2    * #%L
3    * Native ARchive plugin for Maven
4    * %%
5    * Copyright (C) 2002 - 2014 NAR Maven Plugin developers.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   * http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.github.maven_nar.cpptasks.gcc;
21  
22  import java.io.BufferedReader;
23  import java.io.File;
24  import java.io.FileReader;
25  import java.io.IOException;
26  import java.util.Vector;
27  
28  import com.github.maven_nar.cpptasks.CUtil;
29  import com.github.maven_nar.cpptasks.compiler.CaptureStreamHandler;
30  
31  /**
32   * A add-in class for Gcc processors
33   *
34   * 
35   */
36  public class GccProcessor {
37    // the results from gcc -dumpmachine
38    private static String machine;
39    private static String[] specs;
40    // the results from gcc -dumpversion
41    private static String version;
42  
43    private static int addLibraryPatterns(final String[] libnames, final StringBuffer buf, final String prefix,
44        final String extension, final String[] patterns, final int offset) {
45      for (int i = 0; i < libnames.length; i++) {
46        buf.setLength(0);
47        buf.append(prefix);
48        buf.append(libnames[i]);
49        buf.append(extension);
50        patterns[offset + i] = buf.toString();
51      }
52      return offset + libnames.length;
53    }
54  
55    /**
56     * Converts absolute Cygwin file or directory names to the corresponding
57     * Win32 name.
58     * 
59     * @param names
60     *          array of names, some elements may be null, will be changed in
61     *          place.
62     */
63    public static void convertCygwinFilenames(final String[] names) {
64      if (names == null) {
65        throw new NullPointerException("names");
66      }
67      final File gccDir = CUtil.getExecutableLocation("gcc.exe");
68      if (gccDir != null) {
69        final String prefix = gccDir.getAbsolutePath() + "/..";
70        final StringBuffer buf = new StringBuffer();
71        for (int i = 0; i < names.length; i++) {
72          final String name = names[i];
73          if (name != null && name.length() > 1 && name.charAt(0) == '/') {
74            buf.setLength(0);
75            buf.append(prefix);
76            buf.append(name);
77            names[i] = buf.toString();
78          }
79        }
80      }
81    }
82  
83    public static String[] getLibraryPatterns(final String[] libnames) {
84      final StringBuffer buf = new StringBuffer();
85      final String[] patterns = new String[libnames.length * 2];
86      int offset = addLibraryPatterns(libnames, buf, "lib", ".a", patterns, 0);
87      if (isHPUX()) {
88        offset = addLibraryPatterns(libnames, buf, "lib", ".sl", patterns, offset);
89      } else {
90        offset = addLibraryPatterns(libnames, buf, "lib", ".so", patterns, offset);
91      }
92      return patterns;
93    }
94  
95    public static String getMachine() {
96      if (machine == null) {
97        final String[] args = new String[] {
98            "gcc", "-dumpmachine"
99        };
100       final String[] cmdout = CaptureStreamHandler.run(args);
101       if (cmdout.length == 0) {
102         machine = "nomachine";
103       } else {
104         machine = cmdout[0];
105       }
106     }
107     return machine;
108   }
109 
110   public static String[] getOutputFileSwitch(final String letter, final String outputFile) {
111     final StringBuffer buf = new StringBuffer();
112     if (outputFile.indexOf(' ') >= 0) {
113       buf.append('"');
114       buf.append(outputFile.replace('\\', '/'));
115       buf.append('"');
116     } else {
117       buf.append(outputFile.replace('\\', '/'));
118     }
119     final String[] retval = new String[] {
120         letter, buf.toString()
121     };
122     return retval;
123   }
124 
125   /**
126    * Returns the contents of the gcc specs file.
127    * 
128    * The implementation locates gcc.exe in the executable path and then
129    * builds a relative path name from the results of -dumpmachine and
130    * -dumpversion. Attempts to use gcc -dumpspecs to provide this information
131    * resulted in stalling on the Execute.run
132    * 
133    * @return contents of the specs file
134    */
135   public static String[] getSpecs() {
136     if (specs == null) {
137       final File gccParent = CUtil.getExecutableLocation("gcc.exe");
138       if (gccParent != null) {
139         //
140         // build a relative path like
141         // ../lib/gcc-lib/i686-pc-cygwin/2.95.3-5/specs
142         //
143         //
144         // resolve it relative to the location of gcc.exe
145         //
146         final String relativePath = "../lib/gcc-lib/" + getMachine() +
147             '/' +
148             getVersion() +
149             "/specs";
150         final File specsFile = new File(gccParent, relativePath);
151         //
152         // found the specs file
153         //
154         try {
155           //
156           // read the lines in the file
157           //
158           final BufferedReader reader = new BufferedReader(new FileReader(specsFile));
159           final Vector lines = new Vector(100);
160           String line = reader.readLine();
161           while (line != null) {
162             lines.addElement(line);
163             line = reader.readLine();
164           }
165           specs = new String[lines.size()];
166           lines.copyInto(specs);
167         } catch (final IOException ex) {
168         }
169       }
170     }
171     if (specs == null) {
172       specs = new String[0];
173     }
174     return specs;
175   }
176 
177   public static String getVersion() {
178     if (version == null) {
179       final String[] args = new String[] {
180           "gcc", "-dumpversion"
181       };
182       final String[] cmdout = CaptureStreamHandler.run(args);
183       if (cmdout.length == 0) {
184         version = "noversion";
185       } else {
186         version = cmdout[0];
187       }
188     }
189     return version;
190   }
191 
192   public static boolean isCaseSensitive() {
193     return true;
194   }
195 
196   /**
197    * Determines if task is running with cygwin
198    * 
199    * @return true if cygwin was detected
200    */
201   public static boolean isCygwin() {
202     return getMachine().indexOf("cygwin") > 0;
203   }
204 
205   private static boolean isHPUX() {
206     final String osname = System.getProperty("os.name").toLowerCase();
207     if (osname.contains("hp") && osname.contains("ux")) {
208       return true;
209     }
210     return false;
211   }
212 
213   /**
214    * 
215    * Parses the results of the specs file for a specific processor and
216    * options
217    * 
218    * @param specsContent
219    *          Contents of specs file as returned from getSpecs
220    * @param specSectionStart
221    *          start of spec section, for example "*cpp:"
222    * @param options
223    *          command line switches such as "-istart"
224    */
225   public static String[][]
226       parseSpecs(final String[] specsContent, final String specSectionStart, final String[] options) {
227     if (specsContent == null) {
228       throw new NullPointerException("specsContent");
229     }
230     if (specSectionStart == null) {
231       throw new NullPointerException("specSectionStart");
232     }
233     if (options == null) {
234       throw new NullPointerException("option");
235     }
236     final String[][] optionValues = new String[options.length][];
237     final StringBuffer optionValue = new StringBuffer(40);
238     for (int i = 0; i < specsContent.length; i++) {
239       String specLine = specsContent[i];
240       //
241       // if start of section then start paying attention
242       //
243       if (specLine.startsWith(specSectionStart)) {
244         final Vector[] optionVectors = new Vector[options.length];
245         for (int j = 0; j < options.length; j++) {
246           optionVectors[j] = new Vector(10);
247         }
248         //
249         // go to next line and examine contents
250         // and repeat until end of file
251         //
252         for (i++; i < specsContent.length; i++) {
253           specLine = specsContent[i];
254           for (int j = 0; j < options.length; j++) {
255             int optionStart = specLine.indexOf(options[j]);
256             while (optionStart >= 0) {
257               optionValue.setLength(0);
258               //
259               // walk rest of line looking for first non
260               // whitespace
261               // and then next space
262               boolean hasNonBlank = false;
263               int k = optionStart + options[j].length();
264               for (; k < specLine.length(); k++) {
265                 //
266                 // either a blank or a "}" (close of
267                 // conditional)
268                 // section will end the path
269                 //
270                 if (specLine.charAt(k) == ' ' || specLine.charAt(k) == '}') {
271                   if (hasNonBlank) {
272                     break;
273                   }
274                 } else {
275                   hasNonBlank = true;
276                   optionValue.append(specLine.charAt(k));
277                 }
278               }
279               //
280               // transition back to whitespace
281               // value is over, add it to vector
282               if (hasNonBlank) {
283                 optionVectors[j].addElement(optionValue.toString());
284               }
285               //
286               // find next occurance on line
287               //
288               optionStart = specLine.indexOf(options[j], k);
289             }
290           }
291         }
292         //
293         // copy vectors over to option arrays
294         //
295         for (int j = 0; j < options.length; j++) {
296           optionValues[j] = new String[optionVectors[j].size()];
297           optionVectors[j].copyInto(optionValues[j]);
298         }
299       }
300     }
301     //
302     // fill in any missing option values with
303     // a zero-length string array
304     for (int i = 0; i < optionValues.length; i++) {
305       final String[] zeroLenArray = new String[0];
306       if (optionValues[i] == null) {
307         optionValues[i] = zeroLenArray;
308       }
309     }
310     return optionValues;
311   }
312 
313   private GccProcessor() {
314   }
315 }