从Java到C++:CMake

从Java到C++系列目录

前言

CMake是一个开源的、跨平台的构建工具。

Android NDK(Native Development Kit)开发中,编译C/C++代码的方式,主要有两种:ndk-build、CMake。在Android源码中,你会频繁看见前者。而后者,则是Android Studio创建包含C/C++代码的项目时,默认使用的构建工具。CMake可以配合Gradle,完成整个项目的构建。

摘要

本文主要内容如下:

创建Native项目

Native项目的不同

CMake语法

代码

示例代码:Java2Cpp

创建Native项目

Android Studio可以创建包含C/C++代码的项目:

  1. 打开Studio:File->New->New Project
  1. 选择Native C++,然后一路Next即可:

如果是想在已有项目上,新增一个Native模块也可以:

File->New->New Module

Native项目的不同

Native项目与普通Android项目的差异如下:

build.gradle的不同

/module/build.gradle下,会新增配置:

android {
    defaultConfig {
        externalNativeBuild {
            cmake {
                cppFlags ''
            }
        }
    }
    externalNativeBuild {
        cmake {
            //CMake配置文件所在路径
            path file('src/main/cpp/CMakeLists.txt')
            version '3.10.2'
        }
    }
}

目录结构的不同

  1. main下,多一个cpp目录:CMakeLists.txt是CMake的配置文件。*.cpp是C++源文件。
  1. 通过Make Project编译项目后,在/module/build/intermediates/cmake/debug/obj下,会出现so文件(so文件即动态链接库,是由C/C++代码编译出来的):

CMake语法

  1. 设置CMake要求的最小版本号
cmake_minimum_required(VERSION 3.10.2)
  1. 声明项目名称
project("java2cpp")
  1. 创建并命名一个库,设置它为STATIC或者SHARED,并且提供源码文件(.cc、.cpp等)的相对路径。可以同时定义多个库。CMake会进行构建,然后Gradle会自动打包动态库进apk中。
add_library(
        # 设置库名称
        java2cpp

        # 设置库为动态库
        SHARED

        # 提供源文件的相对路径,可以设置多个源文件相对路径
        native-lib.cpp)

注意事项:

  • 库类型有两种:
    • SHARED:动态库,最终生成的库文件是*.so,如libjava2cpp.so
    • STATIC:静态库,最终生成的库文件是*.a,如libjava2cpp.a

如果是要生成静态库,需要修改一下bild.gradle的配置:

externalNativeBuild {
            cmake {
                cppFlags ''
                //增加这一行
                targets "java2cpp"
            }
        }

一般来说,我们使用动态库即可。想了解动态库、静态库相关,可参考:C++静态库与动态库

  • 源文件路径
    add_library中的native-lib.cpp不是指文件名,而是文件相对路径。相对,是相对CMakeLists.txt而言的。如果两者的目录布局如下:
main
├── cpp
│    └──native-lib.cpp
└── CMakeLists.txt

native-lib.cpp需要更改为cpp/native-lib.cpp

  • 源文件路径添加问题
    每次新增.cpp,都要在add_library里面声明该源文件的路径。操作有点繁琐。可以通过aux_source_directory或者file引用目录下的所有源文件:
file(GLOB_RECURSE UTIL_SRC util/*.cpp)
aux_source_directory(. DIR_SRC)

#使用
add_library(
        java2cpp
        SHARED
        ${DIR_SRC}
        ${UTIL_SRC})

aux_source_directory:会包括指定目录的所有源文件,但不包括子目录。

file:不仅当前目录,还会包括子目录的所有源文件。

  1. 导入C/C++头文件
include_directories(
        //相对路径
        include
)

include_directories是会递归搜索include目录下的子目录的。比如,下图的media、util目录里的头文件都会被搜索到:

include
├── media
└── util
  1. 链接其他库文件

如果你的库文件,依赖于其他库时,你需要声明相关链接的库。这些库可以是动态库,也可以是静态库。可以是第三方库,也可以是Android系统库。

  • 链接Android系统库
# 搜索一个指定的预构建的库,并且保存该库的路径为一个变量,如log-lib。
# 因为CMake的搜索路径里,默认包含了系统库的路径,所以我们只需要声明NDK库的名称,如log。
find_library(
        # 设置变量的名字
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        # 指定你想要CMake定位的NDK库的名字
        log)
        
target_link_libraries(
        # 指定目标库
        java2cpp

        # 链接log库到目标库中
        ${log-lib})
  • 链接第三方库
    在项目的libs目录下,有两个第三方库:liba.solibb.a
#设置一下编译选项,把libs目录加入到库的搜索路径中
#CMAKE_CURRENT_SOURCE_DIR是指CMakeLists.txt所在目录
#CMAKE_ANDROID_ARCH_ABI是指Android CPU的架构类型
set(CMAKE_CXX_FLAGS " -L${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI}")

target_link_libraries(
        java2cpp
        ${log-lib}

        a
        b
        )

猜你喜欢

转载自blog.csdn.net/qq_34356130/article/details/123600000