android开发,怎么使用ndk编译成.so文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android开发,怎么使用ndk编译成.so文件相关的知识,希望对你有一定的参考价值。

一、首先下载android-ndk,官方网站是:http://developer.android.com/tools/sdk/ndk/index.html
目前最新的版本是android-ndk-r8e-windows-x86.zip,下载地址:
http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip
下载后把压缩包解压出来,例如:D:\ndk,目录下的ndk-build.cmd就是用来编译的批处理命令。
二、编译,打开cmd命令行窗口,cd进入目录:D:\ndk\samples\hello-jni,
然后执行命令:D:\ndk\ndk-build.cmd(如果设置过环境变量则直接使用ndk-build.cmd)来编译hello-jni,如果没有错误会输出:
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
"Compile thumb : hello-jni <= hello-jni.c
SharedLibrary : libhello-jni.so
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
三、创建android应用程序并使用so文件
打开eclipse创建一个android应用程序HelloJni,默认的com.example.hellojni包下面有一个MainActivity.java,
在此包下添加一个HelloJni.java,
参考技术A 使用在jni目录下使用ndk-build 命令就OK了 参考技术B

请问楼主编译出.so了吗,我报这个错

如何把ndk编译出来的可执行文件伪装成so打包到apk中

ndk编译出来的共享库,eclipse会自动打包到apk中,而编译出来的可执行文件则不会。 要想可执行文件自动被打包到apk中,可以把文件名改成libxxx.so的形式,伪装成so,这样就会被打包进apk。 但是每次编译之后都改一下名字,太麻烦, 写个脚本吧,又有arm, arm

