配置全局变量

先在/etc/profile文件中配置全局变量

#NDK相关配置信息
export NDK="/home/zuojie/android-ndk-r17c" export NDK_GCC_x86="$NDK/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-gcc"
export NDK_GCC_x64="$NDK/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc"
export NDK_GCC_arm="$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc"
export NDK_GCC_arm_64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc" export NDK_CFIG_x86="--sysroot=$NDK/platforms/android-21/arch-x86 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/i686-linux-android"
export NDK_CFIG_x64="--sysroot=$NDK/platforms/android-21/arch-x86_64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/x86_64-linux-android"
export NDK_CFIG_arm="--sysroot=$NDK/platforms/android-21/arch-arm -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/arm-linux-androideabi"
#这个实验,不成功
# export NDK_CFIG_arm_64="--isysroot=$NDK/platforms/android-21/arch-arm64 -isystem $NDK/sysroot/usr/include -isystem -isystem $NDK/sysroot/usr/include/aarch64-linux-android"
export NDK_CFIG_arm_64="--sysroot=$NDK/platforms/android-21/arch-arm64 -isystem $NDK/sysroot/usr/include -isystem $NDK/sysroot/usr/include/aarch64-linux-android" export NDK_AR_x86="$NDK/toolchains/x86-4.9/prebuilt/linux-x86_64/bin/i686-linux-android-ar"
export NDK_AR_x64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar"
export NDK_AR_arm="$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar"
export NDK_AR_arm_64="$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar" # 静态库 动态库相关
export myd="$NDK_GCC_arm $NDK_CFIG_arm -fPIC -shared "
export myj="$NDK_AR_arm rcs "

编译动态库和静态库:

在Linux下使用NDK来编译动态库和静态库

动态库编译

$NDK_GCC_arm $NDK_CFIG_arm -fPIC -shared get.c -o libget.so

静态库编译

ndk编译静态库: 必须使用 arm-linux-androideabi-ar

必须先用交叉编译打出来的 .o,不能使用gcc

$NDK_GCC_arm $NDK_CFIG_arm -fPIC -c get.c -o get.o

在使用arm-linux-androideabi-ar打出静态库

$NDK_AR_arm rcs -o  libget.a *.o

AS mk 方式加载静态库和动态库

先新建一个普通的一个Android项目

配置build.gradle

apply plugin: 'com.android.application'

android {
compileSdkVersion 28
buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.zxj.ndk_mk"
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" //指导源文件编译
externalNativeBuild{
ndkBuild{
abiFilters "armeabi-v7a"
}
} //应该打包几种cpu
ndk{
abiFilters "armeabi-v7a"
}
} //配置Native的构建脚本路径
externalNativeBuild{
ndkBuild{
path "src/main/cpp/Android.mk"
}
} buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
} dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

加载静态库方法

将libget.a考入到项目中

配置Android.mk

新建一个Android.mk文件

#源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。
LOCAL_PATH := $(call my-dir) # 打印
$(info "LOCAL_PATH :== $(LOCAL_PATH)") #引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS) # TODO start 预编译库的引入 == 提前编译好的库
LOCAL_MODULE := myGet
LOCAL_SRC_FILES := libget.a
# LOCAL_SRC_FILES := libget.so
# 告诉构建工具是静态库
include ${PREBUILT_STATIC_LIBRARY}
# 告诉构建工具是动态库
# include ${PREBUILT_SHARED_LIBRARY} #开始清理
include $(CLEAR_VARS)
#TODO end #存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := native-lib #包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := native-lib.c \
Test.c # TODO start 开始连接进来,将libget.a/libget.so连接到总库中(libnative-lib.so)
# 静态库的链接
LOCAL_STATIC_LIBRARIES := myGet
# 动态库的链接
# LOCAL_SHARED_LIBRARIES := myGet
# TODO end #导入log
# LOCAL_LDLIBS := -llog
LOCAL_LDLIBS := -lm -llog #构建动态库
include $(BUILD_SHARED_LIBRARY)

新建native-lib.c

在MainActivity中声明getMyLibMethod方法

public class MainActivity extends AppCompatActivity {

    static {
System.loadLibrary("native-lib");
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getMyLibMethod();
} public native void getMyLibMethod();
}

使用javah生成头文件

javah com.zxj.ndk_mk.MainActivity

在native-lib.c中实现头文件

