配置全局变量

先在/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. select * 的使用说明

    一. SELECT * 的含义 select * 语句是从指定的表中按照顺序返回所有列. 二. SELECT * 的优缺点 1  优点 在实际开发过程中,大家习惯性地使用select *  from  ...

  2. P9801 [NERC2018] King Kog’s Reception

    题目传送门 前置知识 线段树 解法 第一眼感觉和 luogu P1083 [NOIP2012 提高组] 借教室 很像.本题同样采用线段树维护,\(sum_{l,r}(1 \le l \le r \le ...

  3. C语言,结构体成员的地址

    先回顾一个基础的知识,不同类型的数据在16位,32位,64位的机器分别占用多少字节. 类型 16位机器(字节) 32位机器(字节) 64位机器(字节) char 1 1 1 short 2 2 2 i ...

  4. 发布Npm包到GitHub Packages

    发布Npm包到GitHub Packages Github集成了GitHub Packages功能,目前提供了Npm.Docker.Maven.NuGet.RubyGems的包管理工具,可以通过Git ...

  5. lsattr命令

    lsattr命令 lsattr命令用于显示文件的属性. 语法 lsattr [-RVadlv] [file | folder] 参数 -a: 显示所有文件和目录,包括以.为名称开头字符的额外内建,即现 ...

  6. OCP试题解析之053-16 MEMORY_TARGET

    16.Setting which of the following initialization parameters enables Automatic Memory Management? A. ...

  7. Redis原理学习:Redis主体流程分析

    转自:七把刀 https://www.jianshu.com/p/427cf97d7951 网上分析Redis源码的文章挺多,如黄健宏的<Redis设计与实现>就很详尽的分析了redis源 ...

  8. mysql分组后获取每个组排序后的第一条数据(整行)

    有一个学生分数表student,数据结构是这样的 CREATE TABLE `student` ( `id` int(11) NOT NULL, `student_id` int(11) DEFAUL ...

  9. go语言变量的零值和nil

    Go语言中无论是全局变量还是局部变量,只要定义了一个变量都有默认的0值 int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/byte/ ...

  10. 【LeetCode递归】括号生成,使用dfs

    括号匹配 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合. 示例 1: 输入:n = 3 输出:["((()))","(() ...