android編譯armv8
㈠ 新人求教,編譯一個最簡單的Android程序,提示下面的錯誤咋解決
未說明具體問題,以下未說明具體問題,以下供你參考
1、32位系統下的編譯
如果需要在32位系統中編譯android系統,在編譯前需要對部分makefile進行修改
首先修改build/core/main.mk,修改的內容如下所示:
-ifneq (64,$(findstring 64,$(build_arch)))
+ifneq
(i686,$(findstring i686,$(build_arch)))
$(warning
************************************************************) $(warning You are attempting to build on a 32-bit system.)
$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
其次修改如下四個文件:
external/clearsilver/cgi/Android.mk
external/clearsilver/java-jni/Android.mk
external/clearsilver/util/Android.mk
external/clearsilver/cs/Android.mk # This forces a 64-bit build for Java6
-LOCAL_CFLAGS += -m64
-LOCAL_LDFLAGS += -m64
+LOCAL_CFLAGS += -m32
+LOCAL_LDFLAGS += -m32即將LOCAL_CFLAGS和LOCAL_LDFLAGS由-m64改為-m32,從而指定使用32位系統進行編譯如果使用 64bit 的操作系統編譯,這些就都不用修改,但記得需要安裝:For 64-bit servers the following extra packages may be needed:
"sudo apt-get install libc6-dev-i386" (libc6-dev-amd64 if AMD CPU)
"sudo apt-get install g++-multilib lib32ncurses5-dev lib32z1-dev"
還有 jdk64bit 的版本編譯2 、build/core/base_rules.mk:128:*** frameworks/opt/emoji/jni:
.... libgl2jni already defined by framwworks/base/opengl/tests/gl2_jni/jni 停止
從編譯規則上看:
# Make sure that this IS_HOST/CLASS/MODULE combination is unique.
mole_id := MODULE.$(if \
$(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
ifdef $(mole_id)
$(error $(LOCAL_PATH): $(mole_id) already defined by $($(mole_id)))
endif
在framwworks/base/opengl/tests/gl2_jni/下面定義的android.mk定義了:
LOCAL_MODULE := libgl2jni
include $(BUILD_SHARED_LIBRARY)
導致生成的動態庫重復,這是不對的,修改tests這個目錄不參與編譯即可,最直接的辦法刪除掉framwworks/base/opengl/tests/gl2_jni這個文件夾
3、AIDL 編譯報couldn't find import for class原因
「AIDL服務只支持有限的數據類型,因此,如果用AIDL服 務傳遞一些復雜的數據就需要做更一步處理。AIDL服務支持的數據類型如下:
Java的簡單類 型(int、char、boolean等)。不需要導入(import)。String和 CharSequence。不需要導入(import)。
List和 Map。但要注意,List和Map對象的元素類型必須是AIDL服務支持的數據類型。不需要導入(import)。AIDL自動生成 的介面。需要導入(import)。
實現 android.os.Parcelable介面的類。需要導入(import)。
其中後兩種數據類 型需要使用import進行導入,傳遞不需要 import的數據類型的值的方式相同。傳遞一個需要import的數據類型的值(例如,實現android.os.Parcelable 介面的類)的步 驟略顯復雜。除了要建立一個實現android.os.Parcelable介面的類外,還需要為這個類單獨建立一個aidl文件,並使用parcelable關鍵字進行定義。」
沒有加LOCAL_AIDL_INCLUDES += xxx ,所以找不到我的parcelable aidl文件。
修改android源碼根目錄下的build/core/pathmap.mk把你的目錄加進去,此時再make update-api
4、老是提示 @Override錯誤 方法未覆蓋其父類的方法
使 用JDK1.6編譯沒有問題,使用JDK1.5編譯,會報@Override方法未覆蓋其父類的方法。實際上這個方法是類實現的介面中方法,
但是,這個語 法的jdk1.6的下面是可以通過的,也就是說jdk1.6認為類覆蓋父類方法與實現介面方法都叫override,而jdk1.5不
是這樣認為的,不知 道這是當初jdk1.5的bug,還是當初就是認為覆蓋父類方法與實現介面方法是不一樣的,不得而知。但是從
OO角度來看,覆蓋父類方法與實現介面方法都 可以認為override,因為他們目的都是一樣的,都是為了重用,都是多態的一種
表現方式。
更改jdk版本為1.6即可
5、編譯alsa-lib庫錯誤
android系統開發移植alsa-lib庫的過程中編譯的時候出現了如下的錯誤
/tmp/cckyaR40.s: Assembler messages:
/tmp/cckyaR40.s:2763: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:2764: Error: unshifted register required -- `orr r2,ip,#128'
/tmp/cckyaR40.s:2765: Error: selected processor does not support `msr cpsr_c,r2
字面的意思報的是匯編錯誤,選擇的處理器不支持mrs和msr指令。
原來的ARM指令有32位和16位兩種指令模式,16位為thumb指令集,thumb指令集編譯出的代碼佔用空間小,
而且效率也高,所以android的arm編譯器默認用的是thumb模式編譯,問題在於alsa的代碼中有部分的內容
用到了32位的指令,所以才會報如下的錯誤,修改的方法也很簡單,在Android.mk中加入如下內容即可:
LOCAL_ARM_MODE := arm
android的編譯系統中LOCAL_ARM_MODE變數的取值為arm或者thumb,代表32位和16位兩種arm指令集,默認為thumb
prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: failed to set dynamic section sizes: Bad value
collect2: ld returned 1 exit status
make: *** [out/target/proct/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so] 錯誤 1
解決此問題將alsa-lib/include/config.h文件中的如下宏定義去掉即可:
#define VERSIONED_SYMBOLS
開發過程中碰到過很多錯誤,後續再一一總結記錄下來,有些忘記了。。
在android.mk中編譯:
include $(CLEAR_VARS)
$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
出現提示需要定義:LOCAL_MODULE_TAGS := optional 一般修改方法是:
build\core\definitions.mk 中的宏定義變數:
define include-prebuilt
include $$(CLEAR_VARS)
LOCAL_SRC_FILES := $(1)
LOCAL_BUILT_MODULE_STEM := $(1)
LOCAL_MODULE_SUFFIX := $$(suffix $(1))
LOCAL_MODULE := $$(basename $(1))
LOCAL_MODULE_CLASS := $(2)
include $$(BUILD_PREBUILT)
endef
在這里增加一個LOCAL_MODULE_TAGS := optional
但是這需要修改android源碼,如果不是自已的android系統,這么做就麻煩了,所以必須想其它辦法解決:
#include $(CLEAR_VARS)
#$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libyfcdca.a
LOCAL_BUILT_MODULE_STEM := libyfcdca.a
LOCAL_MODULE_SUFFIX := lib
LOCAL_MODULE := yfcdca
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
如此即可了。供你參考
1、32位系統下的編譯
如果需要在32位系統中編譯android系統,在編譯前需要對部分makefile進行修改
首先修改build/core/main.mk,修改的內容如下所示:
-ifneq (64,$(findstring 64,$(build_arch)))
+ifneq
(i686,$(findstring i686,$(build_arch)))
$(warning
************************************************************) $(warning You are attempting to build on a 32-bit system.)
$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
其次修改如下四個文件:
external/clearsilver/cgi/Android.mk
external/clearsilver/java-jni/Android.mk
external/clearsilver/util/Android.mk
external/clearsilver/cs/Android.mk # This forces a 64-bit build for Java6
-LOCAL_CFLAGS += -m64
-LOCAL_LDFLAGS += -m64
+LOCAL_CFLAGS += -m32
+LOCAL_LDFLAGS += -m32即將LOCAL_CFLAGS和LOCAL_LDFLAGS由-m64改為-m32,從而指定使用32位系統進行編譯如果使用 64bit 的操作系統編譯,這些就都不用修改,但記得需要安裝:For 64-bit servers the following extra packages may be needed:
"sudo apt-get install libc6-dev-i386" (libc6-dev-amd64 if AMD CPU)
"sudo apt-get install g++-multilib lib32ncurses5-dev lib32z1-dev"
還有 jdk64bit 的版本編譯2 、build/core/base_rules.mk:128:*** frameworks/opt/emoji/jni:
.... libgl2jni already defined by framwworks/base/opengl/tests/gl2_jni/jni 停止
從編譯規則上看:
# Make sure that this IS_HOST/CLASS/MODULE combination is unique.
mole_id := MODULE.$(if \
$(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
ifdef $(mole_id)
$(error $(LOCAL_PATH): $(mole_id) already defined by $($(mole_id)))
endif
在framwworks/base/opengl/tests/gl2_jni/下面定義的android.mk定義了:
LOCAL_MODULE := libgl2jni
include $(BUILD_SHARED_LIBRARY)
導致生成的動態庫重復,這是不對的,修改tests這個目錄不參與編譯即可,最直接的辦法刪除掉framwworks/base/opengl/tests/gl2_jni這個文件夾
3、AIDL 編譯報couldn't find import for class原因
「AIDL服務只支持有限的數據類型,因此,如果用AIDL服 務傳遞一些復雜的數據就需要做更一步處理。AIDL服務支持的數據類型如下:
Java的簡單類 型(int、char、boolean等)。不需要導入(import)。String和 CharSequence。不需要導入(import)。
List和 Map。但要注意,List和Map對象的元素類型必須是AIDL服務支持的數據類型。不需要導入(import)。AIDL自動生成 的介面。需要導入(import)。
實現 android.os.Parcelable介面的類。需要導入(import)。
其中後兩種數據類 型需要使用import進行導入,傳遞不需要 import的數據類型的值的方式相同。傳遞一個需要import的數據類型的值(例如,實現android.os.Parcelable 介面的類)的步 驟略顯復雜。除了要建立一個實現android.os.Parcelable介面的類外,還需要為這個類單獨建立一個aidl文件,並使用parcelable關鍵字進行定義。」
沒有加LOCAL_AIDL_INCLUDES += xxx ,所以找不到我的parcelable aidl文件。
修改android源碼根目錄下的build/core/pathmap.mk把你的目錄加進去,此時再make update-api
4、老是提示 @Override錯誤 方法未覆蓋其父類的方法
使 用JDK1.6編譯沒有問題,使用JDK1.5編譯,會報@Override方法未覆蓋其父類的方法。實際上這個方法是類實現的介面中方法,
但是,這個語 法的jdk1.6的下面是可以通過的,也就是說jdk1.6認為類覆蓋父類方法與實現介面方法都叫override,而jdk1.5不
是這樣認為的,不知 道這是當初jdk1.5的bug,還是當初就是認為覆蓋父類方法與實現介面方法是不一樣的,不得而知。但是從
OO角度來看,覆蓋父類方法與實現介面方法都 可以認為override,因為他們目的都是一樣的,都是為了重用,都是多態的一種
表現方式。
更改jdk版本為1.6即可
5、編譯alsa-lib庫錯誤
android系統開發移植alsa-lib庫的過程中編譯的時候出現了如下的錯誤
/tmp/cckyaR40.s: Assembler messages:
/tmp/cckyaR40.s:2763: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:2764: Error: unshifted register required -- `orr r2,ip,#128'
/tmp/cckyaR40.s:2765: Error: selected processor does not support `msr cpsr_c,r2
字面的意思報的是匯編錯誤,選擇的處理器不支持mrs和msr指令。
原來的ARM指令有32位和16位兩種指令模式,16位為thumb指令集,thumb指令集編譯出的代碼佔用空間小,
而且效率也高,所以android的arm編譯器默認用的是thumb模式編譯,問題在於alsa的代碼中有部分的內容
用到了32位的指令,所以才會報如下的錯誤,修改的方法也很簡單,在Android.mk中加入如下內容即可:
LOCAL_ARM_MODE := arm
android的編譯系統中LOCAL_ARM_MODE變數的取值為arm或者thumb,代表32位和16位兩種arm指令集,默認為thumb
prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: failed to set dynamic section sizes: Bad value
collect2: ld returned 1 exit status
make: *** [out/target/proct/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so] 錯誤 1
解決此問題將alsa-lib/include/config.h文件中的如下宏定義去掉即可:
#define VERSIONED_SYMBOLS
開發過程中碰到過很多錯誤,後續再一一總結記錄下來,有些忘記了。。
在android.mk中編譯:
include $(CLEAR_VARS)
$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
出現提示需要定義:LOCAL_MODULE_TAGS := optional 一般修改方法是:
build\core\definitions.mk 中的宏定義變數:
define include-prebuilt
include $$(CLEAR_VARS)
LOCAL_SRC_FILES := $(1)
LOCAL_BUILT_MODULE_STEM := $(1)
LOCAL_MODULE_SUFFIX := $$(suffix $(1))
LOCAL_MODULE := $$(basename $(1))
LOCAL_MODULE_CLASS := $(2)
include $$(BUILD_PREBUILT)
endef
在這里增加一個LOCAL_MODULE_TAGS := optional
但是這需要修改android源碼,如果不是自已的android系統,這么做就麻煩了,所以必須想其它辦法解決:
#include $(CLEAR_VARS)
#$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libyfcdca.a
LOCAL_BUILT_MODULE_STEM := libyfcdca.a
LOCAL_MODULE_SUFFIX := lib
LOCAL_MODULE := yfcdca
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
如此即可了。
㈡ android jni程序(c++)如何編譯適用於arm-v8指令集的32位程序
可以看到Android上層的Application和ApplicationFramework都是使用Java編寫,
底層包括系統和使用眾多的LIiraries都是C/C++編寫的。
所以上層Java要調用底層的C/C++函數庫必須通過Java的JNI來實現。
下面將學習Android是如何通過Jni來實現Java對C/C++函數的調用。以HelloWorld程序為例:
第一步:
使用Java編寫HelloWorld 的Android應用程序:
package com.lucyfyr;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class HelloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.v("fresne", printJNI("I am HelloWorld Activity"));
}
static
{
//載入庫文件
System.loadLibrary("HelloWorldJni");
}
//聲明原生函數 參數為String類型 返回類型為String
private native String printJNI(String inputStr);
}
這一步我們可以使用eclipse來生成一個App;
因為eclipse會自動為我們編譯此Java文件,後面要是用到。
第二步:
生成共享庫的頭文件:
進入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/
下:
可以看到裡面後很多後綴為.class的文件,就是eclipse為我們自動編譯好了的java文件,其中就有:
HelloWorld.class文件。
退回到classes一級目錄:/HelloWorld/bin/classes/
執行如下命令:
javah com.lucyfyr.HelloWorld
生成文件:com_lucyfyr_HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lucyfyr_HelloWorld */
#ifndef _Included_com_lucyfyr_HelloWorld
#define _Included_com_lucyfyr_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lucyfyr_HelloWorld
* Method: printJNI
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
可以看到自動生成對應的函數:Java_com_lucyfyr_HelloWorld_printJNI
Java_ + 包名(com.lucyfyr) + 類名(HelloWorld) + 介面名(printJNI):必須要按此JNI規范來操作;
java虛擬機就可以在com.simon.HelloWorld類調用printJNI介面的時候自動找到這個C實現的Native函數調用。
當然函數名太長,可以在.c文件中通過函數名映射表來實現簡化。
第三步:
實現JNI原生函數源文件:
新建com_lucyfyr_HelloWorld.c文件:
#include <jni.h>
#define LOG_TAG "HelloWorld"
#include <utils/Log.h>
/* Native interface, it will be call in java code */
JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI(JNIEnv *env, jobject obj,jstring inputStr)
{
LOGI("fresne Hello World From libhelloworld.so!");
// 從 instring 字元串取得指向字元串 UTF 編碼的指針
const char *str =
(const char *)(*env)->GetStringUTFChars( env,inputStr, JNI_FALSE );
LOGI("fresne--->%s",(const char *)str);
// 通知虛擬機本地代碼不再需要通過 str 訪問 Java 字元串。
(*env)->ReleaseStringUTFChars(env, inputStr, (const char *)str );
return (*env)->NewStringUTF(env, "Hello World! I am Native interface");
}
/* This function will be call when the library first be load.
* You can do some init in the libray. return which version jni it support.
*/
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
void *venv;
LOGI("fresne----->JNI_OnLoad!");
if ((*vm)->GetEnv(vm, (void**)&venv, JNI_VERSION_1_4) != JNI_OK) {
LOGE("fresne--->ERROR: GetEnv failed");
return -1;
}
return JNI_VERSION_1_4;
}
OnLoadJava_com_lucyfyr_HelloWorld_printJNI
函數裡面做一些log輸出 注意JNI中的log輸出的不同。
JNI_OnLoad函數JNI規范定義的,當共享庫第一次被載入的時候會被回調,
這個函數裡面可以進行一些初始化工作,比如注冊函數映射表,緩存一些變數等,
最後返回當前環境所支持的JNI環境。本例只是簡單的返回當前JNI環境。
http://www.cnblogs.com/bastard/archive/2012/05/19/2508913.html
㈢ Android配置ndk支持M1晶元:arm64-v8a
Unable to determine application id: com.android.tools.idea.run.ApkProvisionException: The currently selected variant "debug" uses split APKs, but none of the 1 split apks are compatible with the current device with ABIs "arm64-v8a".
不同的 Android 設備使用不同的 CPU,而不同的 CPU 支持不同的指令集。CPU 與指令集的每種組合都有專屬的應用二進制介面 (ABI)。M1晶元的macbook pro則需要支持"arm64-v8a"的ABI;
配置 build.gradle :
Android ABI詳情,可以去官方文檔查看:
https://developer.android.com/ndk/guides/abis#gradle
㈣ 如何讓android studio 生成的so文件只有arm64-v8a
1.新建一個Project2.創建native方法3.執行Build-MakeProject方法4.命令行生成com_jni_example_NativeUtilsh頭文件5.實現h中的方法6.配置NDK7.打開Project的localproperties文件添加NDK路徑8.打開appMole的buildgradle文件在defaultConfig節點里添加一下代碼並執行同步操作9.生成SO文件10.使用生成SO文件
㈤ 如何使用android的ndk編譯器 編譯c++的庫
1. 概述 首先回顧一下 Android NDK 開發中,Android.mk 和 Application.mk 各自的職責。 Android.mk,負責配置如下內容: (1) 模塊名(LOCAL_MODULE) (2) 需要編譯的源文件(LOCAL_SRC_FILES) (3) 依賴的第三方庫(LOCAL_STATIC_LIBRARIES,LOCAL_SHARED_LIBRARIES) (4) 編譯/鏈接選項(LOCAL_LDLIBS、LOCAL_CFLAGS) Application.mk,負責配置如下內容: (1) 目標平台的ABI類型(默認值:armeabi)(APP_ABI) (2) Toolchains(默認值:GCC 4.8) (3) C++標准庫類型(默認值:system)(APP_STL) (4) release/debug模式(默認值:release) 由此我們可以看到,本文所涉及的編譯選項在Android.mk和Application.mk中均有出現,下面我們將一個個詳細介紹。 2. APP_ABI ABI全稱是:Application binary interface,即:應用程序二進制介面,它定義了一套規則,允許編譯好的二進制目標代碼在所有兼容該ABI的操作系統和硬體平台中無需改動就能運行。(具體的定義請參考 網路 或者 維基網路 ) 由上述定義可以判斷,ABI定義了規則,而具體的實現則是由編譯器、CPU、操作系統共同來完成的。不同的CPU晶元(如:ARM、Intel x86、MIPS)支持不同的ABI架構,常見的ABI類型包括:armeabi,armeabi-v7a,x86,x86_64,mips,mips64,arm64-v8a等。 這就是為什麼我們編譯出來的可以運行於Windows的二進製程序不能運行於Mac OS/Linux/Android平台了,因為CPU晶元和操作系統均不相同,支持的ABI類型也不一樣,因此無法識別對方的二進製程序。 而我們所說的「交叉編譯」的核心原理也跟這些密切相關,交叉編譯,就是使用交叉編譯工具,在一個平台上編譯生成另一個平台上的二進制可執行程序,為什麼可以做到?因為交叉編譯工具實現了另一個平台所定義的ABI規則。我們在Windows/Linux平台使用Android NDK交叉編譯工具來編譯出Android平台的庫也是這個道理。 這里給出最新 Android NDK 所支持的ABI類型及區別: 那麼,如何指定ABI類型呢?在 Application.mk 文件中添加一行即可: APP_ABI := armeabi-v7a //只編譯armeabi-v7a版本 APP_ABI := armeabi armeabi-v7a //同時編譯armeabi,armeabi-v7a版本 APP_ABI := all //編譯所有版本 3. LOCAL_LDLIBS Android NDK 除了提供了Bionic libc庫,還提供了一些其他的庫,可以在 Android.mk 文件中通過如下方式添加依賴: LOCAL_LDLIBS := -lfoo 其中,如下幾個庫在 Android NDK 編譯時就默認鏈接了,不需要額外添加在 LOCAL_LDLIBS 中: (1) Bionic libc庫 (2) pthread庫(-lpthread) (3) math(-lmath) (4) C++ support library (-lstdc++) 下面我列了一個表,給出了可以添加到「LOCAL_LDLIBS」中的不同版本的Android NDK所支持的庫: 下面是我總結的一些常用的CFLAGS編譯選項: (1)通用的編譯選項 -O2 編譯優化選項,一般選擇O2,兼顧了優化程度與目標大小 -Wall 打開所有編譯過程中的Warning -fPIC 編譯位置無關的代碼,一般用於編譯動態庫 -shared 編譯動態庫 -fopenmp 打開多核並行計算, -Idir 配置頭文件搜索路徑,如果有多個-I選項,則路徑的搜索先後順序是從左到右的,即在前面的路徑會被選搜索 -nostdinc 該選項指示不要標准路徑下的搜索頭文件,而只搜索-I選項指定的路徑和當前路徑。 --sysroot=dir 用dir作為頭文件和庫文件的邏輯根目錄,例如,正常情況下,如果編譯器在/usr/include搜索頭文件,在/usr/lib下搜索庫文件,它將用dir/usr/include和dir/usr/lib替代原來的相應路徑。 -llibrary 查找名為library的庫進行鏈接 -Ldir 增加-l選項指定的庫文件的搜索路徑,即編譯器會到dir路徑下搜索-l指定的庫文件。 -nostdlib 該選項指示鏈接的時候不要使用標准路徑下的庫文件 (2) ARM平台相關的編譯選項 -marm -mthumb 二選一,指定編譯thumb指令集還是arm指令集 -march=name 指定特定的ARM架構,常用的包括:-march=armv6, -march=armv7-a -mfpu=name 給出目標平台的浮點運算處理器類型,常用的包括:-mfpu=neon,-mfpu=vfpv3-d16 -mfloat-abi=name 給出目標平台的浮點預算ABI,支持的參數包括:「soft」, 「softfp」 and 「hard」
㈥ Android中的armeabi、armeabi-v7a、arm64-v8a及x86的詳解
一. lib和libs
放在lib中的是被reference的,放在libs中的是被include的。
放在libs中的文件會自動被編輯器所include。所以不要把API放到libs里去。
lib的內容是不會被打包到APK中,libs中的內容是會被打包進APK中
二. .so庫
NDK編譯出來的動態鏈接庫。
一些重要的加密演算法或者核心協議一般都用c寫然後給java調用。這樣可以避免反編譯後查看到應用的源碼。
三. .so庫該如何存放
放置 .so 文件的正確姿勢其實就兩句話:
• 為了減小 apk 體積,只保留 armeabi 和 armeabi-v7a 兩個文件夾,並保證這兩個文件夾中 .so 數量一致
• 對只提供 armeabi 版本的第三方 .so,原樣復制一份到 armeabi-v7a 文件夾
存放so的規則:
你應該盡可能的提供專為每個ABI優化過的.so文件,但要麼全部支持,要麼都不支持:你不應該混合著使用。你應該為每個ABI目錄提供對應的.so文件。
四. libs下armeabi等的作用是什麼
存放.so庫,主要針對不同的設備兼容,也可以說是專門針對不同Android手機下CPU架構的兼容。
Android 設備的CPU類型(通常稱為」ABIs」)
早期的Android系統幾乎只支持ARMv5的CPU架構,後面發展到支持七種不同的CPU架構:ARMv5,ARMv7 (從2010年起),x86 (從2011年起),MIPS (從2012年起),ARMv8,MIPS64和x86_64 (從2014年起),每一種都關聯著一個相應的ABI。
應用程序二進制介面(Application Binary Interface)定義了二進制文件(尤其是.so文件)如何運行在相應的系統平台上,從使用的指令集,內存對齊到可用的系統函數庫。在Android 系統上,每一個CPU架構對應一個ABI:armeabi,armeabi-v7a,x86,mips,arm64- v8a,mips64,x86_64。
armeabi-v7a: 第7代及以上的 ARM 處理器。2011年以後生產的大部分Android設備都使用它.
arm64-v8a: 第8代、64位ARM處理器,很少設備,三星 Galaxy S6是其中之一。
armeabi: 第5代、第6代的ARM處理器,早期的手機用的比較多。
x86: 平板、模擬器用得比較多。
x86_64: 64位的平板。
如果項目只包含了 armeabi,那麼在所有Android設備都可以運行;
如果項目只包含了 armeabi-v7a,除armeabi架構的設備外都可以運行;
如果項目只包含了 x86,那麼armeabi架構和armeabi-v7a的Android設備是無法運行的; 如果同時包含了 armeabi, armeabi-v7a和x86,所有設備都可以運行,程序在運行的時候去載入不同平台對應的so,這是較為完美的一種解決方案,同時也會導致包變大。
最後,如果我們只想支持armeabi-v7a,那麼需要在gradle中配置
因為默認情況下,打包後會自動生成armeabi 到 x86的所有文件夾。這就有可能導致一些x86的設備因為在x86文件夾下找不到so文件而崩潰。
㈦ 如何設置NDK的編譯選項
1. 概述
首先回顧一下 Android NDK 開發中,Android.mk 和Application.mk 各自的職責。
Android.mk,負責配置如下內容:
(1) 模塊名(LOCAL_MODULE)
(2) 需要編譯的源文件(LOCAL_SRC_FILES)
(3) 依賴的第三方庫(LOCAL_STATIC_LIBRARIES,LOCAL_SHARED_LIBRARIES)
(4) 編譯/鏈接選項(LOCAL_LDLIBS、LOCAL_CFLAGS)
Application.mk,負責配置如下內容:
(1) 目標平台的ABI類型(默認值:armeabi)(APP_ABI)
(2) Toolchains(默認值:GCC 4.8)
(3) C++標准庫類型(默認值:system)(APP_STL)
(4) release/debug模式(默認值:release)
由此我們可以看到,本文所涉及的編譯選項在Android.mk和Application.mk中均有出現,下面我們將一個個詳細介紹。
2. APP_ABI
ABI全稱是:Application binary interface,即:應用程序二進制介面,它定義了一套規則,允許編譯好的二進制目標代碼在所有兼容該ABI的操作系統和硬體平台中無需改動就能運行。(具體的定義請參考網路或者維基網路)
由上述定義可以判斷,ABI定義了規則,而具體的實現則是由編譯器、CPU、操作系統共同來完成的。不同的CPU晶元(如:ARM、Intel x86、MIPS)支持不同的ABI架構,常見的ABI類型包括:armeabi,armeabi-v7a,x86,x86_64,mips,mips64,arm64-v8a等。
這就是為什麼我們編譯出來的可以運行於Windows的二進製程序不能運行於Mac OS/Linux/Android平台了,因為CPU晶元和操作系統均不相同,支持的ABI類型也不一樣,因此無法識別對方的二進製程序。
而我們所說的「交叉編譯」的核心原理也跟這些密切相關,交叉編譯,就是使用交叉編譯工具,在一個平台上編譯生成另一個平台上的二進制可執行程序,為什麼可以做到?因為交叉編譯工具實現了另一個平台所定義的ABI規則。我們在Windows/Linux平台使用Android NDK交叉編譯工具來編譯出Android平台的庫也是這個道理。
這里給出最新 Android NDK 所支持的ABI類型及區別:
下面是我總結的一些常用的CFLAGS編譯選項:
(1)通用的編譯選項
-O2 編譯優化選項,一般選擇O2,兼顧了優化程度與目標大小
-Wall 打開所有編譯過程中的Warning
-fPIC 編譯位置無關的代碼,一般用於編譯動態庫
-shared 編譯動態庫
-fopenmp 打開多核並行計算,
-Idir 配置頭文件搜索路徑,如果有多個-I選項,則路徑的搜索先後順序是從左到右的,即在前面的路徑會被選搜索
-nostdinc 該選項指示不要標准路徑下的搜索頭文件,而只搜索-I選項指定的路徑和當前路徑。
--sysroot=dir 用dir作為頭文件和庫文件的邏輯根目錄,例如,正常情況下,如果編譯器在/usr/include搜索頭文件,在/usr/lib下搜索庫文件,它將用dir/usr/include和dir/usr/lib替代原來的相應路徑。
-llibrary 查找名為library的庫進行鏈接
-Ldir 增加-l選項指定的庫文件的搜索路徑,即編譯器會到dir路徑下搜索-l指定的庫文件。
-nostdlib 該選項指示鏈接的時候不要使用標准路徑下的庫文件
(2) ARM平台相關的編譯選項
-marm -mthumb 二選一,指定編譯thumb指令集還是arm指令集
-march=name 指定特定的ARM架構,常用的包括:-march=armv6, -march=armv7-a
-mfpu=name 給出目標平台的浮點運算處理器類型,常用的包括:-mfpu=neon,-mfpu=vfpv3-d16
-mfloat-abi=name 給出目標平台的浮點預算ABI,支持的參數包括:「soft」, 「softfp」 and 「hard」
㈧ so庫如何適配安卓32bit\64bit 的cpu 怎麼編譯
在libs文件下建arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64文件夾,然後把編譯好的so文件拷貝進去
app/build.gradle的android選項卡下添加
ndk{
abiFilters "armeabi","armeabi-v7a","x86","x86_64","mips","mips64","arm64-v8a"
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
設置好native方法的包名,含有native方法的類添加,
static {
System.loadLibrary("videoplay");
}
載入完類庫,添加native方法,如果有c/cpp文件的話需要在app/src/main/目錄下建cpp文件夾,然後編譯運行就好了