private void setupNativeLibraryEnvironment( MakefileHelper makefileHelper, CommandExecutor executor, Set<Artifact> resolveNativeLibraryArtifacts, String ndkArchitecture) { // Only add the LOCAL_STATIC_LIBRARIES if (NativeHelper.hasStaticNativeLibraryArtifact( resolveNativeLibraryArtifacts, unpackedApkLibsDirectory, ndkArchitecture)) { String staticlibs = makefileHelper.createLibraryList(resolveNativeLibraryArtifacts, ndkArchitecture, true); executor.addEnvironment("ANDROID_MAVEN_PLUGIN_LOCAL_STATIC_LIBRARIES", staticlibs); getLog().debug("Set ANDROID_MAVEN_PLUGIN_LOCAL_STATIC_LIBRARIES = " + staticlibs); } // Only add the LOCAL_SHARED_LIBRARIES if (NativeHelper.hasSharedNativeLibraryArtifact( resolveNativeLibraryArtifacts, unpackedApkLibsDirectory, ndkArchitecture)) { String sharedlibs = makefileHelper.createLibraryList(resolveNativeLibraryArtifacts, ndkArchitecture, false); executor.addEnvironment("ANDROID_MAVEN_PLUGIN_LOCAL_SHARED_LIBRARIES", sharedlibs); getLog().debug("Set ANDROID_MAVEN_PLUGIN_LOCAL_SHARED_LIBRARIES = " + sharedlibs); } }
private void cleanUp( File nativeLibDirectory, String ndkArchitecture, boolean libsDirectoryExists, File directoryToRemove, MakefileHelper.MakefileHolder makefileHolder, File makefileCaptureFile) throws IOException, MojoExecutionException { try { // Cleanup libs/armeabi directory if needed - this implies moving any native artifacts into // target/libs if (clearNativeArtifacts) { nativeLibDirectory = cleanUpNativeArtifacts(nativeLibDirectory, ndkArchitecture, libsDirectoryExists); } // Attempt to attach the native library if the project is defined as a "pure" native Android // library // (packaging is 'so' or 'a') or if the plugin has been configured to attach the native // library to the // build if ("so".equals(project.getPackaging()) || "a".equals(project.getPackaging()) || attachNativeArtifacts) { final File nativeArtifactFile; if (ndkFinalLibraryName == null) { nativeArtifactFile = findNativeLibrary(nativeLibDirectory); } else { nativeArtifactFile = nativeLibraryFromName(nativeLibDirectory); } final String artifactType = resolveArtifactType(nativeArtifactFile); if (nativeArtifactFile.getName().endsWith(".so") && !skipStripping) { getLog() .debug("Post processing (stripping) native compiled artifact: " + nativeArtifactFile); invokeNDKStripper(nativeArtifactFile); } getLog().debug("Adding native compiled artifact: " + nativeArtifactFile); File fileToAttach = nativeArtifactFile; if (!libsDirectoryExists) { getLog().debug("Moving native compiled artifact to target directory for preservation"); // This indicates the output directory was created by the build (us) and that we should // really // move it to the target (needed to preserve the attached artifact once install is // invoked) final String destFileName = ndkArchitecture + File.separator + nativeArtifactFile.getName(); final File destFile = new File(ndkOutputDirectory, destFileName); if (destFile.exists()) { destFile.delete(); } getLog().debug(nativeArtifactFile + " -> " + destFile); FileUtils.moveFile(nativeArtifactFile, destFile); fileToAttach = destFile; } projectHelper.attachArtifact(this.project, artifactType, ndkArchitecture, fileToAttach); } // Process conditionally any of the headers to include into the header archive file processMakefileCapture(makefileCaptureFile, ndkArchitecture); } finally { // If we created any directories as part of the build, blow those away after we're done if (!libsDirectoryExists) { getLog().info("Cleaning up native library output directory after build"); getLog().debug("Removing directory: " + directoryToRemove); // AJE - removes 'obj' directory FileUtils.deleteDirectory(directoryToRemove); } // If we created a makefile for the build we should be polite and remove any extracted include // directories after we're done if (makefileHolder != null) { getLog().info("Cleaning up extracted include directories used for build"); MakefileHelper.cleanupAfterBuild(makefileHolder); } } }
/** * @throws MojoExecutionException * @throws MojoFailureException */ public void execute() throws MojoExecutionException, MojoFailureException { try { // Validate the NDK final File ndkBuildFile = new File(getAndroidNdk().getNdkBuildPath()); NativeHelper.validateNDKVersion(ndkBuildFile.getParentFile()); // Validate the makefile - if our packaging type is so (for example) and there are // dependencies on .a files (or shared files for that matter) the makefile should include // the include of our Android Maven plugin generated makefile. validateMakefile(project, makefile); String[] ndkArchitectures = getAndroidNdk() .getNdkArchitectures( ndkClassifier, ndkArchitecture, applicationMakefile, project.getBasedir()); for (String ndkArchitecture : ndkArchitectures) { Preparation preparation = new Preparation().invoke(ndkArchitecture); boolean libsDirectoryExists = preparation.isLibsDirectoryExists(); File directoryToRemove = preparation.getDirectoryToRemove(); // Start setting up the command line to be executed final CommandExecutor executor = CommandExecutor.Factory.createDefaultCommmandExecutor(); // Add an error listener to the build - this allows the build to conditionally fail // depending on a) the output of the build b) whether or not build errors (output on stderr) // should be // ignored and c) whether the pattern matches or not executor.setErrorListener(getNdkErrorListener()); final Set<Artifact> nativeLibraryArtifacts = findNativeLibraryDependencies(); // If there are any static libraries the code needs to link to, include those in the make // file final Set<Artifact> resolveNativeLibraryArtifacts = AetherHelper.resolveArtifacts( nativeLibraryArtifacts, repoSystem, repoSession, projectRepos); if (getLog().isDebugEnabled()) { getLog() .debug( "resolveArtifacts found " + resolveNativeLibraryArtifacts.size() + ": " + resolveNativeLibraryArtifacts.toString()); } final File makefileDir = new File(project.getBuild().getDirectory(), NDK_MAKFILE_DIRECTORY); makefileDir.mkdirs(); final File androidMavenMakefile = new File(makefileDir, "android_maven_plugin_makefile.mk"); // set the ndk build directory if (ndkBuildDirectory == null) { ndkBuildDirectory = project.getBasedir().getAbsolutePath(); } final MakefileHelper makefileHelper = new MakefileHelper( getLog(), repoSystem, repoSession, projectRepos, unpackedApkLibsDirectory); final MakefileHelper.MakefileHolder makefileHolder = makefileHelper.createMakefileFromArtifacts( new File(ndkBuildDirectory), resolveNativeLibraryArtifacts, ndkArchitecture, useHeaderArchives); IOUtil.copy(makefileHolder.getMakeFile(), new FileOutputStream(androidMavenMakefile)); // Add the path to the generated makefile - this is picked up by the build (by an include // from the user) executor.addEnvironment( "ANDROID_MAVEN_PLUGIN_MAKEFILE", androidMavenMakefile.getAbsolutePath()); setupNativeLibraryEnvironment( makefileHelper, executor, resolveNativeLibraryArtifacts, ndkArchitecture); // Adds the location of the Makefile capturer file - this file will after the build include // things like header files, flags etc. It is processed after the build to retrieve the // headers // and also capture flags etc ... final File makefileCaptureFile = File.createTempFile("android_maven_plugin_makefile_captures", ".tmp"); makefileCaptureFile.deleteOnExit(); executor.addEnvironment( MakefileHelper.MAKEFILE_CAPTURE_FILE, makefileCaptureFile.getAbsolutePath()); // Add any defined system properties if (systemProperties != null && !systemProperties.isEmpty()) { for (Map.Entry<String, String> entry : systemProperties.entrySet()) { executor.addEnvironment(entry.getKey(), entry.getValue()); } } executor.setLogger(this.getLog()); // Setup the command line for the make final List<String> commands = new ArrayList<String>(); // Setup the build directory (defaults to the current directory) but may be different // depending // on user configuration commands.add("-C"); commands.add(ndkBuildDirectory); // If the build should use a custom makefile or not - some validation is done to ensure // this exists and all if (makefile != null) { File makeFile = new File(project.getBasedir(), makefile); if (!makeFile.exists()) { getLog().error("Specified makefile " + makeFile + " does not exist"); throw new MojoExecutionException("Specified makefile " + makeFile + " does not exist"); } commands.add("-f"); commands.add(makefile); } configureApplicationMakefile(commands); configureMaxJobs(commands); configureNdkToolchain(commands); // Anything else on the command line the user wants to add - simply splice it up and // add it one by one to the command line if (ndkBuildAdditionalCommandline != null) { String[] additionalCommands = ndkBuildAdditionalCommandline.split(" "); for (final String command : additionalCommands) { commands.add(command); } } // If a build target is specified, tag that onto the command line as the // very last of the parameters if (target != null) { commands.add(target); } else /*if ( "a".equals( project.getPackaging() ) )*/ { commands.add(project.getArtifactId()); } final String ndkBuildPath = resolveNdkBuildExecutable(); getLog().info(ndkBuildPath + " " + commands.toString()); executor.executeCommand(ndkBuildPath, commands, project.getBasedir(), true); cleanUp( preparation.getNativeLibDirectory(), ndkArchitecture, libsDirectoryExists, directoryToRemove, makefileHolder, makefileCaptureFile); } } catch (MojoExecutionException e) { getLog().error("Error during build: " + e.getMessage(), e); throw e; } catch (Exception e) { getLog().error("Error while executing: " + e.getMessage()); throw new MojoExecutionException(e.getMessage(), e); } }