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.cross;
21  
22  import java.io.File;
23  import java.util.Vector;
24  
25  import org.apache.tools.ant.BuildException;
26  import org.apache.tools.ant.types.Environment;
27  
28  import com.github.maven_nar.cpptasks.CCTask;
29  import com.github.maven_nar.cpptasks.CUtil;
30  import com.github.maven_nar.cpptasks.CompilerParam;
31  import com.github.maven_nar.cpptasks.OptimizationEnum;
32  import com.github.maven_nar.cpptasks.compiler.CommandLineCompilerConfiguration;
33  import com.github.maven_nar.cpptasks.compiler.LinkType;
34  import com.github.maven_nar.cpptasks.compiler.Linker;
35  import com.github.maven_nar.cpptasks.compiler.Processor;
36  import com.github.maven_nar.cpptasks.compiler.ProgressMonitor;
37  import com.github.maven_nar.cpptasks.gcc.GccCompatibleCCompiler;
38  import com.github.maven_nar.cpptasks.parser.CParser;
39  import com.github.maven_nar.cpptasks.parser.FortranParser;
40  import com.github.maven_nar.cpptasks.parser.Parser;
41  
42  /**
43   * Adapter for the GCC C/C++ compiler
44   *
45   * @author Adam Murdoch
46   */
47  public final class GccCCompiler extends GccCompatibleCCompiler {
48    private final static String[] headerExtensions = new String[] {
49        ".h", ".hpp", ".inl"
50    };
51    private final static String[] sourceExtensions = new String[] {
52        ".c", /* C */
53        ".cc", /* C++ */
54        ".cpp", /* C++ */
55        ".cxx", /* C++ */
56        ".c++", /* C++ */
57        ".i", /* preprocessed C */
58        ".ii", /* preprocessed C++ */
59        ".f", /* FORTRAN */
60        ".for", /* FORTRAN */
61        ".f90", /* FORTRAN */
62        ".m", /* Objective-C */
63        ".mm", /* Objected-C++ */
64        ".s" /* Assembly */
65    };
66    private static final GccCCompiler cppInstance = new GccCCompiler("c++", sourceExtensions, headerExtensions, false,
67        new GccCCompiler("c++", sourceExtensions, headerExtensions, true, null, false, null), false, null);
68    private static final GccCCompiler g77Instance = new GccCCompiler("g77", sourceExtensions, headerExtensions, false,
69        new GccCCompiler("g77", sourceExtensions, headerExtensions, true, null, false, null), false, null);
70    private static final GccCCompiler gppInstance = new GccCCompiler("g++", sourceExtensions, headerExtensions, false,
71        new GccCCompiler("g++", sourceExtensions, headerExtensions, true, null, false, null), false, null);
72    private static final GccCCompiler instance = new GccCCompiler("gcc", sourceExtensions, headerExtensions, false,
73        new GccCCompiler("gcc", sourceExtensions, headerExtensions, true, null, false, null), false, null);
74  
75    /**
76     * Gets c++ adapter
77     */
78    public static GccCCompiler getCppInstance() {
79      return cppInstance;
80    }
81  
82    /**
83     * Gets g77 adapter
84     */
85    public static GccCCompiler getG77Instance() {
86      return g77Instance;
87    }
88  
89    /**
90     * Gets gpp adapter
91     */
92    public static GccCCompiler getGppInstance() {
93      return gppInstance;
94    }
95  
96    /**
97     * Gets gcc adapter
98     */
99    public static GccCCompiler getInstance() {
100     return instance;
101   }
102 
103   private String identifier;
104   private File[] includePath;
105   private boolean isPICMeaningful = true;
106 
107   /**
108    * Private constructor. Use GccCCompiler.getInstance() to get singleton
109    * instance of this class.
110    */
111   private GccCCompiler(final String command, final String[] sourceExtensions, final String[] headerExtensions,
112       final boolean isLibtool, final GccCCompiler libtoolCompiler, final boolean newEnvironment, final Environment env) {
113     super(command, null, sourceExtensions, headerExtensions, isLibtool, libtoolCompiler, newEnvironment, env);
114     this.isPICMeaningful = !System.getProperty("os.name").contains("Windows");
115   }
116 
117   @Override
118   public void addImpliedArgs(final Vector<String> args, final boolean debug, final boolean multithreaded,
119       final boolean exceptions, final LinkType linkType, final Boolean rtti, final OptimizationEnum optimization) {
120     super.addImpliedArgs(args, debug, multithreaded, exceptions, linkType, rtti, optimization);
121     if (this.isPICMeaningful && linkType.isSharedLibrary()) {
122       args.addElement("-fPIC");
123     }
124   }
125 
126   @Override
127   public Processor changeEnvironment(final boolean newEnvironment, final Environment env) {
128     if (newEnvironment || env != null) {
129       return new GccCCompiler(getCommand(), this.getSourceExtensions(), this.getHeaderExtensions(), this.getLibtool(),
130           (GccCCompiler) this.getLibtoolCompiler(), newEnvironment, env);
131     }
132     return this;
133   }
134 
135   @Override
136   protected Object clone() throws CloneNotSupportedException {
137     final GccCCompiler clone = (GccCCompiler) super.clone();
138     return clone;
139   }
140 
141   @Override
142   public void compile(final CCTask task, final File outputDir, final String[] sourceFiles, final String[] args,
143       final String[] endArgs, final boolean relentless, final CommandLineCompilerConfiguration config,
144       final ProgressMonitor monitor) throws BuildException {
145     try {
146       final GccCCompiler clone = (GccCCompiler) this.clone();
147       final CompilerParam param = config.getParam("target");
148       if (param != null) {
149         clone.setCommand(param.getValue() + "-" + this.getCommand());
150       }
151       clone.supercompile(task, outputDir, sourceFiles, args, endArgs, relentless, config, monitor);
152     } catch (final CloneNotSupportedException e) {
153       supercompile(task, outputDir, sourceFiles, args, endArgs, relentless, config, monitor);
154     }
155   }
156 
157   /**
158    * Create parser to determine dependencies.
159    * 
160    * Will create appropriate parser (C++, FORTRAN) based on file extension.
161    * 
162    */
163   @Override
164   protected Parser createParser(final File source) {
165     if (source != null) {
166       final String sourceName = source.getName();
167       final int lastDot = sourceName.lastIndexOf('.');
168       if (lastDot >= 0 && lastDot + 1 < sourceName.length()) {
169         final char afterDot = sourceName.charAt(lastDot + 1);
170         if (afterDot == 'f' || afterDot == 'F') {
171           return new FortranParser();
172         }
173       }
174     }
175     return new CParser();
176   }
177 
178   @Override
179   public File[] getEnvironmentIncludePath() {
180     if (this.includePath == null) {
181       //
182       // construct default include path from machine id and version id
183       //
184       final String[] defaultInclude = new String[1];
185       final String buf = "/lib/" + GccProcessor.getMachine() +
186           '/' +
187           GccProcessor.getVersion() +
188           "/include";
189       defaultInclude[0] = buf;
190       //
191       // read specs file and look for -istart and -idirafter
192       //
193       final String[] specs = GccProcessor.getSpecs();
194       final String[][] optionValues = GccProcessor.parseSpecs(specs, "*cpp:", new String[] {
195           "-isystem ", "-idirafter "
196       });
197       //
198       // if no entries were found, then use a default path
199       //
200       if (optionValues[0].length == 0 && optionValues[1].length == 0) {
201         optionValues[0] = new String[] {
202             "/usr/local/include", "/usr/include", "/usr/include/win32api"
203         };
204       }
205       //
206       // remove mingw entries.
207       // For MinGW compiles this will mean the
208       // location of the sys includes will be
209       // wrong in dependencies.xml
210       // but that should have no significant effect
211       for (int i = 0; i < optionValues.length; i++) {
212         for (int j = 0; j < optionValues[i].length; j++) {
213           if (optionValues[i][j].indexOf("mingw") > 0) {
214             optionValues[i][j] = null;
215           }
216         }
217       }
218       //
219       // if cygwin then
220       // we have to prepend location of gcc32
221       // and .. to start of absolute filenames to
222       // have something that will exist in the
223       // windows filesystem
224       if (GccProcessor.isCygwin()) {
225         GccProcessor.convertCygwinFilenames(optionValues[0]);
226         GccProcessor.convertCygwinFilenames(optionValues[1]);
227         GccProcessor.convertCygwinFilenames(defaultInclude);
228       }
229       int count = CUtil.checkDirectoryArray(optionValues[0]);
230       count += CUtil.checkDirectoryArray(optionValues[1]);
231       count += CUtil.checkDirectoryArray(defaultInclude);
232       this.includePath = new File[count];
233       int index = 0;
234       for (final String[] optionValue : optionValues) {
235         for (final String anOptionValue : optionValue) {
236           if (anOptionValue != null) {
237             this.includePath[index++] = new File(anOptionValue);
238           }
239         }
240       }
241       for (final String element : defaultInclude) {
242         if (element != null) {
243           this.includePath[index++] = new File(element);
244         }
245       }
246     }
247     return this.includePath.clone();
248   }
249 
250   @Override
251   public String getIdentifier() throws BuildException {
252     if (this.identifier == null) {
253       StringBuffer buf;
254       if (getLibtool()) {
255         buf = new StringBuffer("libtool ");
256       } else {
257         buf = new StringBuffer(" ");
258       }
259       buf.append(getCommand());
260       buf.append(' ');
261       buf.append(GccProcessor.getVersion());
262       buf.append(' ');
263       buf.append(GccProcessor.getMachine());
264       this.identifier = buf.toString();
265     }
266     return this.identifier;
267   }
268 
269   @Override
270   public Linker getLinker(final LinkType linkType) {
271     return GccLinker.getInstance().getLinker(linkType);
272   }
273 
274   @Override
275   public int getMaximumCommandLength() {
276     return Integer.MAX_VALUE;
277   }
278 
279   private void supercompile(final CCTask task, final File outputDir, final String[] sourceFiles, final String[] args,
280       final String[] endArgs, final boolean relentless, final CommandLineCompilerConfiguration config,
281       final ProgressMonitor monitor) throws BuildException {
282     super.compile(task, outputDir, sourceFiles, args, endArgs, relentless, config, monitor);
283   }
284 }