Android Studio 使用 Gcc 编译,如何将其更改为 G++? (使用 CMake)
Posted
技术标签:
【中文标题】Android Studio 使用 Gcc 编译,如何将其更改为 G++? (使用 CMake)【英文标题】:Android Studio Compiles With Gcc, how to change that to G++ ? (Using CMake) 【发布时间】:2020-08-11 07:33:15 【问题描述】:我有一个 android Studio 项目,它使用带有 JNI 的 Native C++ 代码,但是当我尝试构建我的项目时,它会抛出 error: undefined reference to 'std::basic_ostream<char...
错误。
我正在使用 ubuntu,我认为问题是由 IDE 使用 gcc 编译器引起的,并尝试将其编译为 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)
谢谢!
ps:我的 G++ 和 Gcc 版本是 9.3.0,已经安装了 build-essentials。
【问题讨论】:
您是否考虑过使用其他一些构建自动化工具(例如 GNU make 或 ninja...)。当然,请阅读GCC 之前的文档......以及您的build automation 工具。 GCC 和 G++ 的选择取决于文件类型扩展名。我注意到,您添加了*.c
。因此将采用 GCC。否则,您需要使用-lstdc++
指定链接到标准库。有关该主题的更多信息,请访问:***.com/questions/172587/…
这个 CMakeLists.txt 文件有一些主要用途:当您为 Android 进行交叉编译时,您绝对应该不告诉它查看您的系统头文件( include_directories 行)。您还使用了几个未定义的变量。最后,您使用 GLOB 运算符来构造 $srcs 和 $hdrs,但您从不使用这些变量!您应该展示您的目录树并告诉我们组件是什么以及它们如何组合在一起。
【参考方案1】:
您的 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 自己间接处理。
【讨论】:
非常感谢您提供非常详细的回答,这对我帮助很大。第 7 步修复了错误,但现在找不到 tesseract 标头 :) 至少现在我知道这都是关于 CMake 的,继续下一步。以上是关于Android Studio 使用 Gcc 编译,如何将其更改为 G++? (使用 CMake)的主要内容,如果未能解决你的问题,请参考以下文章
GCC-Visual Studio std::thread 编译器差异
单击问题窗口时,在Visual Studio代码上找不到文件错误(使用make,gcc和gcc problemMatcher)
C++ 与 gcc 和 Visual Studio 不同的编译错误,“在此上下文中”