配置全局变量

先在/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. ElasticSearch7.3学习(三十四)----生产环境集群部署总结

    1.集群部署 2.结点的三个角色 主结点:master节点主要用于集群的管理及索引 比如新增结点.分片分配.索引的新增和删除等. 数据结点:data 节点上保存了数据分片,它负责索引和搜索操作. 客户 ...

  2. Pandas分组聚合

    groupby分组操作详解 在数据分析中,经常会遇到这样的情况:根据某一列(或多列)标签把数据划分为不同的组别,然后再对其进行数据分析.比如,某网站对注册用户的性别或者年龄等进行分组,从而研究出网站用 ...

  3. 100 行代码实现用户登录注册与 RESTful 接口 - 手把手教程附 Python 源码

    在开发大多数应用时,用户系统都是必不可少的部分,而我们总是需要开发围绕用户的登录,注册,获取,更新等接口.在这篇文章将带你用一百多行代码简洁地实现一套这样的用户鉴权与 RESTful 接口,并使用 S ...

  4. 【Unity3D】UGUI之Dropdown

    1 Dropdown属性面板 ​ 在 Hierarchy 窗口右键,选择 UI 列表里的 Dwondown (下拉列表)控件,即可创建 Dwondown 控件,选中创建的 Dwondown 控件,按键 ...

  5. maven打包更改版本号

    引入依赖 <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-mave ...

  6. Spring boot 2.0启动自动执行sql语句

    项目地址:https://gitee.com/indexman/spring_boot_in_action 1.准备sql文件 将department.sql放到resources路径下 /* Nav ...

  7. "explicit" 的使用

    今天在编译项目时,代码审查提示 "Single-parameter constructors should be marked explicit" 于是就在构造函数前加上 expl ...

  8. TerminateJobObject是使用

    注意: AssignProcessToJobObject仅适用于win32 desktop app, 比如notepad是适用的,calculator是不适用的 下面的demo是将notepad的句柄 ...

  9. 细说Spring Boot初始化DispatcherServlet

    DispatcherServlet概述 在Spring Boot框架未出现之前,要开发一个基于Spring MVC框架的项目,通常需要在Java web项目的描述符文件web.xml中添加如下配置: ...

  10. Java - 将TXT文本文件转换为PDF文件

    与TXT文本文件,PDF文件更加专业也更适合传输,常用于正式报告.简历.合同等场合.项目中如果有使用Java将TXT文本文件转为PDF文件的需求,可以查看本文中介绍的免费实现方法. 免费Java PD ...