private Set<Artifact> findNativeLibraryDependencies() throws MojoExecutionException {
    final NativeHelper nativeHelper = getNativeHelper();
    final Set<Artifact> staticLibraryArtifacts =
        nativeHelper.getNativeDependenciesArtifacts(this, getUnpackedLibsDirectory(), false);
    final Set<Artifact> sharedLibraryArtifacts =
        nativeHelper.getNativeDependenciesArtifacts(this, getUnpackedLibsDirectory(), true);

    final Set<Artifact> mergedArtifacts = new LinkedHashSet<Artifact>();
    filterNativeDependencies(mergedArtifacts, staticLibraryArtifacts);
    filterNativeDependencies(mergedArtifacts, sharedLibraryArtifacts);

    getLog()
        .debug(
            "findNativeLibraryDependencies found "
                + mergedArtifacts.size()
                + ": "
                + mergedArtifacts.toString());

    return mergedArtifacts;
  }
  private Set<Artifact> findNativeLibraryDependencies() throws MojoExecutionException {
    NativeHelper nativeHelper =
        new NativeHelper(project, projectRepos, repoSession, repoSystem, artifactFactory, getLog());
    final Set<Artifact> staticLibraryArtifacts =
        nativeHelper.getNativeDependenciesArtifacts(unpackedApkLibsDirectory, false);
    final Set<Artifact> sharedLibraryArtifacts =
        nativeHelper.getNativeDependenciesArtifacts(unpackedApkLibsDirectory, true);

    final Set<Artifact> mergedArtifacts = new LinkedHashSet<Artifact>();
    filterNativeDependencies(mergedArtifacts, staticLibraryArtifacts);
    filterNativeDependencies(mergedArtifacts, sharedLibraryArtifacts);

    if (getLog().isDebugEnabled()) {
      getLog()
          .debug(
              "findNativeLibraryDependencies found "
                  + mergedArtifacts.size()
                  + ": "
                  + mergedArtifacts.toString());
    }

    return mergedArtifacts;
  }
  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);
    }
  }
  /**
   * @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);
    }
  }
Esempio n. 5
0
  private void processNativeLibraries(final List<File> natives, String ndkArchitecture)
      throws MojoExecutionException {
    // Examine the native libraries directory for content. This will only be true if:
    // a) the directory exists
    // b) it contains at least 1 file
    final boolean hasValidNativeLibrariesDirectory = hasValidNativeLibrariesDirectory();
    final boolean hasValidBuildNativeLibrariesDirectory = hasValidBuildNativeLibrariesDirectory();
    final Set<Artifact> artifacts = getNativeLibraryArtifacts();

    if (artifacts.isEmpty()
        && hasValidNativeLibrariesDirectory
        && !hasValidBuildNativeLibrariesDirectory) {

      getLog()
          .debug(
              "No native library dependencies detected, will point directly to "
                  + nativeLibrariesDirectory);

      // Point directly to the directory in this case - no need to copy files around
      addNativeDirectory(natives, nativeLibrariesDirectory);

      // FIXME: This would pollute a libs folder which is under source control
      // FIXME: Would be better to not support this case?
      optionallyCopyGdbServer(nativeLibrariesDirectory, ndkArchitecture);

    } else {
      if (!artifacts.isEmpty() || hasValidNativeLibrariesDirectory) {
        // In this case, we may have both .so files in it's normal location
        // as well as .so dependencies

        final File destinationDirectory = makeNativeLibrariesOutputDirectory();

        // Point directly to the directory
        addNativeDirectory(natives, destinationDirectory);

        // If we have a valid native libs, copy those files - these already come in the structure
        // required
        if (hasValidNativeLibrariesDirectory) {
          copyLocalNativeLibraries(nativeLibrariesDirectory, destinationDirectory);
        }

        if (!artifacts.isEmpty()) {
          for (Artifact resolvedArtifact : artifacts) {
            if (NativeHelper.artifactHasHardwareArchitecture(
                resolvedArtifact,
                ndkArchitecture,
                nativeLibrariesDependenciesHardwareArchitectureDefault)) {
              copyNativeLibraryArtifactFileToDirectory(
                  resolvedArtifact, destinationDirectory, ndkArchitecture);
            } else if (APKLIB.equals(resolvedArtifact.getType())
                || AAR.equals(resolvedArtifact.getType())) {
              addNativeDirectory(natives, getUnpackedLibNativesFolder(resolvedArtifact));
            }
          }
        }

        // Finally, think about copying the gdbserver binary into the APK output as well
        optionallyCopyGdbServer(destinationDirectory, ndkArchitecture);
      }
    }
  }