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;
21  
22  import java.io.File;
23  import java.util.Iterator;
24  import java.util.LinkedList;
25  import java.util.List;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.plugin.MojoExecutionException;
29  import org.apache.maven.plugin.MojoFailureException;
30  import org.apache.maven.plugins.annotations.LifecyclePhase;
31  import org.apache.maven.plugins.annotations.Mojo;
32  import org.apache.maven.plugins.annotations.Parameter;
33  import org.apache.maven.plugins.annotations.ResolutionScope;
34  import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
35  import org.apache.tools.ant.BuildException;
36  import org.apache.tools.ant.Project;
37  
38  import com.github.maven_nar.cpptasks.CCTask;
39  import com.github.maven_nar.cpptasks.CUtil;
40  import com.github.maven_nar.cpptasks.CompilerDef;
41  import com.github.maven_nar.cpptasks.LinkerDef;
42  import com.github.maven_nar.cpptasks.OutputTypeEnum;
43  import com.github.maven_nar.cpptasks.RuntimeType;
44  import com.github.maven_nar.cpptasks.SubsystemEnum;
45  import com.github.maven_nar.cpptasks.types.LibrarySet;
46  import com.github.maven_nar.cpptasks.types.LibraryTypeEnum;
47  import com.github.maven_nar.cpptasks.types.LinkerArgument;
48  import com.github.maven_nar.cpptasks.types.SystemLibrarySet;
49  
50  /**
51   * Compiles native test source files.
52   * 
53   * @author Mark Donszelmann
54   */
55  @Mojo(name = "nar-testCompile", defaultPhase = LifecyclePhase.TEST_COMPILE,
56    requiresDependencyResolution = ResolutionScope.TEST)
57  public class NarTestCompileMojo extends AbstractCompileMojo {
58    /**
59     * Skip running of NAR integration test plugins.
60     */
61    @Parameter(property = "skipNar")
62    protected boolean skipNar;
63  
64    private void createTest(final Project antProject, final Test test)
65        throws MojoExecutionException, MojoFailureException {
66      final String type = "test";
67  
68      // configure task
69      final CCTask task = new CCTask();
70      task.setProject(antProject);
71  
72      // subsystem
73      final SubsystemEnum subSystem = new SubsystemEnum();
74      subSystem.setValue("console");
75      task.setSubsystem(subSystem);
76  
77      // outtype
78      final OutputTypeEnum outTypeEnum = new OutputTypeEnum();
79      outTypeEnum.setValue(test.getType());
80      task.setOuttype(outTypeEnum);
81  
82      // outDir
83      File outDir = new File(getTestTargetDirectory(), "bin");
84      outDir = new File(outDir, getAOL().toString());
85      outDir.mkdirs();
86  
87      // outFile
88      final File outFile = new File(outDir, test.getName());
89      getLog().debug("NAR - output: '" + outFile + "'");
90      task.setOutfile(outFile);
91  
92      // object directory
93      File objDir = new File(getTestTargetDirectory(), "obj");
94      objDir = new File(objDir, getAOL().toString());
95      objDir.mkdirs();
96      task.setObjdir(objDir);
97  
98      // failOnError, libtool
99      task.setFailonerror(failOnError(getAOL()));
100     task.setLibtool(useLibtool(getAOL()));
101 
102     // runtime
103     final RuntimeType runtimeType = new RuntimeType();
104     runtimeType.setValue(getRuntime(getAOL()));
105     task.setRuntime(runtimeType);
106 
107     // add C++ compiler
108     final Cpp cpp = getCpp();
109     if (cpp != null) {
110       final CompilerDef cppCompiler = getCpp().getTestCompiler(type, test.getName());
111       if (cppCompiler != null) {
112         task.addConfiguredCompiler(cppCompiler);
113       }
114     }
115 
116     // add C compiler
117     final C c = getC();
118     if (c != null) {
119       final CompilerDef cCompiler = c.getTestCompiler(type, test.getName());
120       if (cCompiler != null) {
121         task.addConfiguredCompiler(cCompiler);
122       }
123     }
124 
125     // add Fortran compiler
126     final Fortran fortran = getFortran();
127     if (fortran != null) {
128       final CompilerDef fortranCompiler = getFortran().getTestCompiler(type, test.getName());
129       if (fortranCompiler != null) {
130         task.addConfiguredCompiler(fortranCompiler);
131       }
132     }
133 
134     // add java include paths
135     getJava().addIncludePaths(task, type);
136 
137     getMsvc().configureCCTask(task);
138 
139     List depLibs = getNarArtifacts();
140     
141     // add dependency include paths
142     for (final Object depLib1 : depLibs) {
143       final Artifact artifact = (Artifact) depLib1;
144 
145       // check if it exists in the normal unpack directory
146       File include = getLayout()
147           .getIncludeDirectory(getUnpackDirectory(), artifact.getArtifactId(), artifact.getBaseVersion());
148       if (!include.exists()) {
149         // otherwise try the test unpack directory
150         include = getLayout()
151             .getIncludeDirectory(getTestUnpackDirectory(), artifact.getArtifactId(), artifact.getBaseVersion());
152       }
153       if (include.exists()) {
154         task.createIncludePath().setPath(include.getPath());
155       }
156     }
157 
158     // add javah generated include path
159     final File jniIncludeDir = getJavah().getJniDirectory();
160     if (jniIncludeDir.exists()) {
161       task.createIncludePath().setPath(jniIncludeDir.getPath());
162     }
163 
164     // add linker
165     final LinkerDef linkerDefinition = getLinker().getTestLinker(this, task, getOS(), getAOL().getKey() + ".linker.",
166         type);
167     task.addConfiguredLinker(linkerDefinition);
168 
169     final File includeDir = getLayout().getIncludeDirectory(getTargetDirectory(), getMavenProject().getArtifactId(),
170         getMavenProject().getVersion());
171 
172     String linkType = test.getLink( getLibraries() );
173     final File libDir = getLayout().getLibDirectory(getTargetDirectory(), getMavenProject().getArtifactId(),
174         getMavenProject().getVersion(), getAOL().toString(), linkType);
175 
176     // copy shared library
177     // FIXME why do we do this ?
178     /*
179      * Removed in alpha-10 if (test.getLink().equals(Library.SHARED)) { try { //
180      * defaults are Unix String libPrefix
181      * = NarUtil.getDefaults().getProperty( getAOLKey() + "shared.prefix",
182      * "lib"); String libExt =
183      * NarUtil.getDefaults().getProperty( getAOLKey() + "shared.extension",
184      * "so"); File copyDir = new
185      * File(getTargetDirectory(), (getOS().equals( "Windows") ? "bin" : "lib") +
186      * "/" + getAOL() + "/" +
187      * test.getLink()); FileUtils.copyFileToDirectory(new File(libDir, libPrefix
188      * + libName + "." + libExt),
189      * copyDir); if (!getOS().equals(OS.WINDOWS)) { libDir = copyDir; } } catch
190      * (IOException e) { throw new
191      * MojoExecutionException( "NAR: Could not copy shared library", e); } }
192      */
193     // FIXME what about copying the other shared libs?
194 
195     // add include of this package
196     if (includeDir.exists()) {
197       task.createIncludePath().setLocation(includeDir);
198     }
199 
200     // add library of this package
201     if (libDir.exists()) {
202       final LibrarySet libSet = new LibrarySet();
203       libSet.setProject(antProject);
204 
205       // String libs = getNarInfo().getLibs( getAOL() );
206       // using getNarInfo().getLibs( getAOL() ); forces to execute the goal
207       // nar-prepare-package prior to
208       // nar-testCompile in order to set the "output" property in narInfo with
209       // the call :
210       // narInfo.setOutput( null, mojo.getOutput(true) ); (set in
211       // NarLayout21.prepareNarInfo(...))
212 
213       // narInfo.getLibs(aol) call in fact narInfo.getProperty( aol,
214       // "libs.names", getOutput( aol, artifactId + "-" + version ) );
215       // where getOutput is the getOutput method in narInfo (which needs the
216       // "output" property).
217       // We call then directly narInfo.getProperty( aol, "libs.names", <output
218       // value>); but we set <output value>
219       // with AbstractCompileMojo.getOutput( boolean versioned ) as it is done
220       // during nar-prepare-package
221       final String libs = getNarInfo().getProperty(getAOL(), "libs.names", getOutput(true));
222 
223       getLog().debug("Searching for parent to link with " + libs);
224       libSet.setLibs(new CUtil.StringArrayBuilder(libs));
225       final LibraryTypeEnum libType = new LibraryTypeEnum();
226       libType.setValue(linkType);
227       libSet.setType(libType);
228       libSet.setDir(libDir);
229       task.addLibset(libSet);
230     }
231 
232     // add dependency libraries
233     final List depLibOrder = getDependencyLibOrder();
234 
235     // reorder the libraries that come from the nar dependencies
236     // to comply with the order specified by the user
237     if (depLibOrder != null && !depLibOrder.isEmpty()) {
238 
239       final List tmp = new LinkedList();
240 
241       for (final Object aDepLibOrder : depLibOrder) {
242 
243         final String depToOrderName = (String) aDepLibOrder;
244 
245         for (final Iterator j = depLibs.iterator(); j.hasNext(); ) {
246 
247           final NarArtifact dep = (NarArtifact) j.next();
248           final String depName = dep.getGroupId() + ":" + dep.getArtifactId();
249 
250           if (depName.equals(depToOrderName)) {
251 
252             tmp.add(dep);
253             j.remove();
254           }
255         }
256       }
257 
258       tmp.addAll(depLibs);
259       depLibs = tmp;
260     }
261 
262     for (final Object depLib : depLibs) {
263       final NarArtifact dependency = (NarArtifact) depLib;
264 
265       // FIXME no handling of "local"
266 
267       final String binding = getBinding(test, dependency);
268       getLog().debug("Using Binding: " + binding);
269       AOL aol = getAOL();
270       aol = dependency.getNarInfo().getAOL(getAOL());
271       getLog().debug("Using Library AOL: " + aol.toString());
272 
273       // We dont link against the following library types :
274       // - JNI, they are Java libraries
275       // - executable, they are not libraries
276       // - none, they are not libraries ... I gess
277       // Static libraries should be linked. Even though the libraries
278       // themselves will have been tested already, the test code could
279       // use methods or classes defined in them.
280       if (!binding.equals(Library.JNI) && !binding.equals(Library.NONE) && !binding.equals(Library.EXECUTABLE)) {
281         // check if it exists in the normal unpack directory
282         File dir = getLayout()
283             .getLibDirectory(getUnpackDirectory(), dependency.getArtifactId(), dependency.getBaseVersion(),
284                 aol.toString(), binding);
285         getLog().debug("Looking for Library Directory: " + dir);
286         if (!dir.exists()) {
287           getLog().debug("Library Directory " + dir + " does NOT exist.");
288 
289           // otherwise try the test unpack directory
290           dir = getLayout()
291               .getLibDirectory(getTestUnpackDirectory(), dependency.getArtifactId(), dependency.getBaseVersion(),
292                   aol.toString(), binding);
293           getLog().debug("Looking for Library Directory: " + dir);
294         }
295         if (dir.exists()) {
296           final LibrarySet libSet = new LibrarySet();
297           libSet.setProject(antProject);
298 
299           // FIXME, no way to override
300           final String libs = dependency.getNarInfo().getLibs(getAOL());
301           if (libs != null && !libs.equals("")) {
302             getLog().debug("Using LIBS = " + libs);
303             libSet.setLibs(new CUtil.StringArrayBuilder(libs));
304             libSet.setDir(dir);
305             task.addLibset(libSet);
306           }
307         } else {
308           getLog().debug("Library Directory " + dir + " does NOT exist.");
309         }
310 
311         // FIXME, look again at this, for multiple dependencies we may need to
312         // remove duplicates
313         final String options = dependency.getNarInfo().getOptions(getAOL());
314         if (options != null && !options.equals("")) {
315           getLog().debug("Using OPTIONS = " + options);
316           final LinkerArgument arg = new LinkerArgument();
317           arg.setValue(options);
318           linkerDefinition.addConfiguredLinkerArg(arg);
319         }
320 
321         final String sysLibs = dependency.getNarInfo().getSysLibs(getAOL());
322         if (sysLibs != null && !sysLibs.equals("")) {
323           getLog().debug("Using SYSLIBS = " + sysLibs);
324           final SystemLibrarySet sysLibSet = new SystemLibrarySet();
325           sysLibSet.setProject(antProject);
326 
327           sysLibSet.setLibs(new CUtil.StringArrayBuilder(sysLibs));
328           task.addSyslibset(sysLibSet);
329         }
330       }
331     }
332 
333     // Add JVM to linker
334     getJava().addRuntime(task, getJavaHome(getAOL()), getOS(), getAOL().getKey() + ".java.");
335 
336     // execute
337     try {
338       task.execute();
339     } catch (final BuildException e) {
340       throw new MojoExecutionException("NAR: Test-Compile failed", e);
341     }
342   }
343 
344   /**
345    * List the dependencies needed for tests compilations, those dependencies are
346    * used to get the include paths needed
347    * for compilation and to get the libraries paths and names needed for
348    * linking.
349    */
350   @Override
351   protected ScopeFilter getArtifactScopeFilter() {
352     // Was Artifact.SCOPE_TEST  - runtime??
353     return new ScopeFilter( Artifact.SCOPE_TEST, null );
354   }
355 
356   @Override
357   protected File getUnpackDirectory() {
358     return getTestUnpackDirectory() == null ? super.getUnpackDirectory() : getTestUnpackDirectory();
359   }
360 
361   @Override
362   public final void narExecute() throws MojoExecutionException, MojoFailureException {
363     if (this.skipTests) {
364       getLog().info("Not compiling test sources");
365     } else {
366 
367       // make sure destination is there
368       getTestTargetDirectory().mkdirs();
369 
370       for (final Object o : getTests()) {
371         createTest(getAntProject(), (Test) o);
372       }
373     }
374   }
375 
376 }