View Javadoc
1   package org.apache.maven.plugin.cxx;
2   
3   /*
4    * Copyright (C) 2011-2016, Neticoa SAS France - Tous droits réservés.
5    * Author(s) : Franck Bonin, Neticoa SAS France
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   *
19   */
20  
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileOutputStream;
24  import java.io.InputStream;
25  import java.io.IOException;
26  import java.io.OutputStream;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Map;
32  import java.util.Iterator;
33  import java.util.regex.Matcher;
34  import java.util.regex.Pattern;
35  import java.util.Set;
36  import java.util.Properties;
37  
38  import org.codehaus.plexus.util.StringUtils;
39  import org.apache.commons.io.FilenameUtils;
40  import org.apache.commons.io.IOUtils;
41  import org.apache.commons.exec.CommandLine;
42  import org.apache.commons.exec.Executor;
43  
44  import org.apache.maven.plugin.MojoExecutionException;
45  
46  /* Use enhanced FileSet and FileManager (not the one provided in this project)*/
47  import org.apache.maven.shared.model.fileset.FileSet;
48  import org.apache.maven.shared.model.fileset.util.FileSetManager;
49  import org.apache.maven.artifact.Artifact;
50  
51  import org.apache.maven.plugins.annotations.LifecyclePhase;
52  import org.apache.maven.plugins.annotations.Mojo;
53  import org.apache.maven.plugins.annotations.Parameter;
54  
55  /**
56   * Goal which cmakes workspace.
57   *
58   * @author Franck Bonin 
59   * 
60   */
61  @Mojo( name = "cmake", defaultPhase = LifecyclePhase.GENERATE_SOURCES )
62  public class CMakeMojo extends AbstractLaunchMojo
63  {
64      @Override
65      protected List<String> getArgsList()
66      {
67          return null;
68      }
69  
70      /**
71       * Directory location of main CMakeList.txt, argument for cmake command 
72       * Defaut set to ${basedir}
73       * 
74       * @since 0.0.4
75       */
76      @Parameter( property = "cmake.projectdir" )
77      private String projectDir;
78      
79      protected String getProjectDir()
80      {
81          if ( null == projectDir )
82          {
83              projectDir = new String( basedir.getAbsolutePath() );
84          }
85          return projectDir;
86      }
87      
88      /**
89       * Generator name, arguments for cmake command
90       * 
91       * @since 0.0.4
92       */
93      @Parameter( property = "cmake.generator", required = true )
94      private String generator;
95      
96      /**
97       * Arguments for the executed program
98       * 
99       * @since 0.0.4
100      */
101     @Parameter( property = "cmake.args" )
102     private String commandArgs;
103     
104     protected String addCMakeDefinition( String sCMakeName, String sMavenValue )
105     {
106         String sResult = null;
107         if ( !StringUtils.isEmpty( sCMakeName ) && ! StringUtils.isEmpty( sMavenValue ) )
108         {
109             sResult = " -D" + sCMakeName + "=\"" + sMavenValue + "\"";
110         }
111         else
112         {
113             sResult = new String();
114         }
115         return sResult;
116     }
117     
118     @Override
119     protected String getCommandArgs()
120     {
121         String result = new String();
122         if ( !StringUtils.isEmpty( commandArgs ) )
123         {
124             result = commandArgs + " ";
125         }
126         result += "\"" + getProjectDir() + "\" -G " + generator;
127         result += addCMakeDefinition( "CMAKE_BUILD_TYPE", buildConfig );
128         result += addCMakeDefinition( "TARGET_ID", project.getArtifactId() );
129         result += addCMakeDefinition( "TARGET_NAME", project.getName() );
130         result += addCMakeDefinition( "DEPENDENCY_DIR", getProjectDependenciesDirectory() );
131         result += addCMakeDefinition( "TARGET_VERSION", project.getVersion() );
132         result += addCMakeDefinition( "TARGET_CLASSIFIER", targetClassifier );
133         result += addCMakeDefinition( "TARGET_PLATFORM", targetPlatform );
134         result += addCMakeDefinition( "TARGET_ARCHITECTURE", targetArchitecture );
135         result += addCMakeDefinition( "EXECUTABLE_SUFFIX", executableSuffix );
136         result += addCMakeDefinition( "SHARED_LIBRARY_PREFIX", sharedLibraryPrefix );
137         result += addCMakeDefinition( "SHARED_LIBRARY_SUFFIX", sharedLibrarySuffix );
138         result += addCMakeDefinition( "SHARED_MODULE_PREFIX", sharedModulePrefix );
139         result += addCMakeDefinition( "SHARED_MODULE_SUFFIX", sharedModuleSuffix );
140         result += addCMakeDefinition( "STATIC_LIBRARY_PREFIX", staticLibraryPrefix );
141         result += addCMakeDefinition( "STATIC_LIBRARY_SUFFIX", staticLibrarySuffix );
142         result += addCMakeDefinition( "INJECT_MAVEN_DEPENDENCIES", injectMavenDependencies ? "true" : "false" );
143         return result;
144     }
145 
146     @Override
147     protected String getExecutable()
148     {
149         return "cmake";
150     }
151 
152     
153     /**
154      * Environment variables to pass to the cmake program.
155      * 
156      * @since 0.0.4
157      */
158     @Parameter()
159     private Map environmentVariables = new HashMap();
160     
161     @Override
162     protected Map getMoreEnvironmentVariables()
163     {
164         return environmentVariables;
165     }
166 
167     @Override
168     protected List<String> getSuccesCode()
169     {
170         return null;
171     }
172 
173     /**
174      * Out of source directory
175      * Defaut set to ${basedir}
176      * 
177      * @since 0.0.4
178      */
179     @Parameter( property = "cmake.outsourcedir" )
180     private File outsourceDir;
181     
182     @Override
183     protected File getWorkingDir()
184     {
185         if ( null == outsourceDir )
186         {
187             outsourceDir = new File( basedir.getPath() );
188         }
189         return outsourceDir;
190     }
191 
192     @Override
193     public boolean isSkip()
194     {
195         return false;
196     }
197     
198     protected String getProjectDependenciesDirectory()
199     {
200         // project.getProperties().setProperty("toto", "toto");
201         //String projectBuildDirectory = project.getProperties().getProperty("project.build.directory");
202         //String projectBuildDirectory = System.getProperty("project.build.directory");
203         //String projectBuildDirectory = project.getModel().getBuild().getDirectory();
204         String projectBuildDirectory = project.getBuild().getDirectory();
205         if ( StringUtils.isEmpty( projectBuildDirectory ) )
206         {
207            projectBuildDirectory = basedir.getAbsolutePath() + "/target";
208         }         
209         return projectBuildDirectory + "/dependency";
210     }
211     
212    
213     /**
214      * generate a cmake maven dependency file according
215      * 
216      * @since 0.0.6
217      */
218     @Parameter( property = "cmake.injectMavenDependencies", defaultValue = "true" )
219     private boolean injectMavenDependencies;
220     
221     /**
222      * cmake maven dependency file name. If not full qualified name file location is ${basedir}
223      * 
224      * @since 0.0.6
225      */
226     @Parameter( property = "cmake.mavenDependenciesFile", defaultValue = "CMakeMavenDependencies.txt" )
227     private String cmakeMavenDependenciesFile;
228     
229     /**
230      * cmake dependency file name. If not full qualified name file location is ${basedir}
231      * 
232      * @since 0.0.6
233      */
234     @Parameter( property = "cmake.dependenciesFile", defaultValue = "CMakeDependencies.txt" )
235     private String cmakeDependenciesFile;
236     
237     /**
238      * build configuration {debug, release, debcov, relcov, relinfo}
239      * 
240      * @since 0.0.6
241      */
242     @Parameter( property = "buildConfig", defaultValue = "" )
243     private String buildConfig;
244     
245     /**
246      * maven artifact sub-classifier {win32, win64, linux-x64_64, etc.}
247      * 
248      * @since 0.0.6
249      */
250     @Parameter( property = "targetClassifier", defaultValue = "" )
251     private String targetClassifier;
252     
253     /**
254      * build platform = "native API" {win32, linux, mac}
255      * 
256      * @since 0.0.6
257      */
258     @Parameter( property = "targetPlatform", defaultValue = "" )
259     private String targetPlatform;
260     
261     /**
262      * build architecture {i386, x86_64, etc.}
263      * 
264      * @since 0.0.6
265      */
266     @Parameter( property = "targetArchitecture", defaultValue = "" )
267     private String targetArchitecture;
268     
269     /**
270      *  executables suffix of current platform {".exe", etc.}
271      * 
272      * @since 0.0.6
273      */
274     @Parameter( property = "executableSuffix", defaultValue = "" )
275     private String executableSuffix;
276     
277     /**
278      * libraries prefixe of current platform {"lib", etc.}
279      * 
280      * @since 0.0.6
281      */
282     @Parameter( property = "sharedLibraryPrefix", defaultValue = "" )
283     private String sharedLibraryPrefix;
284     
285     /**
286      * libraries suffixe of current platform {".so", ".dylib", etc.}
287      * 
288      * @since 0.0.6
289      */
290     @Parameter( property = "sharedLibrarySuffix", defaultValue = "" )
291     private String sharedLibrarySuffix;
292     
293     /**
294      * module prefixe of current platform {"lib", etc.}
295      * 
296      * @since 0.0.6
297      */
298     @Parameter( property = "sharedModulePrefix", defaultValue = "" )
299     private String sharedModulePrefix;
300     
301     /**
302      * module suffixe of current platform {".so", ".dylib", etc.}
303      * 
304      * @since 0.0.6
305      */
306     @Parameter( property = "sharedModuleSuffix", defaultValue = "" )
307     private String sharedModuleSuffix;
308     
309     /**
310      * static libraries prefixe of current platform {"lib", etc.}
311      * 
312      * @since 0.0.6
313      */
314     @Parameter( property = "staticLibraryPrefix", defaultValue = "" )
315     private String staticLibraryPrefix;
316     
317     /**
318      * static libraries suffixe of current platform {".a", ".lib", etc.}
319      * 
320      * @since 0.0.6
321      */
322     @Parameter( property = "staticLibrarySuffix", defaultValue = "" )
323     private String staticLibrarySuffix;
324     
325     /**
326      * directories were additional bin dependencies are
327      * default dependencies location is : ${project.build.directory}/dependency/${targetClassifier}/${buildConfig}
328      * "${targetClassifier}/${buildConfig}" will be automaticaly added to provided path to search for
329      * additionnal dependencies
330      * 
331      * @since 0.0.6
332      */
333     @Parameter()
334     private String additionalDependenciesRoots[] = null;
335     
336     /**
337      * Directory where additional include dependencies are
338      * 
339      * @since 0.0.6
340      */
341     @Parameter( )
342     protected String additionalIncludeRoots[] = null;
343     
344     
345     protected void findDependencies( Map<String, String> aiDependenciesRoots, List<String> aoDependenciesLib )
346     {
347         for ( Map.Entry<String, String> entry : aiDependenciesRoots.entrySet() )
348         {
349             String dependencyRoot = new String( entry.getKey() );
350 
351             FileSet afileSet = new FileSet();
352             afileSet.setDirectory( dependencyRoot );
353             
354             getLog().info( "Search for **/*.[so|dylib|dll|lib|a|] from " + afileSet.getDirectory() );
355             afileSet.setIncludes( Arrays.asList( 
356                 new String[]{"**/*.so", "**/*.dll", "**/*.dylib", "**/*.lib", "**/*.a"} ) );
357             
358             FileSetManager aFileSetManager = new FileSetManager();
359             String[] found = aFileSetManager.getIncludedFiles( afileSet );
360             
361             for ( int j = 0; null != found && j < found.length; j++ )
362             {
363                 // $FB always use unix path separator with cmake even under windows !
364                 getLog().info( "Found dependencies Lib : " + found[j] );
365                 getLog().info( "Found dependencies Lib full path : " + dependencyRoot + "/" + found[j] );
366                 getLog().info( "Found dependencies Lib generalized path : " + entry.getValue() 
367                     + "/" + found[j] );
368                 aoDependenciesLib.add( entry.getValue() + "/" + found[j] );
369             }
370         }
371     }
372     
373     protected String baseNameAsStaticLibrary( String sName, boolean bMavenDependency )
374     {
375         if ( FilenameUtils.isExtension( sName, FilenameUtils.getExtension( staticLibrarySuffix ) ) )
376         {
377             sName = FilenameUtils.removeExtension( sName ) + ( bMavenDependency ? "${STATIC_LIBRARY_SUFFIX}" : "" );
378             if ( !StringUtils.isEmpty( staticLibraryPrefix ) )
379             {
380                 if ( 0 == sName.indexOf( staticLibraryPrefix ) )
381                 {
382                     sName = sName.replaceFirst( Pattern.quote( staticLibraryPrefix ), "" );
383                     sName = ( bMavenDependency ? "${STATIC_LIBRARY_PREFIX}" : "" ) + sName;
384                 }
385                 else
386                 {
387                     sName = "";
388                 }
389             }
390             else
391             {
392                 sName = ( bMavenDependency ? "${STATIC_LIBRARY_PREFIX}" : "" ) + sName;
393             }
394         }
395         return sName;
396     }
397     
398     protected String baseNameAsSharedModule( String sName, boolean bMavenDependency )
399     {
400         if ( FilenameUtils.isExtension( sName, FilenameUtils.getExtension( sharedModuleSuffix ) ) )
401         {
402             sName = FilenameUtils.removeExtension( sName ) + ( bMavenDependency ? "${SHARED_MODULE_SUFFIX}" : "" );
403             if ( !StringUtils.isEmpty( sharedModulePrefix ) )
404             {
405                 if ( 0 == sName.indexOf( sharedModulePrefix ) )
406                 {
407                     sName = sName.replaceFirst( Pattern.quote( sharedModulePrefix ), "" );
408                     sName = ( bMavenDependency ? "${SHARED_MODULE_PREFIX}" : "" ) + sName;
409                 }
410                 else
411                 {
412                     sName = "";
413                 }
414             }
415             else
416             {
417                 sName = ( bMavenDependency ? "${SHARED_MODULE_PREFIX}" : "" ) + sName;
418             }
419         }
420         return sName;
421     }
422     
423     protected String baseNameAsSharedLibrary( String sName, boolean bMavenDependency )
424     {
425         if ( FilenameUtils.isExtension( sName, FilenameUtils.getExtension( sharedLibrarySuffix ) ) )
426         {
427             sName = FilenameUtils.removeExtension( sName ) + ( bMavenDependency ? "${SHARED_LIBRARY_SUFFIX}" : "" );
428             if ( !StringUtils.isEmpty( sharedLibraryPrefix ) )
429             {
430                 if ( 0 == sName.indexOf( sharedLibraryPrefix ) )
431                 {
432                     sName = sName.replaceFirst( Pattern.quote( sharedLibraryPrefix ), "" );
433                     sName = ( bMavenDependency ? "${SHARED_LIBRARY_PREFIX}" : "" ) + sName;
434                 }
435                 else
436                 {
437                     sName = "";
438                 }
439             }
440             else
441             {
442                 sName = ( bMavenDependency ? "${SHARED_LIBRARY_PREFIX}" : "" ) + sName;
443             }
444         }
445         return sName;
446     }
447     
448     protected String generalizeDependencyFileName( String dependency, boolean bMavenDependency )
449     {
450         String sName = FilenameUtils.getName( dependency );
451         String fullPath = FilenameUtils.getFullPathNoEndSeparator( dependency );
452 
453         String sGeneralizedName = baseNameAsSharedLibrary( sName, bMavenDependency );
454         if ( StringUtils.isEmpty( sGeneralizedName ) )
455         {
456             sGeneralizedName = baseNameAsStaticLibrary( sName, bMavenDependency );
457         }
458         if ( StringUtils.isEmpty( sGeneralizedName ) )
459         {
460             sGeneralizedName = baseNameAsSharedModule( sName, bMavenDependency );
461         }
462         // $FB always use unix path separator with cmake even under windows !
463         return ( bMavenDependency ? fullPath + "/" : "" ) 
464             + ( StringUtils.isEmpty( sGeneralizedName ) ? sName : sGeneralizedName );
465     }
466     
467     protected boolean isDebugBuild()
468     {
469          return ( !StringUtils.isEmpty( buildConfig ) && 0 == buildConfig.indexOf( "deb" ) );
470     }
471     
472     protected void updateOrCreateCMakeDependenciesFile( List aiDependenciesLib, boolean bMavenDependencies )
473     {
474         String dependencieFile = ( bMavenDependencies ? cmakeMavenDependenciesFile : cmakeDependenciesFile );
475         String fullDependenciesFile = dependencieFile;
476         File file = new File( dependencieFile );
477         if ( !file.isAbsolute() ) 
478         {
479             // $FB always use unix path separator with cmake even under windows !
480             fullDependenciesFile = getProjectDir() + "/" + dependencieFile;
481         }
482         file = new File( fullDependenciesFile );
483       
484         if ( !file.exists() )
485         {  
486             try 
487             {
488                 file.createNewFile();
489             }
490             catch ( IOException e ) 
491             {
492                 getLog().error( dependencieFile + " script can't be created at " + file.getAbsolutePath() );
493                 return;
494             }
495         }
496         
497         // check file content
498         InputStream dependenciesStream = null;
499         String content = new String();
500         try
501         {  
502             dependenciesStream = new FileInputStream( file );
503             content = IOUtils.toString( dependenciesStream, "UTF8" );
504         }
505         catch ( IOException e )
506         {
507             // shall not happen since file has been created
508             getLog().error( dependencieFile + " script can't be opened at " + file.getAbsolutePath() );
509         }
510         finally
511         {
512             getLog().debug( "close input stream at reading" );
513             IOUtils.closeQuietly( dependenciesStream );
514         }
515 
516         String beginDepsPattern = ( bMavenDependencies
517             ? ( isDebugBuild() ? "# BEGIN MAVEN_DEBUG_DEPENDENCIES" : "# BEGIN MAVEN_OPTIMIZED_DEPENDENCIES" )
518             : "# BEGIN CMAKE_DEPENDENCIES" );
519         String endDepsPattern = ( bMavenDependencies
520             ? ( isDebugBuild() ? "# END MAVEN_DEBUG_DEPENDENCIES" : "# END MAVEN_OPTIMIZED_DEPENDENCIES" )
521             : "# END CMAKE_DEPENDENCIES" );
522             
523         String beginIncPattern = "# BEGIN MAVEN_INCLUDE_ROOTS";
524         String endIncPattern = "# END MAVEN_INCLUDE_ROOTS";
525                     
526         // reset file content if needed
527         if ( StringUtils.isEmpty( content ) || content.indexOf( beginDepsPattern ) == -1 )
528         {
529             getLog().info( file.getAbsolutePath() + " content full update" );
530             try
531             { 
532                 dependenciesStream = getClass().getResourceAsStream(
533                     ( bMavenDependencies ? "/cmake-cpp-project/CMakeMavenDependencies.txt"
534                     : "/cmake-cpp-project/CMakeDependencies.txt" ) );
535                 content = IOUtils.toString( dependenciesStream, "UTF8" );
536             }
537             catch ( IOException e )
538             {
539                 getLog().error( dependencieFile + " default content not found " );
540             }
541             finally
542             {
543                 getLog().debug( "close input stream at full update" );
544                 IOUtils.closeQuietly( dependenciesStream );
545             }
546         }
547         
548         // update file content
549         String simpleIndentation = "\n    ";
550         String doubleIndentation = "\n        ";
551         Iterator itDeps = aiDependenciesLib.iterator();
552         StringBuilder allDepsBuilder = new StringBuilder( ( bMavenDependencies
553             ? doubleIndentation : simpleIndentation ) );
554         while ( itDeps.hasNext() )
555         {
556             String dep = ( String ) itDeps.next();
557             if ( bMavenDependencies )
558             {
559                 String externalDep = generalizeDependencyFileName( dep, true );
560                 allDepsBuilder.append( "target_link_libraries(${target} "
561                     + ( isDebugBuild() ? "debug " : "optimized " )
562                     + externalDep + ")" + doubleIndentation );
563             }
564             else
565             {
566                 String cmakeDep = generalizeDependencyFileName( dep, false );         
567                 allDepsBuilder.append( 
568                     "# If a \"" + cmakeDep + "\" target has been define, this means we are building "
569                     + "an amalgamed cmake project" + simpleIndentation
570                     + "# but maven dependencies can be used too" + simpleIndentation
571                     + "if(TARGET " + cmakeDep + ")" + doubleIndentation 
572                     + "message(\"Adding direct " + cmakeDep + " cmake dependencies to target '${target}'\")"
573                     + doubleIndentation
574                     + "target_link_libraries(${target} " + cmakeDep + ")" + simpleIndentation
575                     + "endif()" + simpleIndentation );
576             }
577         }
578         
579         // adding additionalIncludeRoots in cmake maven dependencies file
580         StringBuilder addIncsBuilder = new StringBuilder( doubleIndentation );
581         if ( bMavenDependencies && null != additionalIncludeRoots )
582         {
583             addIncsBuilder.append( "include_directories( " + doubleIndentation );
584             for ( String includeRoot : additionalIncludeRoots )
585             {
586                 addIncsBuilder.append( "\"" + includeRoot + "\"" + doubleIndentation );
587             }
588             addIncsBuilder.append( ")" + doubleIndentation );
589             for ( String includeRoot : additionalIncludeRoots )
590             {
591                 addIncsBuilder.append( "message(\"Adding '" + includeRoot + "' additional include root.\")"
592                     + doubleIndentation );
593             }
594         }
595             
596         getLog().debug( dependencieFile + " depfile was : " + content );
597         String allDeps = Matcher.quoteReplacement( allDepsBuilder.toString() );
598             //.replace( "$", "\\$" ); // Matcher replaceAll() is a bit rigid !
599         getLog().debug( dependencieFile + " injected dependency will be : " + allDeps );
600         // regexp multi-line replace, see http://stackoverflow.com/questions/4154239/java-regex-replaceall-multiline
601         Pattern p1 = Pattern.compile( beginDepsPattern + ".*" + endDepsPattern, Pattern.DOTALL );
602         Matcher m1 = p1.matcher( content );
603         content = m1.replaceAll( beginDepsPattern + allDeps + endDepsPattern );
604         
605         if ( bMavenDependencies && null != additionalIncludeRoots )
606         {
607             String addIncs = Matcher.quoteReplacement( addIncsBuilder.toString() );
608                 //.replace( "$", "\\$" ); // Matcher replaceAll() is a bit rigid !
609             getLog().debug( dependencieFile + " injected includes Roots will be : " + addIncs );
610             Pattern p2 = Pattern.compile( beginIncPattern + ".*" + endIncPattern, Pattern.DOTALL );
611             Matcher m2 = p2.matcher( content );
612             content = m2.replaceAll( beginIncPattern + addIncs + endIncPattern );
613         }
614         
615         getLog().debug( dependencieFile + " depfile now is : " + content );
616         OutputStream outStream = null;
617         try
618         { 
619             outStream = new FileOutputStream( file );
620             IOUtils.write( content, outStream, "UTF8" );
621         }
622         catch ( IOException e )
623         {
624             getLog().error( dependencieFile + " script can't be written at " + file.getAbsolutePath() + e.toString() );
625         }
626         finally
627         {
628             getLog().debug( "close output stream at update" );
629             IOUtils.closeQuietly( outStream );
630         }
631     }
632     
633     protected String extractBuildConfig( String classifier )
634     {
635         //bin-${targetClassifier}-${buildConfig}
636         String[] parts = classifier.split( "-" );
637         return ( parts.length >= 3 ) ? parts[parts.length - 1] : null;
638     }
639      
640     protected String extractSubClassifier( String classifier )
641     {
642         //bin-${targetClassifier}-${buildConfig}
643         String[] parts = classifier.split( "-" );
644         if ( parts.length >= 3 )
645         {
646             //parts[1] .. parts[length-2]
647             StringBuilder builder = new StringBuilder();
648             builder.append( parts[1] );
649             for ( int i = 2; i <= parts.length - 2; i++ ) 
650             {
651                 builder.append( "-" );
652                 builder.append( parts[i] );
653             }
654             return builder.toString();
655         }
656         return  null;
657     }
658     
659     @Override
660     protected void preExecute( Executor exec, CommandLine commandLine, Properties enviro )
661         throws MojoExecutionException
662     {
663         HashMap<String, String> dependenciesRoots = new HashMap<String, String>();
664         
665         //Iterator<String> itAdditionnalDeps = additionalDependenciesRoots.iterator();
666         //while ( itAdditionnalDeps.hasNext() )
667         if ( null != additionalDependenciesRoots )
668         {
669             for ( String dependencyRoot : additionalDependenciesRoots )
670             {
671                 // $FB always use unix path separator with cmake even under windows !
672                 String cur = dependencyRoot + "/" + targetClassifier + "/"
673                     + buildConfig;
674                 dependenciesRoots.put( cur, cur );
675                 getLog().info( "add additional Dependency Root: \"" + cur + "\"" );
676             }
677         }
678         
679         // enhanced auto-detection of dependency root dir with artifacts classifier :
680         // maven 2.0.11 api doesn't provide generics containers
681         @SuppressWarnings( "unchecked" ) Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
682         Iterator<Artifact> itDeps = dependencyArtifacts.iterator();
683         while ( itDeps.hasNext() )
684         {
685             Artifact cur = itDeps.next();
686             String artifactId = cur.getArtifactId();
687             String classifer = cur.getClassifier();
688             if ( !StringUtils.isEmpty( classifer ) && 0 == classifer.indexOf( "bin" ) )
689             {
690                 String artifactBuildConfig = extractBuildConfig( classifer );
691                 String artifactBuildConfigGeneralized = artifactBuildConfig;
692                 if ( StringUtils.isEmpty( artifactBuildConfig ) || artifactBuildConfig.equals( buildConfig ) )
693                 {
694                     artifactBuildConfig = buildConfig;
695                     artifactBuildConfigGeneralized = buildConfig; //"${CMAKE_BUILD_TYPE}";
696                 }
697                 
698                 String artifactSubClassifier = extractSubClassifier( classifer );
699                 String artifactSubClassifierGeneralized = artifactSubClassifier;
700                 if ( StringUtils.isEmpty( artifactSubClassifier ) 
701                     || artifactSubClassifier.equals( targetClassifier ) )
702                 {
703                     artifactSubClassifier = targetClassifier;
704                     artifactSubClassifierGeneralized = "${TARGET_CLASSIFIER}";
705                 }
706                 // $FB always use unix path separator with cmake even under windows !
707                 String newDepRoot = getProjectDependenciesDirectory() + "/"
708                     + artifactSubClassifier + "/" + artifactBuildConfig + "/" + artifactId;
709                     
710                 String newDepRootGeneralized = "${DEPENDENCY_DIR}" + "/"
711                     + artifactSubClassifierGeneralized + "/" + artifactBuildConfigGeneralized
712                     + "/" + artifactId;
713                 
714                 if ( !dependenciesRoots.containsKey( newDepRoot ) )
715                 {
716                     dependenciesRoots.put( newDepRoot, newDepRootGeneralized );
717                     getLog().info( "add Dependency Root: \"" + newDepRoot + "\" <=> \""
718                         + newDepRootGeneralized + "\"" );
719                 }
720             }
721         }
722         
723         ArrayList<String> dependenciesLib = new ArrayList<String>();
724         findDependencies( dependenciesRoots, dependenciesLib );
725         
726         updateOrCreateCMakeDependenciesFile( dependenciesLib, true ); // maven dependencies
727         updateOrCreateCMakeDependenciesFile( dependenciesLib, false ); // cmake project dependencies
728     }
729 }