Android Studio 使用 Gcc 编译,如何将其更改为 G++?(使用CMake)

Ege*_*rım 0 c++ cmake android-ndk

我有一个 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函数,但即使我将enable_language(CPP)行添加到我的CMakeLists.txt中,它也会给出相同的错误。

这是我的 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})
Run Code Online (Sandbox Code Playgroud)

谢谢!

ps:我的G++和Gcc版本是9.3.0,build-essentials已经安装了。

小智 5

你的 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} )

如果您还想包含子目录中的文件,请在命令中使用GLOB_RECURSE而不是GLOBfile(GLOB srcs *.cpp *.c)

file(GLOB hdrs *.hpp *.h)据我所知,这条线完全没用。我不明白所有头文件的列表在 CMake 脚本中有何用处。


5. 使用新的基于目标的 CMake 配置。

旧版 CMake 使用基于文件的配置,现在鼓励基于目标的配置。例如,基于文件的命令是link_librariesinclude_directories,其基于目标的替代命令是target_link_librariestarget_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,您需要搜索互联网或文档来找出将每个库添加到目标所需的命令(除非您从源编译库)。尽管它几乎总是find_packagetarget_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 )
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

Ndk 使用自己的工具链,因此切勿手动将系统工具链中的路径添加到 NDK 项目中。

我不鼓励在任何其他项目上也这样做。它不可移植,类似的事情应该由 CMake 本身间接处理。