Android:链接到预建的静态库

时间:2018-04-12 08:06:37

标签: android c++ cmake android-ndk static-libraries

我为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_'

虽然错误不仅仅是由于缺少Lapack功能,还有Mumps等。

修改

查看特定的失败命令,我相信库的顺序是正确的:

  

失败:cmd.exe / C" cd。 &安培;&安培;铛++。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 -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa, - noexecstack -Wformat -Werror = format-security -O0 -fno-limit-debug -info -Wl, - exclude-libs,libgcc.a -Wl, - exclude-libs,libatomic.a --sysroot C:/ Android / android-sdk / ndk-bundle / platforms / 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,now -shared -Wl,-soname,libnative-lib.so -o ........ \ build \ intermediates \ cmake \ debug \ obj \ arm64-v8a \ libnative-lib 。所以   CMakeFiles /原生lib.dir / src目录/主/ CPP / cpp_example.cpp.o   CMakeFiles / native-lib.dir / src / main / cpp / MyNLP.cpp.o libcoinblas.a   libcoinlapack.a libcoinmetis.a libcoinmumps.a libipopt.a -latomic -lm   " C:/ Android设备/ Android的SDK / NDK束/源/ CXX-STL / GNU-的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)

但这也失败了。出于某种原因,在这种情况下,链接命令甚至不包括它应该链接的库:

  

失败:cmd.exe / C" cd。 &安培;&安培;   C:\ Android的\ Android的SDK \ NDK束\工具链\ LLVM \预置的\ WINDOWS-x86_64的\ BIN \铛++ 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-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -Wa, - noexecstack -Wformat -Werror = format-security -O0 -fno-limit-debug -info -Wl, - exclude-libs,libgcc.a -Wl, - exclude-libs,libatomic.a --sysroot C:/ Android / android-sdk / ndk-bundle / platforms / 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,now -shared -Wl,-soname,libnative-lib.so -o ........ \ build \ intermediates \ cmake \ debug \ obj \ arm64-v8a \ libnative-lib 。所以   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-STL / GNU-的libstdc ++ / 4.9 /库/ arm64-V8A / libgnustl_static.a"   &安培;&安培; cd。" CMakeFiles / native-lib.dir / src / main / cpp / cpp_example.cpp.o:In   函数`Java_io_jeti_ipopt_1static_MainActivity_stringFromJNI':

2 个答案:

答案 0 :(得分:5)

您的图书馆是相互依存的:

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

这意味着链接它们的顺序应相反:

ipopt
mumps
metis
lapack
blas 

如果您不想浪费时间来确定最佳订单,而是让链接器找出(这可能是slow your builds significantly),您可以使用

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

您还可以通过IMPORTED_LINK_INTERFACE_LIBRARIES教授CMake关于导入的静态库之间的依赖关系,例如

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

答案 1 :(得分:0)

这可能与图书馆完全没有任何关系。这可能与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

现在这不是我的专业领域,但很可能这个宏在你的情况下没有做正确的事情。您可以在Fortran编译器生成的相关.o文件上运行 nm ,以查看它与您的特定构建设置生成的内容。如果它不是 dppsv _ ,那么你就知道错误了。