ndk编译出来的共享库,eclipse会自动打包到apk中,而编译出来的可执行文件则不会。
要想可执行文件自动被打包到apk中,可以把文件名改成libxxx.so的形式,伪装成so,这样就会被打包进apk。
但是每次编译之后都改一下名字,太麻烦,
写个脚本吧,又有arm, armv7, x86的麻烦事,
想试着改LOCAL_MODULE_FILENAME来试试,NDK又不允许。
于是稍微看了下NDK的编译脚本,发现如下解决办法。
NDK是通过在Android.mk文件中include $(BUILD_EXECUTABLE)来编译可执行文件,其实就是调用了一个已经写好的脚本——build-executable.mk。(编译脚本都在NDK_ROOT/build/core目录里面)
仔细看脚本的调用过程可以发现,脚本一开始先检查一下变量合法性(前面改LOCAL_MODULE_FILENAME的方法在这里过不去),最终调用include$(BUILD_SYSTEM)/build-module.mk来编译。
于是研究这个脚本,找到决定编译输出的变量,在调用最终的编译脚本之前改成想要的就可以了。
最终我的方案如下:
1. 为了不破坏ndk本来的脚本,将build-executable.mk拷贝一份放在自己的工程目录下面,在倒数第三行插入一句?$(evalLOCAL_BUILT_MODULE := $(TARGET_OUT)/$(MY_LOCAL_MODULE_FILENAME))
2. 在自己的Android.mk文件中定义MY_LOCAL_MODULE_FILENAME变量,当然值就是你想要的文件名啦
3. 编译时不调用系统的include$(BUILD_EXECUTABLE), 而改调用自己的脚本(就是上面拷贝出来且做了修改的那个脚本),为了方便,你可以给自己的脚本定义一个变量来指向它。
就是这样。
写得比较乱,贴几段关键代码吧。
修改后的build-executable.mk代码。
LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
LOCAL_MAKEFILE := $(local-makefile)
$(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
$(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
$(call check-LOCAL_MODULE_FILENAME)
# we are building target objects
my := TARGET_
$(call handle-module-filename,,)
$(call handle-module-built)
$(eval LOCAL_BUILT_MODULE := $(TARGET_OUT)/$(MY_LOCAL_MODULE_FILENAME))
LOCAL_MODULE_CLASS := EXECUTABLE
include $(BUILD_SYSTEM)/build-module.mk
14行就是我们加的那一行。
上面的文件放在jni根目录,跟目录下的Android.mk代码:
MY_BUILD_EXECUTABLE := $(JNI_ROOT)/build-executable.mk
include $(call all-subdir-makefiles)
需要编译可执行文件的模块这样写:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := ...
LOCAL_MODULE := xxx
MY_LOCAL_MODULE_FILENAME := libxxx.so
LOCAL_C_INCLUDES := ...
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
LOCAL_CFLAGS := -fPIC
include $(MY_BUILD_EXECUTABLE)。
参考技术A   ndk编译出来的共享库,eclipse会自动打包到apk中,而编译出来的可执行文件则不会。 要想可执行文件自动被打包到apk中,可以把文件名改成libxxx.so的形式,伪装成so,这样就会被打包进apk。 但是每次编译之后都改一下名字,太麻烦! 写个脚本吧,又有arm, arm

  ndk编译出来的共享库,eclipse会自动打包到apk中,而编译出来的可执行文件则不会。
  要想可执行文件自动被打包到apk中,可以把文件名改成libxxx.so的形式,伪装成so,这样就会被打包进apk。
  但是每次编译之后都改一下名字,太麻烦!
  写个脚本吧,又有arm, armv7, x86的麻烦事!
  想试着改LOCAL_MODULE_FILENAME来试试,NDK又不允许。
  于是稍微看了下NDK的编译脚本,发现如下解决办法。
  NDK是通过在Android.mk文件中include $(BUILD_EXECUTABLE)来编译可执行文件,其实就是调用了一个已经写好的脚本——build-executable.mk。(编译脚本都在NDK_ROOT/build/core目录里面)
  仔细看脚本的调用过程可以发现,脚本一开始先检查一下变量合法性(前面改LOCAL_MODULE_FILENAME的方法在这里过不去),最终调用include$(BUILD_SYSTEM)/build-module.mk来编译。
  于是研究这个脚本,找到决定编译输出的变量,在调用最终的编译脚本之前改成想要的就可以了。
  最终我的方案如下:
  1. 为了不破坏ndk本来的脚本,将build-executable.mk拷贝一份放在自己的工程目录下面,在倒数第三行插入一句?$(evalLOCAL_BUILT_MODULE := $(TARGET_OUT)/$(MY_LOCAL_MODULE_FILENAME))
  2. 在自己的Android.mk文件中定义MY_LOCAL_MODULE_FILENAME变量,当然值就是你想要的文件名啦
  3. 编译时不调用系统的include$(BUILD_EXECUTABLE), 而改调用自己的脚本(就是上面拷贝出来且做了修改的那个脚本),为了方便,你可以给自己的脚本定义一个变量来指向它。
  就是这样。
  写得比较乱,贴几段关键代码吧。
  修改后的build-executable.mk代码。
  LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
  LOCAL_MAKEFILE := $(local-makefile)
  $(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
  $(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
  $(call check-LOCAL_MODULE_FILENAME)
  # we are building target objects
  my := TARGET_
  $(call handle-module-filename,,)
  $(call handle-module-built)
  $(eval LOCAL_BUILT_MODULE := $(TARGET_OUT)/$(MY_LOCAL_MODULE_FILENAME))
  LOCAL_MODULE_CLASS := EXECUTABLE
  include $(BUILD_SYSTEM)/build-module.mk
  14行就是我们加的那一行。
  上面的文件放在jni根目录,跟目录下的Android.mk代码:
  MY_BUILD_EXECUTABLE := $(JNI_ROOT)/build-executable.mk
  include $(call all-subdir-makefiles)
  需要编译可执行文件的模块这样写:
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_SRC_FILES := ...
  LOCAL_MODULE := xxx
  MY_LOCAL_MODULE_FILENAME := libxxx.so
  LOCAL_C_INCLUDES := ...
  LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
  LOCAL_CFLAGS := -fPIC
  include $(MY_BUILD_EXECUTABLE)
  OK, 大功告成!
  转载本回答被提问者和网友采纳

以上是关于android开发,怎么使用ndk编译成.so文件的主要内容,如果未能解决你的问题,请参考以下文章

Android NDk环境配置

如何用Android NDK编译FFmpeg

ubuntu如何利用ndk-build生成.so文件?在终端输入显示没有那个文件或目录怎么办!!!

Linux下NDK编译出的SO库能在WIndows下的android工程直接使用么

eclipse里配置Android ndk环境,用eclipse编译.so文件

android JNI开发