У меня есть проект JNI, настроенный с Maven, используя nar-maven-plugin
, И Java, и код C ++ находятся в проекте. Основной код, по-видимому, компилируется правильно (как на C ++, так и на Java). Проблема с тестовым кодом (JUnit).
Тестовый код определил один класс Java, который сам имеет собственный метод. Соответствующий нативный код находится в каталоге
<project root>
+- src
+- test
+- c++
В сообщениях о сборке нет никаких доказательств того, что этот собственный тестовый код когда-либо компилируется, а соответствующий собственный метод вообще не отображается при запуске nm
из командной строки на DLL, созданной в процессе сборки. Кроме того, я намеренно поместил синтаксическую ошибку в тестовый код и перекомпилировал, чтобы увидеть, получу ли я ошибку во время компиляции. Там нет ошибки, в соответствии с моим убеждением, что код никогда не компилируется.
Соответственно я получаю UnsatisfiedLinkError
когда тест выполняется во время mvn install
, Обратите внимание, что из точки, в которой тест не удался, я могу сказать, что нативные методы для основного (не тестового) кода были правильно загружены и связаны. Отсюда я делаю вывод, что существует определенная проблема, связанная с созданием и компоновкой нативного тестового кода.
В настоящее время я работаю на Windows 10, используя Eclipse IDE и MinGW компиляторы для собственного кода.
Соответствующие разделы моего POM приведены ниже (слегка обновлены после моего ответа на Как избежать машинно-зависимого POM с помощью компилятора MinGW и плагина nar-maven-plugin связано с проблемой ранней конфигурации):
<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>
Есть ли известный способ справиться с этой проблемой? (Может быть, дополнительные теги конфигурации?)
Я получил это на работу, но это было не красиво. Я дам детали POM в конце, но, в общих чертах, это шаги:
<tests>
раздел на nar-maven-plugin
чтобы скомпилировать собственный тестовый код, отметив, что он действительно настроен на создание исполняемых файлов для собственных тестов, а не на создание DLL / SO, поддерживающих тесты Java<testOptions>
компоновщику, чтобы взломать его для создания DLL / SO вместо исполняемого файла<testOptions>
чтобы ваш тестовый код связывался с основным кодом проекта, так как он не поддерживается автоматически при выборе jni
(скорее, чем shared
или же static
) тип библиотекиБолее подробно рассмотрим последний пункт. Даже если вы получите тестовый код для компиляции, вы не сможете загрузить его из Java, поскольку тестовые каталоги не находятся в java.library.path
когда тесты запущены! Лучшее решение, которое я смог найти, — это временно переместить тестовую библиотеку в каталог по пути. Это казалось проще, чем изменение пути благодаря легко доступным параметрам конфигурации. При условии, что вы получите библиотеку на пути, то вы можете использовать System.loadLibrary
как обычно во время выполнения теста JUnit.
Теперь вот расширенные сегменты POM, которые выполняют вышеуказанное. Это основано на том, что я имел в вопросе, но с новыми частями требуется выполнить маркеры в начале ответа. Обратите внимание, что код JNI, поддерживающий тест, находится в файле TestWrapper.cpp
в /src/test/c++
, (Я знаю, что это не стандартное соглашение об именах для исходного файла JNI.)
НОТА: На данный момент я только разработал флаги компоновщика для тестирования на моем компьютере с Windows 10, который представляет в profiles
раздел. Аналогично, копия / удаление имеет .dll
расширение явно, что должно быть скорректировано. (Однако обратите внимание, что даже если вы получаете .dll
файл, он будет иметь .exe
расширение, когда плагин делает это!) Мой POM, без сомнения, сломан для других машин / архитектур на данный момент, но есть четкий путь к тому, чтобы заставить их работать отсюда, поэтому, кажется, стоит опубликовать ответ как есть.
<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>
Других решений пока нет …