全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

详解Android studio ndk配置cmake开发native C

Android 2.2 以后的版本对NDK的支持已经非常好了。最近把一个纯C的android项目,从eclipse ADT迁移到Android studio上。本文是参考Add C and C++ Code to Your Project 官方文档(需要翻墙),经过各种尝试之后的总结。

Android studio整合NDK开发,有两种模式,一种是ndk build,一种是cmake,如果是新项目官方推荐cmake。原来,ADT的时候只能用ndk build,这次切换IDE并没有选用ndk build,而是尝试了cmake感觉上配置更加简洁方便。

本文探讨一下几点:

1. 迁移现有native C代码使用cmake,如果是新项目同理更加简单。
2. 项目是native activity就是没有java代码的纯native project。
3. 构建编译出多个so文件,并有依赖关系。
4. 使用不依赖IDE目录结构的代码目录。
5. 创建过程中的注意事项。

创建native项目,可以有两个选项。第一个是创建的时候,选择带有C++ Support功能的。


第二个是对已有工程添加c/c++功能。这里,无论是不是新项目,都推荐使用创建一个项目在添加c/c++功能,这样native code就可以独立于项目放在任意目录。创建一个没有native code工程,在根据CMakeLists.txt文件来添加NDK的支持。File -> Link C++ Project with Gradle。

这样,我们的代码就可以独立于IDE的目录结构。只要提供CMakeLists.txt文件即可。一旦我们提供了CMakeLists.txt文件,Android studio就会根据这个文件为我们在工程下面生成一个cpp文件夹用来存放CMakeLists.txt里面配置的native代码文件。

下面我们来快速的介绍一下CMakeLists.txt基本功能的写法,能够应付通常的情况。更多丰富的使用规则需要查看官方文档。CMake documentation。

# Sets the minimum version of CMake required to build the native 
# library. You should either keep the default value or only pass a 
# value of 3.4.0 or lower. 
 
cmake_minimum_required(VERSION 3.4.1) 
 
##################################################################### 
 
# 这个是设置了编译C的参数,这里使用C99并开启三级优化 
# 类似的设置还有CMAKE_CPP_FLAGS就是设置编译C++的参数 
# 更多的参数就要根据需要看文档了 
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -std=c99") 
 
##################################################################### 
 
# 这个函数是用来编译库的,主要是so文件和a文件。 
add_library( # 括号不在这一行语法错误 
  # 库的名字自定义的 
  PNG    
 
  # static 就是a文件,shared 就是so文件  
  STATIC   
 
  # 这里提供的是预编译好的文件,所以用这个imported, 
  # 否则需要提供需要编译文件的列表 
  IMPORTED  
) 
 
# 设置编译库文件的属性,有很多属性设置,根据需要查看文档 
set_target_properties( 
  # 设置哪个库的编译属性 
  PNG         
 
  # 上面的PNG库是预编译的,这里的属性表示文件所在的位置 
  PROPERTIES IMPORTED_LOCATION  
                 
  # 提供预编译文件的位置。 
  # CMAKE_SOURCE_DIR 是内置变量表示当前CMakeLists.txt的位置。 
  # 这里需要提供绝对路径所以需要这个变量, 
  # 下面会看到所有的设置都是相对于当前文件的。但这个设置需要绝对路径。 
  # ANDROID_ABI内置变量,会根据当前编译的平台分配一个文件夹名字, 
  # 比如armeabi-v7a, armeabi,x86等等 
  ${CMAKE_SOURCE_DIR}/PNG/Prebuilt/Android/${ANDROID_ABI}/libpng.a 
) 
 
##################################################################### 
 
# 表示编译文件时候,头文件的位置。路径是相对于当前文件的 
# 正确设置了这个路径,在IDE中代码头文件也会正确索引。否则会无法定位头文件。 
# 这里我们提供了代码的文件的根目录和PNG库的头文件目录 
include_directories( 
  ../../../ 
  ../../External/PNG/Include/Android/ 
) 
 
# 另外一个用法。编译so文件,自定义名字叫做NativeLib 
# 就像NDK Build的配置一样,需要把源文件列表提供,不需要头文件。 
# 这些源文件会编译成一个NativeLib.so文件。 
# 值得一提的时候,在NDK Build中,我编译一个没有源文件的so文件, 
# 以后把其他的a文件整体连接进来。这里不行,必须提供源文件至少一个。 
add_library( 
  NativeLib SHARED 
 
  ../../Toolkit/Toolkit.c 
  ../../Toolkit/Math/Math.c 
  ../../Toolkit/Math/Matrix.c 
  ../../Toolkit/Math/TweenEase.c 
  ../../Toolkit/Utils/Array.c 
  ../../Toolkit/Utils/ArrayList.c 
  ../../Toolkit/Utils/ArrayStrMap.c 
  ../../Toolkit/Utils/ArrayIntMap.c 
  ../../Toolkit/Utils/ArrayQueue.c 
  ../../Toolkit/Utils/BufferReader.c 
  ../../Toolkit/Utils/Json.c 
  ../../Toolkit/Utils/Tween.c 
  ../../Toolkit/Utils/TweenTool.c 
  ../../Toolkit/Platform/File.c 
) 
 
