it-roy-ru.com

Android: ссылки на готовые статические библиотеки

Я собрал несколько статических и общих библиотек для Android. В частности, у меня есть библиотеки 

libcoinblas.a   libcoinlapack.a   libcoinmetis.a   libcoinmumps.a   libipopt.a
libcoinblas.so  libcoinlapack.so  libcoinmetis.so  libcoinmumps.so  libipopt.so

Кроме того, эти библиотеки взаимозависимы, то есть 

Lapack requires Blas
Mumps  requires Blas and Metis
Ipopt  requires Mumps, Metis, and Lapack

Проект Android корректно связывается и запускается при использовании общих библиотек, но не может быть собран со статическими библиотеками. 

В общем случае я использую файл cmake

cmake_minimum_required(VERSION 3.4.1)

add_library( native-lib
             SHARED
             src/main/cpp/cpp_example.cpp
             src/main/cpp/MyNLP.cpp)

# Add dependent libraries
add_library(blas SHARED IMPORTED)
set_property(TARGET blas PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinblas.so)

add_library(lapack SHARED IMPORTED)
set_property(TARGET lapack PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinlapack.so)

add_library(metis SHARED IMPORTED)
set_property(TARGET metis PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinmetis.so)

add_library(mumps SHARED IMPORTED)
set_property(TARGET mumps PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinmumps.so)

add_library(ipopt SHARED IMPORTED)
set_property(TARGET ipopt PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libipopt.so)

# Location of header files
include_directories(${CMAKE_SOURCE_DIR}/libs/include
                    ${CMAKE_SOURCE_DIR}/libs/include/ThirdParty)

target_link_libraries( native-lib

                       blas
                       lapack
                       metis
                       mumps
                       ipopt
                       )

и в статическом случае 

cmake_minimum_required(VERSION 3.4.1)

add_library( native-lib
             SHARED
             src/main/cpp/cpp_example.cpp
             src/main/cpp/MyNLP.cpp)

# Add dependent libraries
add_library(blas STATIC IMPORTED)
set_property(TARGET blas PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinblas.a)

add_library(lapack STATIC IMPORTED)
set_property(TARGET lapack PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinlapack.a)

add_library(metis STATIC IMPORTED)
set_property(TARGET metis PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinmetis.a)

add_library(mumps STATIC IMPORTED)
set_property(TARGET mumps PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libcoinmumps.a)

add_library(ipopt STATIC IMPORTED)
set_property(TARGET ipopt PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/${Android_ABI}/libipopt.a)

# Location of header files
include_directories(${CMAKE_SOURCE_DIR}/libs/include
                    ${CMAKE_SOURCE_DIR}/libs/include/ThirdParty)

target_link_libraries( native-lib

                       blas
                       lapack
                       metis
                       mumps
                       ipopt
                       )

Я предположил, что мне просто нужно изменить способ добавления библиотек из 

add_library(libxxx SHARED IMPORTED)
set_property(TARGET libxxx PROPERTY ... libxxx.so)

в 

add_library(libxxx STATIC IMPORTED)
set_property(TARGET libxxx PROPERTY ... libxxx.a)

Но это не работает. В частности, в статическом случае я получаю кучу (сотни) 

undefined reference to xxx 

ошибки. Например, 

../../../../libs/arm64-v8a/libipopt.a(IpLapack.o): In function `Ipopt::IpLapackDppsv(int, int, double const*, double*, int, int&)':
IpLapack.cpp:(.text+0x3d4): undefined reference to `dppsv_'

Хотя ошибки связаны не только с отсутствующими функциями Лапака, но и с Mumps и другими. 


Правка

Глядя на конкретную неудачную команду, я считаю, что библиотеки были указаны в правильном порядке: 

СБОЙ: cmd.exe/C "cd. && clang ++. Exe --Target = aarch64-none-linux-Android --gcc-toolchain = C:/Android/android-sdk/ndk-bundle/toolchains/aarch64 -linux-Android-4.9/prebuilt/windows-x86_64 --sysroot = sysroot -fPIC -isystem C:/Android/android-sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-Android -D__Android_API __ = 23 -g -DANDROID -функция-разделы -funwind-таблицы -fstack-protector-strong -no-канонические-префиксы -Wa, - noexecstack -Wformat -Werror = формат-безопасность -O0 -fno-limit- debug-info -Wl, - exclude-libs, libgcc.a -Wl, - exclude-libs, libatomic.a --sysroot C:/Android/android-sdk/ndk-bundle/платформы/Android-23/Arch -arm64 -Wl, - build-id -Wl, - warn-shared-textrel -Wl, - fatal-warnings -Wl, - no-undefined -Wl, -z, noexecstack -Qunused-arguments -Wl, -z, relro -Wl, -z, теперь -shared -Wl, -soname, libnative-lib.so -o ........\build\middleates\cmake\debug\obj\arm64- v8a\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/cpp_example.cpp.o CMakeFiles/native-lib.dir/sr c/main/cpp/MyNLP.cpp.o libcoinblas.a libcoinlapack.a libcoinmetis.a libcoinmumps.a libipopt.a -latomic -lm "C:/Android/Android-SDK/NDK-расслоение/источники/CXX-СТЛ/гну-libstdc ++/4,9/ЛИЭС/arm64-V8A/libgnustl_static.a" && CD ."

