配置全局变量

先在/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. JVM(Java虚拟机)整理(二)

    前言 上一篇内容:JVM(Java虚拟机)整理(一)https://www.cnblogs.com/xiegongzi/p/17994659 Java 内存模型(JMM) Java 内存模型引入 声明 ...

  2. 《ASP.NET Core 微服务实战》-- 读书笔记(第8章)

    第 8 章 服务发现 面对大量服务,为了简化配置和管理工作,我们需要了解"服务发现"概念 回顾云原生特性 配置外置 将 URL 和登录凭证移到配置文件和 C# 代码之外,放到环境变 ...

  3. 计算机算法设计与分析(第5版)PDF

    <计算机算法设计与分析(第5版)>是2018年电子工业出版社出版的图书,作者是王晓东. 整本书的结构是:先介绍算法设计策略思想,然后从解决经典算法问题来学习,通过实践的方式去学习算法. 网 ...

  4. 【Android】使用AIDL实现进程间通讯简单案例

    1 AIDL 简介 ​ AIDL(Android Interface Definition Language)是一种接口定义语言,用于生成可在 Android 设备上两个进程之间进行进程间通信(IPC ...

  5. 实操开源版全栈测试工具RunnerGo安装(一)

    Docker版安装文档 一.环境要求​ 1.1 部署服务器要求​ 操作系统:任何支持 Docker 的 Linux x86 CPU内存:最低要求 4C8G,推荐 8C16G 网络要求:可访问互联网 ​ ...

  6. BUUCTF [强网杯 2019]随便注 1

    1. 拿到题目,先输入一个1'试一下是否存在注入点 报错 error 1064 : You have an error in your SQL syntax; check the manual tha ...

  7. java轻量级规则引擎easy-rules使用介绍

    我们在写业务代码经常遇到需要一大堆if/else,会导致代码可读性大大降低,有没有一种方法可以避免代码中出现大量的判断语句呢? 答案是用规则引擎,但是传统的规则引擎都比较重,比如开源的Drools,不 ...

  8. django时区相关说明

    # naive time 从字面意思上理解,这是个"幼稚的时间",所以可以理解为它是个本地时间,不带时区信息,不能直接用于存储,如下 import datetime datetim ...

  9. Javascript之Object、Array

    Object.keys 对象的键转化为数组 Object.values 对象的属性值转化为数组 Object.assign 对象的合并   Array.from() 伪数组对象的属性值转化为数组.类似 ...

  10. 【Azure K8S】记录AKS VMSS实例日志收集方式

    问题描述 如何从AKS的VMSS集群中收集实例日志? 参考步骤 第一步:登陆VMSS实例 参考官网步骤:使用 SSH 连接到 Azure Kubernetes 服务 (AKS) 群集节点以进行维护或故 ...