#include <jni.h>
#include <android/log.h> extern int get(); JNIEXPORT void JNICALL Java_com_zxj_ndk_1mk_MainActivity_getMyLibMethod
(JNIEnv *env, jobject inst){ __android_log_print(ANDROID_LOG_DEBUG,"zuo","testgetMethod:%d",get());
}

加载动态库方法

加载动态库方法跟加载静态库基本一样,只不过有点小区别,下面是在加载静态库的基础上进行修改

将libget.so考入到项目中

配置Android.mk文件

#源文件在的位置。宏函数 my-dir 返回当前目录(包含 Android.mk 文件本身的目录)的路径。
LOCAL_PATH := $(call my-dir) # 打印
$(info "LOCAL_PATH :== $(LOCAL_PATH)") #引入其他makefile文件。CLEAR_VARS 变量指向特殊 GNU Makefile,可为您清除许多 LOCAL_XXX 变量
#不会清理 LOCAL_PATH 变量
include $(CLEAR_VARS) # TODO start 预编译库的引入 == 提前编译好的库
LOCAL_MODULE := myGet
# LOCAL_SRC_FILES := libget.a
LOCAL_SRC_FILES := libget.so
# 告诉构建工具是静态库
# include ${PREBUILT_STATIC_LIBRARY}
# 告诉构建工具是动态库
include ${PREBUILT_SHARED_LIBRARY} #开始清理
include $(CLEAR_VARS)
#TODO end # TODO start 开始连接进来,将libget.a/libget.so连接到总库中(libnative-lib.so)
# 静态库的链接
# LOCAL_STATIC_LIBRARIES := myGet
# 动态库的链接
LOCAL_SHARED_LIBRARIES := myGet
# TODO end #存储您要构建的模块的名称 每个模块名称必须唯一,且不含任何空格
#如果模块名称的开头已是 lib,则构建系统不会附加额外的前缀 lib;而是按原样采用模块名称,并添加 .so 扩展名。
LOCAL_MODULE := native-lib #包含要构建到模块中的 C 和/或 C++ 源文件列表 以空格分开
LOCAL_SRC_FILES := native-lib.c \
Test.c #导入log
# LOCAL_LDLIBS := -llog
LOCAL_LDLIBS := -lm -llog #构建动态库
include $(BUILD_SHARED_LIBRARY)
在>=6.0系统上会报错

加载动态库方法在>=6.0设备中是无法执行的

这个错误是报动态库的路径无法找到,而这个动态库的路径是电脑的路径,在Android设备上肯定是找不到的所以会报错。目前还没有找到在>=6.0设备的解决方法,最好是使用CMake

加载libget.so库

因为动态库在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,所以需要在加载总库(libnative-lib.so)之前进行加载libget.so库。

static {
//一定要在加载总库(libnative-lib.so)之前进行加载libget.so库
System.loadLibrary("get");
System.loadLibrary("native-lib");
}

其他的跟加载静态库的代码一样,直接运行就可以成功

AS cmake方式加载静态库和动态库

先创建一个Native C++工程,创建好工程后,build.gradle文件里的externalNativeBuild里默认是cppFlags ""表示默认包含四大平台

我们可以使用abiFilters来指定某个平台

加载静态库方法

将静态库考入到某一个目录下,我这里考入的是cpp目录下

配置CMakeLists.txt文件

配置CMakeLists.txt有两种方式,

  1. 以add_library和set_target_properties的方式配置静态库
  2. 以set方式配置动态库
1.以add_library和set_target_properties的方式配置动态库

这里以add_library可以取一个名称MyGet,那么在下面就需要使用这个名称MyGet

cmake_minimum_required(VERSION 3.4.1)

#打印日志
message("当前CMake的路径时:${CMAKE_SOURCE_DIR}") add_library(
native-lib
SHARED
native-lib.cpp) # 加入一个库,取名为MyGet,STATIC 静态库,IMPORTED 以导入的方式
add_library(MyGet STATIC IMPORTED)
#开始真正的导入
set_target_properties(MyGet PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libget.a) find_library(
log-lib
log) #链接到库
target_link_libraries(
native-lib
MyGet
${log-lib})
2.以set方式配置动态库

使用set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")这个进行配置。另外target_link_libraries里要配置的是libget.soget

cmake_minimum_required(VERSION 3.4.1)

