JNI/NDK开发指进阶(四) JNI/NDK 调试工具 LLDB, CMake

今天不是来讲lldb ,因为用的是android studio 3.0,只能用CMake 才能调试(3.0 以下可以配合 gradle-experimental,不过也要有改动,这里不再细说),所以需要把原来的 Android.mk 转成CMake,

前提,自己去下载 lldb,cmake,ndk,这个在sdk 管理中,见下图:

这里主要讲一下,怎么手机编写CMakeList.txt

 

只要在Android中有使用过jni的应该都了解我们要编译写的c/c++文件都需要配置编译用的配置文件,在eclipse中要写mk文件;在Android Studio中要写CMakeList.txt这个配置文件。
只有写好了这个配置文件我们才正确编译出我们想要的so动态库,今天就讲讲Android Studio中的CMakeList.txt这个文件怎么写,eclispe的mk文件的写法在这就不讲了,如果不了解的可以到ndk安装路径中打中doc文档中查看Android.mk的写法,文档中详细的介绍


要了解CMakeList这个东西,那就应该要知道CMake干嘛用的,CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程)。他能够输出各种各样的makefile或者project文件,能测试编译器所支持的C++特性,类似UNIX下的automake。
太详细的用法在此就不讲了,下我会以ffmpeg的配置,来讲解在Android Studio中CMakeList.txt的常用写法。
在此附上CMake官方学习文档:
英文文档:https://cmake.org/documentation/
中文文档:https://www.zybuluo.com/khan-lau/note/254724

在CMakeList.txt开头时应该设置好我们的jni文件夹目录,这样才能让gcc在编译时找到对应的文件,具体的写法如下:

set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)

反斜线的后面是固定的格式,前面的你的jni文件夹所在的路径;后面的写法一般不建议修改。
写好这个后,如里我们有需要引入的第三方头文件,在这时应该要配置头文件的路径,具体的写法如下:

include_directories(src/main/jniLibs/include/ffmpeg)

如里有多个, 也是一样的依次往一加上就可以了,如里有要引用第三方编译好的.so库,在这时应该要配置进来编译;引入第三方的.so库具体写法如下:

add_library(
    avcodec-lib
    SHARED
    IMPORTED)
set_target_properties( avcodec-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavcodec-56.so)

首先要添加库,也就是:add_library函数,里面要传入三个参数;第一个是要引入的库别名,第二个是库的类型,是静态库还是动态库。在Android中是不能引用静态库的也就是.dll后缀的库,所以第二个参数只要是引入第三方的.so库都是写“SHARED”,第三个是通过什么样方式引入进来,第三方的一般都是通过包含进来,所以第三个参数基本也是固定的都是写“IMPORTED”。
add_library后,就要设置.so的详细路径了,通过set_target_properties()函数来设置;该函数也是要传入三参数来指定.so库的路径。第一个参数和add_library的第一个参数一样,不过这里的库别名要和add_library的库别名要一致,要不然在编译时会报找不到库的错误。第二个参数是固定的,都是写“ PROPERTIES IMPORTED_LOCATION”主要用来指定库的引入方式。都是通过本地引入。第三个就是库的具体路径,这个不能写错,如果写错了,编译时也同样会找不到库的。只要是引入第三方的库使用add_library就要使用set_target_propeties这个组合,所以它们是成对出现的。
add_library还有一种写法那就是CMakeList.txt中默认写法

add_library( # Sets the name of the library.
             playController

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/playController.c)

这样是就是编译我们自己在项目中写的c/c++文件。这里就不用set_target_propeties()。
下面就到find_library()了;看到这个名字相信都会知道它是干嘛用的,查找库用的,用在哪里呢,这个主要是查找系统库用的,如果项目里面有用到系统的.so库就是要把库名写到这个函数里面去找到相对应的为。


find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

比如上面用了日志库,那就要把日志库加进来。
最后一个函数target_link_libraries()这个是函数是干嘛用的呢,讲到这个函数就要讲到c/c++的编译原理了,在linux中c/c++的编译一般都是用gcc来编译的,c/c++编译时会产生.o文件要通过make工具来把这些.o文件链接起来,这样才能得一个可执行程序。所以.so在编译时要把所有库链接起来才能编译。target_link_libraries()就是干这个事的。

target_link_libraries( # Specifies the target library.
                       playController
                       avcodec-lib
                       avdevice-lib
                       avfilter-lib
                       avformat-lib
                       avutil-lib
                       postproc-lib
                       swresample-lib
                       swscale-lib
                       yuv-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

把要链接的库别名都写到这里就可以了,如果是系统的库要用这个格式${库的名字}。
好了,CMakeList.txt的基本写法就讲到这里,如里有发现写错了,小伙伴可以留言给我,及时改正大家一起进步。
最后附上ffmpeg的CMakeList.txt全部写法

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)

add_library(
    avcodec-lib
    SHARED
    IMPORTED)
set_target_properties( avcodec-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavcodec-56.so)

add_library( avdevice-lib
             SHARED
             IMPORTED)

set_target_properties( avdevice-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavdevice-56.so)

add_library(
            avfilter-lib
            SHARED
            IMPORTED)
set_target_properties( avfilter-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libavfilter-5.so)

add_library(
            avformat-lib
            SHARED
            IMPORTED)

set_target_properties( avformat-lib
                       PROPERTIES IMPORTED_LOCATION
                       ${distribution_DIR}/${ANDROID_ABI}/libavformat-56.so)
add_library(
            avutil-lib
            SHARED
            IMPORTED)
set_target_properties(
                      avutil-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libavutil-54.so)
add_library(
             postproc-lib
             SHARED
             IMPORTED)
set_target_properties(
                      postproc-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libpostproc-53.so)
add_library(
            swresample-lib
            SHARED
            IMPORTED)
set_target_properties(
                      swresample-lib
                      PROPERTIES IMPORTED_LOCATION
                      ${distribution_DIR}/${ANDROID_ABI}/libswresample-1.so)
add_library(
            swscale-lib
            SHARED
            IMPORTED)

set_target_properties(
            swscale-lib
            PROPERTIES IMPORTED_LOCATION
            ${distribution_DIR}/${ANDROID_ABI}/libswcale-3.so)


add_library(
            yuv-lib
            SHARED
            IMPORTED)
set_target_properties(
             yuv-lib
             PROPERTIES IMPORTED_LOCATION
             ${distribution_DIR}/${ANDROID_ABI}/libyvu.so)
#支持-std=gnu++11
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

#判断编译器类型,如果是gcc编译器,则在编译选项中加入c++11支持
if(CMAKE_COMPILER_IS_GNUCXX)
    set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
    message(STATUS "optional:-std=c++11")
endif(CMAKE_COMPILER_IS_GNUCXX)







# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             playController

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/playController.c)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
include_directories(src/main/jniLibs/include/ffmpeg)
include_directories(src/main/jniLibs/include/libyuv)
target_link_libraries( # Specifies the target library.
                       playController
                       avcodec-lib
                       avdevice-lib
                       avfilter-lib
                       avformat-lib
                       avutil-lib
                       postproc-lib
                       swresample-lib
                       swscale-lib
                       yuv-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

猜你喜欢

转载自blog.csdn.net/q610098308/article/details/80565941