2017-06-30 1 views
1

J'ai un projet JNI configuré avec Maven en utilisant le nar-maven-plugin. Le code Java et le code C++ résident tous les deux dans le projet. Le code principal compile apparemment correctement (C++ et Java). Le problème est avec le code de test (JUnit).Le code natif pour les tests JUnit n'est pas compilé avec `nar-maven-plugin`

Le code de test a défini une classe Java qui possède elle-même une méthode native. Le code natif réside dans le répertoire

<project root> 
+- src 
    +- test 
     +- c++ 

Il n'y a aucune preuve des messages de construction que ce code de test natif correspondant est jamais compilé et la méthode native correspondante ne semble pas du tout quand je lance nm de la ligne de commande la DLL créée par le processus de construction. En outre, j'ai intentionnellement mis une erreur de syntaxe dans le code de test et recompilé pour voir si j'obtiendrais une erreur de compilation. Il n'y a pas d'erreur, cohérente avec ma conviction que le code n'est jamais compilé.

En conséquence, j'obtiens un UnsatisfiedLinkError lorsque le test est exécuté pendant mvn install. Notez que je peux dire à partir du moment où le test a échoué que les méthodes natives pour le code principal (non-test) ont été correctement chargées et liées. Par conséquent, je conclus qu'il y a un problème lié à la construction et à la liaison du code de test natif spécifiquement.

Je suis actuellement sur Windows 10 utilisant les compilateurs Eclipse IDE et MinGW pour le code natif.

Les sections pertinentes de mon POM sont ci-dessous (légèrement mis à jour de ma réponse sur Avoiding machine-dependent POM with MinGW compiler and nar-maven-plugin liée à un problème de configuration précoce):

<profiles> 
    <profile> 
     <id>Windows-MinGW</id> 
     <activation> 
      <os> 
       <family>Windows</family> 
      </os> 
     </activation> 
     <build> 
      <plugins> 
       <plugin> 
        <groupId>com.github.maven-nar</groupId> 
        <artifactId>nar-maven-plugin</artifactId> 
        <version>3.5.1</version> 
        <extensions>true</extensions> 
        <configuration> 
         <cpp> 
          <options> 
            <option>-std=c++1y</option> 
          </options> 
         </cpp> 

         <linker> 
          <name>g++</name> 
          <options> 
           <option>-Wl,--kill-at</option> 
          </options> 
         </linker> 
        </configuration> 
       </plugin> 
      </plugins> 
     </build> 
    </profile> 
</profiles> 

<build> 
    <defaultGoal>integration-test</defaultGoal> 

    <plugins> 
     <plugin> 
      <groupId>com.github.maven-nar</groupId> 
      <artifactId>nar-maven-plugin</artifactId> 
      <version>3.5.1</version> 
      <extensions>true</extensions> 
      <configuration> 
       <cpp> 
        <defines> 
         <define>EXPORT_DLL</define> 
        </defines> 
       </cpp> 
       <libraries> 
        <library> 
         <type>jni</type> 
         <narSystemPackage>com.mycompany.sandbox</narSystemPackage> 
        </library> 
       </libraries> 
      </configuration> 
     </plugin> 
    </plugins> 

</build> 

Yat-il un moyen connu pour gérer ce problème? (Peut-être des balises de configuration supplémentaires?)

Répondre

1

Je me suis mis au travail, mais ce n'était pas joli. Je vais vous donner les pièces POM à la fin, mais, dans les grandes lignes, ce sont les étapes:

  • Mettre en place le projet dans la question de la compilation du code principal
  • Utilisez la section <tests> sur nar-maven-plugin à compiler le code de test natif, en notant que c'est vraiment configuré pour créer des exécutables pour les tests natifs pour ne pas créer de DLL/SO backing tests Java
  • Spécifiez <testOptions> à l'éditeur de liens pour le pirater en faisant un DLL/SO au lieu d'un exécutable
  • Précisez encore <testOptions> pour que votre code de test soit lié au code principal du projet puisque ce ne sont pas pris en charge automatiquement lorsque vous choisissez jni (plutôt que shared ou static) type de bibliothèque
  • Déplacer la bibliothèque de test dans le chemin avant le test et la supprimer après