#打印日志
message("当前CMake的路径时:${CMAKE_SOURCE_DIR}") add_library(
native-lib
SHARED
native-lib.cpp) # 设置一个变量
# CMAKE_CXX_FLAGS C++的参数,会传给编译器。CMAKE_C_FLAGS C的参数,会传给编译器
# ${CMAKE_CXX_FLAGS} 使用变量,就是例如之前已经定了CMAKE_CXX_FLAGS= --sysroot=XX,现在重新定义 CMAKE_CXX_FLAGS 变量
# -L 指定库的路径
# CMAKE_SOURCE_DIR的值就是当前这个文件(CMakeLists.txt)的路径
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}") find_library(
log-lib
log) #链接到库
target_link_libraries(
native-lib
get
${log-lib})

调用链接库的方法

native-lib.cpp

#include <jni.h>
#include <string>
#include <android/log.h> //因为链接的库libget.a,是C语言的,这里是C++的,所以需要extern "C"
extern "C"{
int get();
} extern "C" JNIEXPORT jstring JNICALL
Java_com_zxj_ndk_1cmake_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++" ; __android_log_print(ANDROID_LOG_DEBUG,"zuo","使用CMake方式---test getMethod:%d",get()); return env->NewStringUTF(hello.c_str());
}

最后运行就可以了

加载动态库方法

将动态库考入到某一个目录下,这里我们习惯把动态库夸人到/main/jniLibs/armeabi-v7下

配置CMakeLists.txt文件

配置CMakeLists.txt有两种方式,

  1. 以add_library和set_target_properties的方式配置动态库
  2. 以set方式配置动态库
1.以add_library和set_target_properties的方式配置动态库

这里以add_library可以取一个名称MyGet,那么在下面就需要使用这个名称MyGet

cmake_minimum_required(VERSION 3.4.1)

#打印日志
message("当前CMake的路径时:${CMAKE_SOURCE_DIR}")
message("当前系统的平台:${CMAKE_ANDROID_ARCH_ABI}") add_library(
native-lib
SHARED
native-lib.cpp) # 加入一个库,取名为MyGet,STATIC 静态库,IMPORTED 以导入的方式
add_library(MyGet SHARED IMPORTED)
# ${CMAKE_ANDROID_ARCH_ABI} 当前系统的平台,这里就是armeabi-v7a
set_target_properties(MyGet PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libget.so) find_library(
log-lib
log) #链接到库
target_link_libraries(
native-lib
MyGet
${log-lib})
2.以set方式配置动态库

使用set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")这个进行配置。另外target_link_libraries里要配置的是libget.soget

cmake_minimum_required(VERSION 3.4.1)

#打印日志
message("当前CMake的路径时:${CMAKE_SOURCE_DIR}")
message("当前系统的平台:${CMAKE_ANDROID_ARCH_ABI}") add_library(
native-lib
SHARED
native-lib.cpp) # 设置一个变量
# CMAKE_CXX_FLAGS C++的参数,会传给编译器。CMAKE_C_FLAGS C的参数,会传给编译器
# ${CMAKE_CXX_FLAGS} 使用变量,就是例如之前已经定了CMAKE_CXX_FLAGS= --sysroot=XX,现在重新定义 CMAKE_CXX_FLAGS 变量
# -L 指定库的路径
# CMAKE_SOURCE_DIR的值就是当前这个文件(CMakeLists.txt)的路径
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}") find_library(
log-lib
log) #链接到库
target_link_libraries(
native-lib
get
${log-lib})
在>=6.0系统上会报错

CMake加载动态库方式跟Makefile的一样,第一种方式只能在6.0以下使用,否则会报错,原因跟Makefile的一样,而第2种以set方式的可以兼容>=6.0版本以上的

加载libget.so库

因为动态库在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,所以需要在加载总库(libnative-lib.so)之前进行加载libget.so库。

static {
System.loadLibrary("get");
System.loadLibrary("native-lib");
}

