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

Android Studio Compiles With Gcc, how to change that to G++ ? (Using CMake)

我有一个 Android 工作室项目,它使用带有 JNI 的本机 C++ 代码,但是当我尝试构建我的项目时,它抛出 error: undefined reference to 'std::basic_ostream<char... 错误。

我正在使用 ubuntu,我认为问题是由 IDE 使用 gcc 编译器并尝试将其编译为 C 代码引起的。当我尝试在终端中通过 运行ning 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})

谢谢!

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

你的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。它应该从 Gradle 脚本内部调用,Android Studio 用于构建整个项目。


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++ 库(我认为)中定义,需要 linked 到您的库中。默认情况下,libc++ 应该是 linked,这是正确的选择。但是有一个选项可以解决这个问题。因此,请检查您的 gradle 构建文件中是否存在 ANDROID_STL 变量,并删除对该变量的所有赋值。 NDK 中 C++ 库的问题在这里解释:https://developer.android.com/ndk/guides/cpp-support#cmake


4.缺少源文件。

当您调用 add_library 时,您只添加了一个源文件 - native-lib.cpp。所以只有这个文件会在库中编译(除了 lib_opencv 是 linked 到它)。 file(GLOB srcs *.cpp *.c) 行将所有 cpp 和 c 文件分配给 ${srcs} 变量,但该变量随后未被使用。您可以更改 add_library 以使用该变量:add_library( native-lib SHARED ${srcs} ).

如果您还想包含子目录中的文件,请在 [=14= 中使用 GLOB_RECURSE 而不是 GLOB ]命令。

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


5.使用新的 target-based CMake 配置。

旧版 CMake 使用 file-based 配置,现在鼓励使用 target-based 配置。 File-based 命令例如 link_librariesinclude_directories,它们的 target-based 替代项是 target_link_librariestarget_include_directories。你正在混合这两种风格。基本上,当一个命令有它的 target_ 变体时,你总是想使用它。

您需要先使用 add_library( native-lib SHARED ${srcs} ) 创建目标,目标名称为 native-lib。然后使用 target-based 命令向其中添加所有包含目录和 link 所有库。

此外,您添加 lib_opencv 的方式缺少 find_package 命令。使用find_package(OpenCV REQUIRED)然后target_link_libraries( native-lib PUBLIC ${OpenCV_LIBS} )到link它。

您添加日志库的方式没问题,因为 log-lib 库是本机 API (https://developer.android.com/ndk/guides/stable_apis#logging) 的一部分,所以更直接。

使用 CMake,您需要搜索 Internet 或文档以了解将每个库添加到您的目标需要哪些命令(除非您从源代码编译库)。尽管它几乎总是 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 )

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 本身间接处理。