Android Studio 基于cmake 链接静态库,动态库

1. 搭建环境

环境变量:      
sudo apt-get remove openjdk*      
export JAVA_HOME=/opt/java/jdk1.8.0_211
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export NDK=/opt/java/android-ndk-r13b
export ANDROID_SDK=/opt/Sdk
export PATH=.:${JAVA_HOME}/bin:$PATH:$NDK:$ANDROID_SDK/platform-tools:$ANDROID_SDK/tools

-----------------------ndk13------------------------------------------------------------------------------------------------------------

export CC=/opt/java/android-ndk-r13b/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
echo $CC         #编译arm 下执行gcc
export CFCAGS="--sysroot=/opt/java/android-ndk-r13b/platforms/android-21/arch-arm"
                 #参数  指定编译头文件

$CC $CFCAGS -fPIC -shared -o libTest.so hello.c -I.     # 生成 arm 平台下 的动态库libTest.so

$CC  $CFCAGS -c hello.c -o hello.o
ar -crsv libStaticTest.a hello.o       #生成静态库libStaticTest.a

------------------ndk 16-------------------------------------------------------------------------------------------------------------------

export CC=/opt/android-ndk-r16-beta1/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
echo $CC         #编译arm 下执行gcc
export CFCAGS="--sysroot=/opt/android-ndk-r16-beta1/platforms/android-21/arch-arm -isysroot /opt/android-ndk-r16-beta1/sysroot  -isystem /opt/android-ndk-r16-beta1/sysroot/usr/include/arm-linux-androideabi"
                 #参数  指定编译头文件
                 
$CC $CFCAGS -fPIC -shared -o libTestDynastic.so hello.c -I.

ndk 16 头文件单独放入了android-ndk-r16-beta1/sysroot 目录下

----------------------------------------------------------------------------------------

--sysroot=XX
  使用xx作为这一次编译头文件与库的查找目录, 默认查找下面/usr/include  usr/lib目录
--isysroot  xx
  头文件查找目录,覆盖--sysroot,查找XX/usr/include
-IXX 
  头文件查找目录
-LXX 
  指定库文件目录
-xx.so
  指定需要链接的库名
优先级: -I > -isystem >  sysroot

  hello.c源文件:

#include <stdio.h>
#include <stdlib.h>

int  test(){
   printf("test  test  ");
  return 1000000;
}
int  test2(){ 
  printf("test2  test2  ");
  return 1;
}
void main(){
     test();
     test2();
  }

  2.1 新建android工程, Include C++ Support
   2.2. 拷贝so 库静态库 放入到指定 编译环境目录 下   库名:libTest.so、libStaticTest.a

   2.3. native-lib.cpp 中 调用 so库函数

 Java :

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

native-lib.cpp

#include <jni.h>
#include <string>

#include <android/log.h>
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "JNI", __VA_ARGS__)

// c++ 中调用 c ,必须 要  extern "C"
extern "C" {
   extern jint test();   // 1000000, static test

   extern jint test2();    // 1, dynastic test
}


extern "C"
JNIEXPORT jstring

JNICALL
Java_dn_denganzhi_com_myapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {


       jint r=  test();
        LOGE(" test1---%d",r);

        int r2= test2();
         LOGE(" test2---%d",r2);


    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());


}


    2.4. 修改 CMakeLists.txt指定编译的时候 链接 libTest.so 库 , 编译动态库,指定红色的即可

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 主文件  编译生成库名   动态库   路径
add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# 连接log
find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# 设置一个变量
# CMAKE_CXX_FLAGS    c++的参数,会传递给编译器
# CMAKE_C_FLAGS      c
# 编译的时候传递参数需要连接so
# 动态库生成可执行程序的时候链接:
#  3.gcc main.c -o main -I. -L. -lsy : 生成可执行程序
#  -L 指定动态库的路径  libTestDynastic.so
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}")


# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
#  表示以引入静态库的方式引入StaticTest
#add_library(StaticTest STATIC IMPORTED)
#  设置目标导入路径,这里是一行
#set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libStaticTest.a)

# 使用message 输出 cmake 内置变量
message("ANDROID_ABI : ${ANDROID_ABI}")

# 第一个参数目标so
# 编译native-lib 模块需要 StaticTest 模块
target_link_libraries( # Specifies the target library.
                       native-lib
                   #     StaticTest      # 静态库编译链接
                       TestDynastic    #动态库编译链接,指定动态库名,去头lib去尾巴so
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

2.5.  gradle配置   abiFilters生成架构库

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "dn.denganzhi.com.myapplication"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
                abiFilters "armeabi-v7a"
            }
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
 

   2.6. 加载库, 调用native方法运行,输出结果

调用: 

package dn.denganzhi.com.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
//        System.loadLibrary("Test");
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


    }

    public void  showMsg(View view){
          stringFromJNI();
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

输出结果:

 静态库配置:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
# 主文件  编译生成库名   动态库   路径
add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
# 连接log
find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# 设置一个变量
# CMAKE_CXX_FLAGS    c++的参数,会传递给编译器
# CMAKE_C_FLAGS      c
# 编译的时候传递参数需要连接so
# 动态库生成可执行程序的时候链接:
#  3.gcc main.c -o main -I. -L. -lsy : 生成可执行程序
#  -L 指定动态库的路径  libTestDynastic.so
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}")


# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
#  表示以引入静态库的方式引入StaticTest
add_library(StaticTest STATIC IMPORTED)
#  设置目标导入路径,这里是一行
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libStaticTest.a)

# 使用message 输出 cmake 内置变量
message("ANDROID_ABI : ${ANDROID_ABI}")

# 第一个参数目标so
# 编译native-lib 模块需要 StaticTest 模块
target_link_libraries( # Specifies the target library.
                       native-lib
                        StaticTest      # 静态库编译链接
                  #     TestDynastic    #动态库编译链接,指定动态库名,去头lib去尾巴so
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

 

运行输出结果:

注意:
在4.4以上,如果load一个动态库,需要先将这个动态库的依赖的其他动态库load进来

6.0以下, System.loadLibrary  不会自动为我们加载依赖的动态库
6.0以上,System.loadLibrary  会自动为我们加载依赖动态库

发布了65 篇原创文章 · 获赞 61 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/dreams_deng/article/details/104540775