Обратите внимание, что я очистил пути чуть выше, чтобы они были немного читабельными, но ближе к концу вы можете видеть, что библиотеки перечислены в порядке 

libcoinblas.a libcoinlapack.a libcoinmetis.a libcoinmumps.a libipopt.a

Правка

Я также попытался изменить команду ссылки с target_link_library на link_library:

link_libraries(native-lib blas lapack metis mumps ipopt)

но это также не удается. По какой-то причине в этом случае команда link даже не включает библиотеки, на которые она должна ссылаться: 

СБОЙ: cmd.exe/C "cd. && C:\Android\android-sdk\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang ++. Exe --Target = aarch64 -none-linux-Android --gcc-toolchain = C: /Android/android-sdk/ndk-bundle/toolchains/aarch64-linux-Android-4.9/prebuilt/windows-x86_64 --sysroot = C:/Android/android-sdk/ndk-bundle/sysroot -fPIC -isystem C:/Android/android-sdk/ndk-bundle/sysroot/usr/include/aarch64-linux-Android -D__Android_API __ = 23 -g -DANDROID -ffunction-section -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa, - noexecstack -Wformat -Werror = формат-безопасность -O0 -fno-limit-debug-info -Wl, - исключить -libs, libgcc.a -Wl, - exclude-libs, libatomic.a --sysroot C:/Android/android-sdk/ndk-bundle/платформы/Android-23/Arch-arm64 -Wl, - -build-id -Wl, - warn-shared-textrel -Wl, - fatal-warnings -Wl, - no-undefined -Wl, -z, noexecstack -Qunused-arguments -Wl, -z, relro -Wl , -z, теперь -shared -Wl, -soname, libnative-lib.so -o ........\build\middleates\cmake\debug\obj\arm64- V8A\libnative-lib.so CMakeFiles/нативной lib.dir/SRC/главная/CPP/cpp_example.cpp.o CMakeFiles/native-lib.dir/src/main/cpp/MyNLP.cpp.o -latomic -lm "C:/Android/Android-SDK/NDK-расслоение/источники/CXX-СТЛ/гну-libstdc ++/4,9/ЛИЭС/arm64-V8A/libgnustl_static.a" && cd. "CMakeFiles/native-lib.dir/src/main/cpp/cpp_example.cpp.o: в функция` Java_io_jeti_ipopt_1static_MainActivity_stringFromJNI ':

9
bremen_matt

Ваши библиотеки взаимозависимы:

Lapack requires Blas
Mumps  requires Blas and Metis
Ipopt  requires Mumps, Metis, and Lapack

Это означает, что порядок их связывания должен быть обратным:

ipopt
mumps
metis
lapack
blas 

Если вы не хотите тратить время на поиск лучшего порядка, а просто позволить компоновщику выяснить (это может значительно замедлить ваши сборки ), вы можете использовать

target_link_libraries (native-lib -Wl, - start-group blas lapack metis mumps ipopt -Wl, - end-group) .

Вы также можете обучить CMake зависимостям между импортированными статическими библиотеками через IMPORTED_LINK_INTERFACE_LIBRARIES , например,.

set_target_properties(lapack 
  PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES 
  blas)

и так далее.

Это переведет 

target_link_libraries( native-lib
                   blas
                   lapack
                   )

К

clang++ -o libnative-lib.so … libblas.a libnlapack.a libblas.a
4
Alex Cohn

Это может не иметь никакого отношения к библиотекам вообще. Это может быть связано с тем, как прототип dppsv ().

Исходный файл, соответствующий ошибке компоновщика, которую вы цитируете в своем сообщении, находится здесь:

https://github.com/coin-or/Ipopt/blob/master/Ipopt/src/LinAlg/IpLapack.cpp

И это содержит следующий фрагмент кода:

extern "C" {

/** LAPACK Fortran subroutine DPPSV. */
void F77_FUNC(dppsv,DPPSV)(char *uplo, ipfint *n,
                           ipfint *nrhs, const double *A,
                           double *B, ipfint *ldB, ipfint *info);
}

Макрос F77_FUNC, очевидно, предназначен для сопоставления с соглашением об именах функций, используемым любым используемым вами компилятором Fortran, см. Здесь:

https://github.com/coin-or/Ipopt/blob/master/Ipopt/src/Common/IpoptConfig.h

Сейчас это не моя область знаний, но вполне возможно, что этот макрос не работает правильно в вашем случае. Вы можете запустить nm для соответствующего файла .o, созданного компилятором Fortran, чтобы увидеть, что он генерирует с вашей конкретной конфигурацией сборки. Если это не dppsv_, то вы знаете, что не так.

0
Paul Sanders