L'expansion sur la dernière balle dans plus detail: Même une fois que vous aurez compilé le code de test, vous ne pourrez pas le charger depuis Java car les répertoires de test ne sont pas sur le java.library.path lorsque les tests sont exécutés! La meilleure solution que j'ai pu trouver était de déplacer temporairement la bibliothèque de test dans un répertoire qui se trouve sur le chemin. Cela semblait plus facile que de changer le chemin en raison des options de configuration facilement disponibles. À condition que vous obteniez la bibliothèque sur le chemin, vous pouvez utiliser System.loadLibrary comme d'habitude pendant l'exécution du test JUnit.

Maintenant, voici les segments POM développés qui accomplissent ce qui précède. Ceci est basé sur ce que j'avais dans la question, mais avec les nouvelles pièces nécessite d'accomplir les balles au début de la réponse. Notez que le code JNI soutenant le test est dans un fichier TestWrapper.cpp dans /src/test/c++. (Je sais que ce n'est pas convention de nommage standard pour un fichier source JNI.)

NOTE: A ce stade, je n'ai travaillé les drapeaux de l'éditeur de liens pour tester sur ma machine Windows 10, qui représente dans la section profiles. De même, la copie/suppression a l'extension .dll explicitement, qui aurait besoin d'être ajustée. (Notez en outre, que même si vous obtenez un fichier .dll, il aura une extension .exe quand le plugin le fera!) Mon POM est sans aucun doute cassé pour d'autres machines/architectures à ce stade, mais il y a un chemin clair vers l'avant pour les faire fonctionner à partir d'ici, il semble donc utile d'afficher la réponse telle quelle.

<profiles> 
    <profile> 
     <id>Windows-MinGW</id> 
     <activation> 
      <os> 
       <family>Windows</family> 
      </os> 
     </activation> 
     <build> 
      <plugins> 
       <plugin> 
        <groupId>com.github.maven-nar</groupId> 
        <artifactId>nar-maven-plugin</artifactId> 
        <version>3.5.1</version> 
        <extensions>true</extensions> 
        <configuration> 
         <cpp> 
          <options> 
           <option>-std=c++1y</option> 
          </options> 
         </cpp> 
         <linker> 
          <name>g++</name> 
          <options> 
           <option>-Wl,--kill-at</option> 
          </options> 
          <testOptions> 
           <!-- Put the -shared flag onto the linker - That will force a DLL instead of an EXE --> 
           <testOption>-shared</testOption> 
           <!-- We cannot easily link to the *library* that was created for the main project but we can get the compiled object files with the following option --> 
           <testOption>${project.build.directory}/nar/obj/${nar.aol}/*.o</testOption> 
          </testOptions> 
         </linker> 
        </configuration> 
       </plugin>     
      </plugins> 
     </build> 
    </profile> 
</profiles> 

<build> 
    <defaultGoal>integration-test</defaultGoal> 

    <plugins> 
     <plugin> 
      <groupId>com.github.maven-nar</groupId> 
      <artifactId>nar-maven-plugin</artifactId> 
      <version>3.5.1</version> 
      <extensions>true</extensions> 
      <configuration> 
       <cpp> 
        <defines> 
         <define>EXPORT_DLL</define> 
        </defines> 
       </cpp> 
       <libraries> 
        <library> 
         <type>jni</type> 
         <narSystemPackage>com.mycompany.mypackage</narSystemPackage> 
        </library> 
       </libraries> 
       <tests> 
        <test> 
         <name>TestWrapper</name> 
         <run>false</run> 
        </test> 
       </tests> 
      </configuration> 
     </plugin> 

     <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-antrun-plugin</artifactId> 
      <version>1.7</version> 
      <executions> 
       <execution> 
        <id>copy-test-lib-to-path</id> 
        <phase>pre-integration-test</phase> 
        <configuration> 
         <target> 
          <copy file="${project.build.directory}/test-nar/bin/${nar.aol}/TestWrapper.exe" tofile="${project.build.directory}/nar/${project.artifactId}-${project.version}-${nar.aol}-jni/lib/${nar.aol}/jni/TestWrapper.dll"/> 
         </target> 
        </configuration> 
        <goals> 
         <goal>run</goal> 
        </goals> 
       </execution> 
       <execution> 
        <id>delete-test-lib-from-deployment</id> 
        <phase>post-integration-test</phase> 
        <configuration> 
         <target> 
          <delete file="${project.build.directory}/nar/${project.artifactId}-${project.version}-${nar.aol}-jni/lib/${nar.aol}/jni/TestWrapper.dll"/> 
         </target> 
        </configuration> 
        <goals> 
         <goal>run</goal> 
        </goals> 
       </execution> 
      </executions> 
     </plugin> 

    </plugins>