# 这是编译一个a文件。可见此函数可以使用任意多个,编译出多个库文件。 
add_library( 
  EntryLink STATIC 
  ../../Application/EntryLink.c 
) 
 
# 这是连接一个库文件。在库文件使用了平台,或是预编译库的接口文件,就需要在此连接。 
# 才能在运行时正确调用到这些接口函数。 
target_link_libraries( 
  # 需要连接的库名字,上面定义的任何一个库都行。 
  NativeLib 
   
  # 这里奇怪的参数,是让PNG这个库直接拷贝到NativeLib里面。 
  # 因为并不打算把PNG这个库单独载入,平台也不一定有这个库, 
  # 于是就整体复制到NativeLib.so里面 
  "-Wl,--whole-archive"   
  PNG   
  "-Wl,--no-whole-archive"   
   
  # 这个库存在的意义是 
  # 比如我在NativeLib用到了一些接口函数,希望留给另外一个库使用。 
  # 连接的时候,不提供另外一个库,或是那个库还没编译。就会连接失败找不到函数实现。 
  # 所以我们用这个库实现空的函数,用作连接。 
  # 并不会放到NativeLib.so里。真正运行的时候,有别的so库文件提供。 
  EntryLink   
 
  # 以下就是Android平台提供的库直接写名字就行了。官方文档有说明哪些。 
  android        
  EGL   
  GLESv2   
  log   
  z 
) 

那么编译出来的库文件在为什么位置呢,如下:

系统生成apk的时候,会自动安装进去。那么,有些情况,能不能自己控制库文件的输出的目录能。当然是可以的,参看NDK官方的例子,hello-libs。

add_library(gmath STATIC src/gmath.c) 
set_target_properties(gmath 
           PROPERTIES 
           # 拷贝到下面的指定目录,注意这个属性名,这是拷贝a文件的。 
           ARCHIVE_OUTPUT_DIRECTORY  
           ${CMAKE_CURRENT_SOURCE_DIR}/lib/${ANDROID_ABI}) 
 
add_library(gperf SHARED src/gperf.c) 
set_target_properties(gperf 
           PROPERTIES 
           # 拷贝到下面的指定目录,注意这个属性名,这是拷贝so文件的。 
           LIBRARY_OUTPUT_DIRECTORY  
           ${CMAKE_CURRENT_SOURCE_DIR}/lib/${ANDROID_ABI}) 

接下来的问题就是,如果我有多个不同库功能不同,源码很多不能放在一起编译。希望能够模块化管理,有两个方案。

第一个方案,给工程添加一个依赖模块,用同样的方法link一个CMakeLists.txt这样。如果这样,工程就有两个模块不同的gradle配置,就需要我们用上面的方法把作为库文件产生的so文件编译到指定目录下面,在添加预编译文件的方式进行连接。我开始是用的这个方法,可以工作但感觉并不好,NDK的例子hello-libs也是用的这个方法。后来我发现了一个跟简单的方法。

第二个方案,利用CMake的add_subdirectory函数,可以添加一个子目录,去让CMakeLists.txt再去载入另外一个CMakeLists.txt。这正是我们需要方法。类似于NDK Build里面的嵌套mk文件。

两种方案都会把多个CMakeLists.txt文件导入到Android Studio里面。

# Sets the minimum version of CMake required to build the native 
# library. You should either keep the default value or only pass a 
# value of 3.4.0 or lower. 
 
cmake_minimum_required(VERSION 3.4.1) 
 
set(CMAKE_VERBOSE_MAKEFILE ON) 
 
##################################################################### 
 
# 第一个参数表示需要加载的子目录CMakeLists.txt文件目录 
# 第二个参数表示编译这个文件内容的中间文件目录 
# 都是绝对路径,所以我们使用了内置变量,来跨平台 
add_subdirectory( 
  ${CMAKE_SOURCE_DIR}/../../../NativeLib/Build/Android/ 
  ${CMAKE_SOURCE_DIR}/../../../NativeLib/Build/Android/Bin/ 
) 
 
##################################################################### 
 
include_directories( 
  ../../../ 
) 
 
add_library( 
  Development SHARED 
 
  ../AppInit.c 
  ../Tool.c 
  ../GameMap.c 
  ../Hero.c 
  ../Enemy.c 
  ../EnemyAI.c 
  ../GameActor.c 
) 
 
##################################################################### 
 
target_link_libraries( 
  Development 
  NativeLib 
) 

如上,我们把NativeLib作为库编译,Development依赖这个库。需要注意的是,在子目录的CMakeLists.txt中内置变量CMAKE_SOURCE_DIR是父目录的值,而不是当前文件目录。另外,可以看到我们编译出了两个so文件,链接它们。这样在java中就需要载入两个so文件。其实我是想合并两个so的,但是利用"-Wl,--whole-archive"属性的时候,会发生libc.so里面很多重定义。经过google发现这个可能是NDK的一个bug并没有修复。