Linux下编译成静态库和动态库,引入到项目中的更多相关文章

  1. Linux 下Python调用C++编写的动态库

    在工程中用到使用Python调用C++编写的动态库,结果报如下错误: OSError: ./extract_str.so: undefined symbol: _ZNSt8ios_base4InitD ...

  2. 使用CMake在Linux下编译tinyxml静态库

    环境:CentOS6.6+tinyxml_2_6_21.下载并解压tinyxml_2_6_2.zip unzip tinyxml_2_6_2.zip 2.在tinyxml文件夹里创建一个CMakeLi ...

  3. Linux下编译、使用静态库和动态库 自己测过的

    每个程序实质上都会链接到一个或者多个的库.比如使用C函数的程序会链接到C运行时库,GUI程序会链接到窗口库等等.无论哪种情况,你都会要决定是链接到静态库(static libary)还是动态库(dyn ...

  4. Linux下Gcc生成和使用静态库和动态库详解(转)

    一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...

  5. 在Linux下如何使用GCC编译程序、简单生成 静态库及动态库

      最近在编写的一个Apache  kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a    静态库编译的,,,而我们这 ...

  6. Linux下Gcc生成和使用静态库和动态库详解

    参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...

  7. [转]Linux下用gcc/g++生成静态库和动态库(Z)

    Linux下用gcc/g++生成静态库和动态库(Z) 2012-07-24 16:45:10|  分类: linux |  标签:链接库  linux  g++  gcc  |举报|字号 订阅     ...

  8. linux下的共享库(动态库)和静态库

    1.什么是库在windows平台和linux平台下都大量存在着库.本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行.由于windows和linux的本质不同,因此二者库的二进制是不 ...

  9. 【转】Linux下gcc生成和使用静态库和动态库详解

    一.基本概念 1.1 什么是库 在Windows平台和Linux平台下都大量存在着库. 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不 ...

  10. (笔记)Linux下的静态库和动态库使用详解

    库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 一.静态库和动态库的区别 1. 静态函数库 这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比 ...

随机推荐

  1. 好书推荐之《码出高效》、《阿里巴巴JAVA开发手册》

    好评如潮 <阿里巴巴Java开发手册> 简介 <阿里巴巴Java开发手册>的愿景是码出高效,码出质量.它结合作者的开发经验和架构历程,提炼阿里巴巴集团技术团队的集体编程经验和软 ...

  2. [刺客伍六七&黑客] 魔刀千刃evilblade的使用手册与开源

    0x00 前言 2023.8.15 夜里 非常欢迎使用我的魔刀千刃,并且欢迎各位师傅对我的开源代码进行指导! -–Offense without defense, unparalleled in th ...

  3. NC24961 Hotel

    题目链接 题目 题目描述 The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and ...

  4. NC22604 小A与任务

    题目链接 题目 题目描述 小A手头有 n 份任务,他可以以任意顺序完成这些任务,只有完成当前的任务后,他才能做下一个任务 第 i 个任务需要花费 \(x_i\) 的时间,同时完成第 i 个任务的时间不 ...

  5. 【Unity3D】激光灯、碰撞特效

    1 需求描述 ​ 本文将模拟激光灯(或碰撞)特效,详细需求如下: 从鼠标位置发射屏幕射线,检测是否与物体发生碰撞 当与物体发生碰撞时,在物体表面覆盖一层激光灯(或碰撞)特效 ​ 本文代码见→激光灯.碰 ...

  6. JVM之直接内存与非直接内存

    直接内存 直接内存:概指系统内存,而非堆内存,不指定大小时它的大小默认与堆的最大值-Xmx参数值一致. 非直接内存: 也可以称之为堆内存,运行JVM都会预先分配一定内存,我们把JVM管理的这些内存称为 ...

  7. 【Python语法糖】闭包和装饰器

    Python闭包和装饰器 参考: https://zhuanlan.zhihu.com/p/453787908 https://www.bilibili.com/video/BV1JW411i7HR/ ...

  8. 01、etcd基础介绍

    互联网技术发展真的快,层出不穷的新技术.最近项目使用到了etcd,自己之前在部署k8s集群的时候玩过,但是并没有系统的学习.正好趁这个机会,系统性的学习下.文章中的内容有些是来自官方文档,有些是来自网 ...

  9. 为Study.BlazorOne引入Study.Trade模块

    # 1.在Application项目中添加Trade的对应的包 默认的源多半是nuget.org 我们自己的模块,一般在我们自己的NuGet服务器 从"已安装"切换到"浏 ...

  10. 【Filament】纹理贴图

    1 前言 ​ 本文主要介绍使用 Filament 实现纹理贴图,读者如果对 Filament 不太熟悉,请回顾以下内容. Filament环境搭建 绘制三角形 绘制矩形 绘制圆形 绘制立方体 ​ Fi ...