【问题标题】:Android Studio linker command failed while including Boost librariesAndroid Studio 链接器命令在包含 Boost 库时失败
【发布时间】:2017-07-21 11:29:36
【问题描述】:

坦率地说,我已经无能为力了,我真的需要一个地方来崩溃。在编译时,我不断得到一个

错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)

我认为这是由于项目构建和 boost 库之间的不兼容或只是不同的编译器版本,但只要我阅读二进制文件就可以完美兼容(?)。

建筑加速
我在 Windows 10 上通过 MinGW 编译,但为了排除此处的错误,我最终使用 this git shell script 构建了 boost,它与最新版本的 Boost (1.64.0) 和 NDK (r15b) 一起使用。我在带有 Ubuntu 16.04 的 VirtualBox 中做到了这一点,因为我没有足够的知识来适应 Windows 10(至少我不能)。现在我已经用 gnu-4.9 和 llvm-3.5 为 x86 编译了分片和静态库(我在 AStudio 中的模拟器也被禁止使用)。

Android Studio
我正在使用 Cmake 构建我的项目的 C/C++ 库。我有几个相互依赖的 C 库和一个 C++ 库。最后一个是使用boost的。由于 all 库的构建和发现没有错误,尽管所有 C 头文件都有预处理器声明:extern C,但对我来说似乎是一个名称修改问题。除了 boost 部分,所有的都运行完美

CMake
设置了 find_package() REQUIRED 参数并且 Boost_DEBUG 告诉所有组件都已找到。因为在某个时候我得到了错误

对 boost::system::generic_category() 的未定义引用

我将系统添加到组件中,因此我的简约组件设置仅包含与此特定问题有关的许多其他线程所建议的计时和系统。我尝试单独链接 boost 库,但没有成功:

target_link_libraries( MyLib ${Boost_SYSTEM_LIBRARY} 
                                            ${Boost_CHRONO_LIBRARY}
                                            )

但现在我遇到了上述问题,此时我正在举起休战旗。每个提示都非常感谢!非常感谢您!

CMakeLists.txt

set( Boost_DEBUG ON )
set( Boost_USE_STATIC_LIBS ON )
set( Boost_USE_STATIC_RUNTIME ON )
set( Boost_USE_MULTITHREADED OFF )
set( Boost_NO_SYSTEM_PATHS ON )
set( BOOST_ALL_DYN_LINK OFF )

set( BOOST_ROOT C:/MyBoost )
set( Boost_INCLUDE_DIR ${BOOST_ROOT}/include )
set( Boost_LIBRARY_DIR ${BOOST_ROOT}/lib )
set( Boost_Version 1.64.0 )

find_package( Boost ${Boost_Version} COMPONENTS system chrono )
if( Boost_FOUND )
    target_include_directories( MyLib PUBLIC/PRIVATE ${Boost_INCLUDE_DIR} )    
    link_directories( ${Boost_LIBRARY_DIR} )
endif()
target_link_libraries( MyLib ${Boost_LIBRARIES} )

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "My_ID"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

===== 更新 =====

我加了

externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions -DBOOST_SYSTEM_NO_DEPRECATED"
            }

到 build.gradle 文件,现在它可以按预期编译,甚至包括线程或 chrono 库!虽然我之前注释掉的一些命令现在仍然不起作用。我现在收到以下错误:

libboost_chrono.a:添加符号时出错:文件格式错误

这应该是apk版本和boost库的问题??!如果是这样,如何确保我使用的是正确的 Boost 版本?

