问题描述
我有一个Android Studio项目,该项目使用带有JNI的Native C ++代码,但是当我尝试构建我的项目时,它会抛出error: undefined reference to 'std::basic_ostream<char...
错误。
我正在使用ubuntu,我相信问题是由使用gcc编译器的IDE引起的,并尝试将其编译为C代码。当我尝试通过在终端中运行gcc -o foo foo.cpp
来运行简单的hello world程序时,它给出了相同的错误。当我将gcc更改为g ++时,一切正常。
但是如何在IDE中更改编译器?我对使用CMake有点陌生,我认为我需要使用cmake的enable_language函数,但是即使我在我的CMakeLists.txt文件中添加enable_language(CPP)行,也会出现相同的错误。
这是我的CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
include_directories("/usr/include/x86_64-linux-gnu/c++/9")
include_directories("/usr/include/c++/9")
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("/usr/include")
file(GLOB srcs *.cpp *.c)
file(GLOB hdrs *.hpp *.h)
include_directories(${OpenCV_DIR}/jni/include)
include_directories(${TESSERACT_INCLUDE_DIRS})
include_directories(${LEPTONICA_INCLUDE_DIRS})
add_library( lib_opencv SHARED IMPORTED )
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${OpenCV_DIR}/libs/${ANDROID_ABI}/libopencv_java4.so)
add_library(
native-lib
SHARED
#
native-lib.cpp )
find_library(
log-lib
log )
target_link_libraries(
native-lib
lib_opencv
${log-lib}
${TESSERACT_LIBRARIES}
${LEPTONICA_LIBRARIES})
谢谢!
ps:我的G ++和Gcc版本是9.3.0,已经安装了构建必备软件。
解决方法
您的CMakeLists.txt非常混乱。让我们一个接一个地解决一些潜在的问题,看看它是否开始起作用。
解决方案可能在第7点,但是我已经写了所有内容,因此我将其留在这里。让我知道我的回答是否对您有帮助。
1。 Android Studio是否真的使用此CMakeLists.txt文件进行构建?
NDK有两种常用的构建系统-较旧的ndk-build和较新的CMake。检查您的Gradle构建文件,以查看此CMakeLists.txt是否真正被使用。以下是有关其工作方式的文档:https://developer.android.com/studio/projects/gradle-external-native-builds。
当然,您可以在CMakeLists.txt文件中故意犯下语法错误,以查看构建系统是否开始抱怨它。
并且请注意,在为Android构建时,不应单独调用CMake。应该从Android Studio用于构建整个项目的Gradle脚本中调用它。
2。所有使用C ++库的源文件都具有.cpp扩展名吗?
CMake根据文件的扩展名确定使用哪种编译器(C或C ++)。如果它是.c文件,则使用C编译器。如果是.cpp文件,则使用C ++编译器。
还要注意,Android NDK现在使用Clang(来自LLVM项目)而不是GCC,因此GCC版本或自定义GCC调用可能无关紧要。
您还可以使CMake变得冗长-打印所有构建命令,以查看正确执行了哪些命令。将set(CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON")
添加到您的CMakeLists.txt文件中,使其变得冗长。
3。是否使用了正确的C ++库?
您缺少的符号(来自std :: basic_ostream的符号)在C ++库(我认为)中定义,需要链接到您的库。默认情况下,应该链接libc ++,这是正确的选择。但是有一个选项可以解决这个问题。因此,请在gradle构建文件中检查ANDROID_STL
变量,并删除对该变量的所有分配。 NDK中的C ++库问题在这里说明:https://developer.android.com/ndk/guides/cpp-support#cmake
4。缺少源文件。
调用add_library时,您仅添加一个源文件- native-lib.cpp 。因此,只有一个文件会在库中编译(链接到的lib_opencv除外)。第file(GLOB srcs *.cpp *.c)
行将所有cpp和c文件分配给 $ {srcs} 变量,但是该变量未被使用。您可以将 add_library 更改为使用该变量:add_library( native-lib SHARED ${srcs} )
。
如果您还希望包含子目录中的文件,请在file(GLOB srcs *.cpp *.c)
命令中使用 GLOB_RECURSE 代替 GLOB 。
据我所知,file(GLOB hdrs *.hpp *.h)
行是完全没有用的。我看不到所有头文件的列表在CMake脚本中如何有用。
5。使用新的基于目标的CMake配置。
较旧的CMake使用基于文件的配置,现在鼓励基于目标的配置。基于文件的命令例如是 link_libraries 和 include_directories ,它们基于目标的替代方法是 target_link_libraries 和 target_include_directories 。您正在混合这两种样式。基本上,当命令具有其 target _ 变体时,您总是想使用它。
您首先需要使用add_library( native-lib SHARED ${srcs} )
创建目标,目标名称为 native-lib 。然后添加所有包含目录,并使用基于目标的命令将所有库链接到该目录。
添加lib_opencv的方式也缺少 find_package 命令。使用find_package(OpenCV REQUIRED)
,然后使用target_link_libraries( native-lib PUBLIC ${OpenCV_LIBS} )
进行链接。
添加日志记录库的方式是可以的,因为log-lib库是本机API(https://developer.android.com/ndk/guides/stable_apis#logging)的一部分,因此更简单。
使用CMake时,您需要搜索Internet或文档以找出将每个库添加到目标所需的命令(除非您从源代码编译库)。尽管几乎总是 find_package 和 target_link_libraries 的某种组合。
6。缺少项目信息。 我不确定这有多重要,但是通常您会使用以下内容启动主CMakeLists.txt:
cmake_minimum_required( VERSION 3.4.1 )
project( my_special_project )
set( CMAKE_CXX_STANDARD 14 )
set( CMAKE_CXX_STANDARD_REQUIRED True )
7。不要手动添加系统目录。
考虑一下,这可能是问题所在。扔掉所有这些行:
include_directories("/usr/include/x86_64-linux-gnu/c++/9")
include_directories("/usr/include/c++/9")
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("/usr/include")
Ndk使用自己的工具链,因此切勿手动将路径从系统工具链添加到NDK项目。
我不鼓励在其他任何项目上也这样做。它不是可移植的,类似的事情应该由CMake自己间接解决。