View Javadoc

1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *      http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  package com.jayway.maven.plugins.android;
15  
16  import com.jayway.maven.plugins.android.phase05compile.NdkBuildMojo;
17  import org.apache.commons.lang.SystemUtils;
18  import org.apache.maven.plugin.MojoExecutionException;
19  
20  import java.io.File;
21  import java.util.ArrayList;
22  import java.util.Arrays;
23  import java.util.List;
24  
25  /**
26   * Represents an Android NDK.
27   *
28   * @author Johan Lindquist <johanlindquist@gmail.com>
29   */
30  public class AndroidNdk
31  {
32  
33      public static final String PROPER_NDK_HOME_DIRECTORY_MESSAGE = "Please provide a proper Android NDK directory path"
34              + " as configuration parameter <ndk><path>...</path></ndk> in the plugin <configuration/>. As an "
35              + "alternative, you may add the parameter to commandline: -Dandroid.ndk.path=... or set environment "
36              + "variable " + NdkBuildMojo.ENV_ANDROID_NDK_HOME + ".";
37  
38      public static final String[] NDK_ARCHITECTURES = { "armeabi", "armeabi-v7a", "mips", "x86" };
39  
40      /**
41       * Arm toolchain implementations.
42       */
43      private static final String[] ARM_TOOLCHAIN = {  "arm-linux-androideabi-4.7", "arm-linux-androideabi-4.6",
44                                                       "arm-linux-androideabi-4.4.3" };
45  
46      /**
47       * x86 toolchain implementations.
48       */
49      private static final String[] X86_TOOLCHAIN = { "x86-4.7", "x86-4.6", "x86-4.4.3" };
50  
51      /**
52       * Mips toolchain implementations.
53       */
54      private static final String[] MIPS_TOOLCHAIN = { "mipsel-linux-android-4.7", "mipsel-linux-android-4.6",
55                                                       "mipsel-linux-android-4.4.3" };
56  
57      /**
58       * Possible locations for the gdbserver file.
59       */
60      private static final String[] GDB_SERVER_LOCATIONS = { "toolchains/%s/prebuilt/gdbserver",
61                                                             "prebuilt/%s/gdbserver/gdbserver" };
62  
63      private final File ndkPath;
64  
65      public AndroidNdk( File ndkPath )
66      {
67          assertPathIsDirectory( ndkPath );
68          this.ndkPath = ndkPath;
69      }
70  
71      private void assertPathIsDirectory( final File path )
72      {
73          if ( path == null )
74          {
75              throw new InvalidNdkException( PROPER_NDK_HOME_DIRECTORY_MESSAGE );
76          }
77          if ( ! path.isDirectory() )
78          {
79              throw new InvalidNdkException(
80                      "Path \"" + path + "\" is not a directory. " + PROPER_NDK_HOME_DIRECTORY_MESSAGE );
81          }
82      }
83  
84      private File findStripper( String toolchain )
85      {
86          List<String> osDirectories = new ArrayList<String>();
87          String extension = "";
88  
89          if ( SystemUtils.IS_OS_LINUX )
90          {
91              osDirectories.add( "linux-x86" );
92              osDirectories.add( "linux-x86_64" );
93          }
94          else if ( SystemUtils.IS_OS_WINDOWS )
95          {
96              osDirectories.add( "windows" );
97              osDirectories.add( "windows-x86_64" );
98              extension = ".exe";
99          }
100         else if ( SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_MAC_OSX )
101         {
102             osDirectories.add( "darwin-x86" );
103             osDirectories.add( "darwin-x86_64" );
104         }
105 
106         String fileName = "";
107         if ( toolchain.startsWith( "arm" ) )
108         {
109             fileName = "arm-linux-androideabi-strip" + extension;
110         }
111         else if ( toolchain.startsWith( "x86" ) )
112         {
113             fileName = "i686-linux-android-strip" + extension;
114         }
115         else if ( toolchain.startsWith( "mips" ) )
116         {
117             fileName = "mipsel-linux-android-strip" + extension;
118         }
119 
120         for ( String osDirectory : osDirectories )
121         {
122             String stripperLocation =
123                 String.format( "toolchains/%s/prebuilt/%s/bin/%s", toolchain, osDirectory, fileName );
124             final File stripper = new File( ndkPath, stripperLocation );
125             if ( stripper.exists() )
126             {
127                 return stripper;
128             }
129         }
130         return null;
131     }
132 
133     public File getStripper( String toolchain ) throws MojoExecutionException
134     {
135         final File stripper = findStripper( toolchain );
136         if ( stripper == null )
137         {
138             throw new MojoExecutionException( "Could not resolve stripper for current OS: " + SystemUtils.OS_NAME );
139         }
140 
141         // Some basic validation
142         if ( ! stripper.exists() )
143         {
144             throw new MojoExecutionException( "Strip binary " + stripper.getAbsolutePath()
145                     + " does not exist, please double check the toolchain and OS used" );
146         }
147 
148         // We should be good to go
149         return stripper;
150     }
151 
152     private String resolveNdkToolchain( String[] toolchains )
153     {
154         for ( String toolchain : toolchains )
155         {
156             File f = findStripper( toolchain );
157             if ( f != null && f.exists() )
158             {
159                 return toolchain;
160             }
161         }
162         return null;
163     }
164 
165     /**
166      * Tries to resolve the toolchain based on the path of the file.
167      *
168      * @param file Native library
169      * @return String
170      * @throws MojoExecutionException When no toolchain is found
171      */
172     public String getToolchain( File file ) throws MojoExecutionException
173     {
174         String resolvedNdkToolchain = null;
175 
176         // try to resolve the toolchain now
177         String ndkArchitecture = file.getParentFile().getName();
178         if ( ndkArchitecture.startsWith( "arm" ) )
179         {
180             resolvedNdkToolchain = resolveNdkToolchain( ARM_TOOLCHAIN );
181         }
182         else if ( ndkArchitecture.startsWith( "x86" ) )
183         {
184             resolvedNdkToolchain = resolveNdkToolchain( X86_TOOLCHAIN );
185         }
186         else if ( ndkArchitecture.startsWith( "mips" ) )
187         {
188             resolvedNdkToolchain = resolveNdkToolchain( MIPS_TOOLCHAIN );
189         }
190 
191         // if no toolchain can be found
192         if ( resolvedNdkToolchain == null )
193         {
194             throw new MojoExecutionException(
195                 "Can not resolve automatically a toolchain to use. Please specify one." );
196         }
197         return resolvedNdkToolchain;
198     }
199 
200     /**
201      * Returns the complete path for the ndk-build tool, based on this NDK.
202      *
203      * @return the complete path as a <code>String</code>, including the tool's filename.
204      */
205     public String getNdkBuildPath()
206     {
207         if ( SystemUtils.IS_OS_WINDOWS )
208         {
209             return new File( ndkPath, "/ndk-build.cmd" ).getAbsolutePath();
210         }
211         else
212         {
213             return new File( ndkPath, "/ndk-build" ).getAbsolutePath();
214         }
215     }
216 
217     public File getGdbServer( String ndkArchitecture ) throws MojoExecutionException
218     {
219         // create a list of possible gdb server parent folder locations
220         List<String> gdbServerLocations = new ArrayList<String>();
221         if ( ndkArchitecture.startsWith( "arm" ) )
222         {
223             gdbServerLocations.add( "android-arm" );
224             gdbServerLocations.addAll( Arrays.asList( ARM_TOOLCHAIN ) );
225         }
226         else if ( ndkArchitecture.startsWith( "x86" ) )
227         {
228             gdbServerLocations.add( "android-x86" );
229             gdbServerLocations.addAll( Arrays.asList( X86_TOOLCHAIN ) );
230         }
231         else if ( ndkArchitecture.startsWith( "mips" ) )
232         {
233             gdbServerLocations.add( "android-mips" );
234             gdbServerLocations.addAll( Arrays.asList( MIPS_TOOLCHAIN ) );
235         }
236 
237         // check for the gdb server
238         for ( String location : GDB_SERVER_LOCATIONS )
239         {
240             for ( String gdbServerLocation : gdbServerLocations )
241             {
242                 File gdbServerFile = new File( ndkPath, String.format( location, gdbServerLocation ) );
243                 if ( gdbServerFile.exists() )
244                 {
245                     return gdbServerFile;
246                 }
247             }
248         }
249 
250         //  if we got here, throw an error
251         throw new MojoExecutionException( "gdbserver binary for architecture " + ndkArchitecture
252             + " does not exist, please double check the toolchain and OS used" );
253     }
254 }