【问题讨论】:

  • 您可以尝试运行“make VERBOSE=1”来查看所有构建命令,并特别检查链接器命令是否真的包含所有必需的库(在这种情况下特别是-lboost_system) .
  • 另外,如果实际链接了 lib 但此错误仍然存​​在,您可以尝试将 -DBOOST_SYSTEM_NO_DEPRECATED 添加到编译器标志(有关详细信息,请参阅此处:stackoverflow.com/a/30877725/1274747
  • @axalis 我尝试设置 -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON 但即使在检查了所有输出文件(如 cmakes 和 ninja 的输出文件)之后,我也无法找到您所说的命令 - 详细输出在哪里到?您的第二条评论让我更进一步,但我仍然遇到错误。请查看我更新的问题以获取详细信息=)我检查了该链接,但只仔细阅读了接受的答案,而另一个只是断断续续的 - 对此感到抱歉
  • 通常详细输出会发送到控制台,但我只使用过 make,而不是 ninja 后端。 “文件格式错误”似乎暗示代码和 boost 库之间存在一些不兼容......可能是它们是使用不同的平台设置(不同的 Android 架构目标或类似)构建的
  • 好吧,现在我注意到一件对我来说很奇怪的事情:我正在 x86 模拟器上进行测试,而之前为了提高插入效果,我可以很好地测试。但错误列表也包含以下消息:“C:/Users/.../toolchains/mips64el-linux-android-4.9/...”。但那是错误的文件夹,我没有为指定的架构编译 boost,所以很明显链接器命令失败了???!如何告诉 gradle 使用哪个工具链?

标签: c++ android-studio boost android-ndk cmake


【解决方案1】:

总结 cmets:

可以通过将-DBOOST_SYSTEM_NO_DEPRECATED 添加到编译器标志来解决编译错误“undefined reference to boost::system::generic_category()”(更多详细信息请参见此处:undefined reference to boost::system::system_category() when compiling)。

要将构建仅限于 x86,您可以在 cppFlags 旁边的“externalNativeBuild:cmake”部分中提供abiFilters "x86"

dlopen() 问题:

动态链接库时,它也需要在共享库搜索路径中,否则在实际运行可执行文件时可能找不到。所以 Boost 共享库路径需要放到 PATH (Windows) 或 LD_LIBRARY_PATH (Linux) (如果它不在标准位置,如 '/lib[64]' 或 '/usr/local/lib [64]')。

您也可以使用静态库来构建:

set(Boost_USE_STATIC_LIBS   ON)
find_package(Boost REQUIRED ...)

另一种选择是在安装步骤中将 Boost 库位置添加到 RPATH:

set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

(但这对于发布版本可能并不理想,因为它修复了库位置,该位置可能位于目标机器上的不同位置)

【讨论】:

  • 感谢您提供这个好的答案和许多替代方案!可悲的是,通过将 libs 路径添加到环境 PATH 变量并没有改变错误:加载库时它仍然崩溃。但是,使用静态库会导致“错误:链接器命令失败,退出代码为 1”。对此有什么想法吗?您会推荐使用 make 而不是 cmake 吗?
  • 添加到 PATH 后是否尝试重新启动计算机?从 Java 运行时,如果 JVM 已经启动,它可能在重新启动之前不会选择新的 PATH 设置。另一种选择可能是提供java -Djava.library.path=/path/to/my/dll 参数。
  • 使用静态库有点奇怪......当链接器失败时,至少应该有一些其他信息(如符号解析失败等)
  • 您的提示帮助我找出了我在答案中没有提到的事情,因为我认为这不会产生任何影响 - 对此感到抱歉。我将 Boost 包含命令从 add_subdirectory() CMakeLists.txt 文件移动到根 CMakeLists.txt 和 Boost 就像一个魅力。如果这是问题的真正原因,我目前无法进一步调查,因为我没有时间了,但我会在发现更多信息后立即发布更新。非常感谢您的帮助,非常感谢!
  • 嗯,可能是这样,因为在子 CMakeList 中设置的变量(默认情况下)仅向下传播,而不是向上传播(或兄弟姐妹)。因此,如果您在根 CMakeList.txt 中找到_package,则每个子目录 CMakeList 都会拥有它,但不是相反(您需要将 find_package(Boost) 添加到使用它的每个子目录 CMakeLists - 另一方面,允许在不同的子目录中使用不同的 Boost 库)。
猜你喜欢
  • 2012-09-21
  • 1970-01-01
  • 2017-09-30
  • 1970-01-01
  • 2017-04-12
  • 1970-01-01
  • 1970-01-01
  • 2016-10-18
  • 2017-07-15
相关资源
最近更新 更多