当然,也可以只生成一个so文件。就是让NativeLib编译为STATIC的,然后在Development target_link_libraries的时候使用"-Wl,--whole-archive"完全把NativeLib的a文件合并到Development里面就可以了。 

最后,就是一个Gradle的配置了。

apply plugin: 'com.android.application' 
 
android { 
  compileSdkVersion 23 
  buildToolsVersion '25.0.0' 
  defaultConfig { 
    applicationId 'com.test.development' 
    minSdkVersion 19 
    targetSdkVersion 23 
    versionCode 1 
    versionName '1.0' 
    ndk { 
      // 这里控制NDK编译哪些类型的ABI so文件,用来适配不同平台 
      abiFilters 'armeabi-v7a' 
    } 
    externalNativeBuild { 
      // 使用cmake,还可以使用ndk 
      cmake { 
        arguments '-DANDROID_TOOLCHAIN=clang',  
             '-DANDROID_STL=system' 
        cFlags  '-std=c99' 
      } 
    } 
  } 
  buildTypes { 
    release { 
      minifyEnabled false 
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 
    } 
  } 
  externalNativeBuild { 
    cmake { 
      // 定位文件,link的时候自动生成 
      path '../../Build/Android/CMakeLists.txt' 
    } 
  } 
} 
 
dependencies { 
  compile fileTree(include: ['*.jar'], dir: 'libs') 
} 

cmake的参数配置,arguments可以参看官方文档 Using CMake Variables,更多的gradle cmake配置在这里 Configure Build Types,需要科学上网。当然也可以自定义自己需要的参数,比如fire_base_sdk_dir用在cmake的配置中。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# Android  # studio  # ndk配置cmake 


相关文章: 长沙企业网站制作哪家好,长沙水业集团官方网站?  详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)  实现点击下箭头变上箭头来回切换的两种方法【推荐】  宝塔建站教程:一键部署配置流程与SEO优化实战指南  建站之星如何实现网站加密操作?  常州自助建站费用包含哪些项目?  网站制作软件免费下载安装,有哪些免费下载的软件网站?  如何通过建站之星自助学习解决操作问题?  文字头像制作网站推荐软件,醒图能自动配文字吗?  魔毅自助建站系统:模板定制与SEO优化一键生成指南  如何快速生成专业多端适配建站电话?  清除minerd进程的简单方法  制作农业网站的软件,比较好的农业网站推荐一下?  电脑免费海报制作网站推荐,招聘海报哪个网站多?  定制建站模板如何实现SEO优化与智能系统配置?18字教程  c++如何打印函数堆栈信息_c++ backtrace函数与符号名解析【方法】  如何实现建站之星域名转发设置?  如何通过IIS搭建网站并配置访问权限?  如何在阿里云高效完成企业建站全流程?  免费ppt制作网站,有没有值得推荐的免费PPT网站?  一键网站制作软件,义乌购一件代发流程?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  设计网站制作公司有哪些,制作网页教程?  如何快速建站并高效导出源代码?  开心动漫网站制作软件下载,十分开心动画为何停播?  制作网站的公司有哪些,做一个公司网站要多少钱?  网站制作费用多少钱,一个网站的运营,需要哪些费用?  测试制作网站有哪些,测试性取向的权威测试或者网站?  企业网站制作公司网页,推荐几家专业的天津网站制作公司?  免费制作海报的网站,哪位做平面的朋友告诉我用什么软件做海报比较好?ps还是cd还是ai这几个软件我都会些我是做网页的?  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  整蛊网站制作软件,手机不停的收到各种网站的验证码短信,是手机病毒还是人为恶搞?有这种手机病毒吗?  SAX解析器是什么,它与DOM在处理大型XML文件时有何不同?  高防网站服务器:DDoS防御与BGP线路的AI智能防护方案  保定网站制作方案定制,保定招聘的渠道有哪些?找工作的人一般都去哪里看招聘信息?  如何通过NAT技术实现内网高效建站?  大型企业网站制作流程,做网站需要注册公司吗?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  平台云上自助建站如何快速打造专业网站?  想学网站制作怎么学,建立一个网站要花费多少?  建站主机数据库如何配置才能提升网站性能?  枣阳网站制作,阳新火车站打的到仙岛湖多少钱?  Android自定义控件实现温度旋转按钮效果  如何用花生壳三步快速搭建专属网站?  建站主机默认首页配置指南:核心功能与访问路径优化  javascript中的try catch异常捕获机制用法分析  网站制作网站,深圳做网站哪家比较好?  深圳网站制作费用多少钱,读秀,深圳文献港这样的网站很多只提供网上试读,但有些人只要提供试读的文章就能全篇下载,这个是怎么弄的?  C#如何使用XPathNavigator高效查询XML  在线教育网站制作平台,山西立德教育官网? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。