关于在Android中使用CMake你所需要了解的一切(二)

栏目: C · 发布时间: 5年前

内容简介:​ 这个在写JNI的时候就很常见了,比如json库,C++自己是没有提供json库的,然后我们在写JNI的时候,通常需要和上层交互数据,较简单的就是json了,那么就拿json来做讲解吧。首先来找一个json库啦!​OK,集成成功,但是太复杂,太麻烦了,每次要写那么一堆配置文件,少一个都不行,还要挨个的去改 include 想想都可怕,那么可不可以把这个jsoncpp打成库呢?那么我们就要考虑如下:

​ 这个在写JNI的时候就很常见了,比如json库,C++自己是没有提供json库的,然后我们在写JNI的时候,通常需要和上层交互数据,较简单的就是json了,那么就拿json来做讲解吧。首先来找一个json库啦!

jsoncpp 本篇就用这个json库来做讲解吧,首先把代码clone下来。

源码集成进项目中

  1. 将include里的json文件夹拷贝到../app/src/main/cpp目录下;

  2. 将src/lib_json里面的文件除去 CMakeLists.txt拷贝到../app/src/main/cpp目录下;

  3. 最终如下:

    关于在Android中使用CMake你所需要了解的一切(二)
  4. 修改../app/src/main/cpp/CMakeLists.txt如下:

    cmake_minimum_required(VERSION 3.4.1)
    add_library(
            native_hello
            SHARED
            json_tool.h
            json_reader.cpp
            json_valueiterator.inl
            json_value.cpp
            json_writer.cpp
            version.h.in
            # 下面的cpp若是没有则新建一个,本文基于上篇文章
            native_hello.cpp
    )
    target_link_libraries(
            native_hello
            android
            log
    )
    复制代码
  5. make build一下

    关于在Android中使用CMake你所需要了解的一切(二)

    What Are you!!!出错了,告诉在json_tool.h的第10行出错了,那行吧,点进去瞅一眼,如下:

    关于在Android中使用CMake你所需要了解的一切(二)

    哦,include错了,应该改为 #include “json/config.h” 那就改吧!cv过来的所有文件都得去查看一下(试想一下,若是cv过来的文件有1W个,咋办…,改完这个,将来别的地方在引用,又忘了那个曾经是改过的了,停!stop,我眼疼!)。

编写测试代码

  1. 打开../app/src/main/cpp/native_hello.cpp 更改如下:

    //
    // Created by xong on 2018/9/28.
    //
    #include<jni.h>
    #include "json/json.h"
    #define XONGFUNC(name)Java_com_xong_andcmake_jni_##name
    
    extern "C" JNIEXPORT
    jstring JNICALL
    XONGFUNC(NativeFun_outputJsonCode)(JNIEnv *env, jclass thiz,
                                        jstring jname, jstring jage, jstring jsex, jstring jtype)
    {
        Json::Value root;
        const char *name = env->GetStringUTFChars(jname, NULL);
        const char *age = env->GetStringUTFChars(jage, NULL);
        const char *sex = env->GetStringUTFChars(jsex, NULL);
        const char *type = env->GetStringUTFChars(jtype, NULL);
        root["name"] = name;
        root["age"] = age;
        root["sex"] = sex;
        root["type"] = type;
        
        env->ReleaseStringUTFChars(jname, name);
        env->ReleaseStringUTFChars(jage, age);
        env->ReleaseStringUTFChars(jsex, sex);
        env->ReleaseStringUTFChars(jtype, type);
    
        return env->NewStringUTF(root.toStyledString().c_str());
    }
    
    extern "C" JNIEXPORT
    jstring JNICALL
    XONGFUNC(NativeFun_parseJsonCode)(JNIEnv *env, jclass thiz,
                                       jstring jjson)
    {
        const char *json_str = env->GetStringUTFChars(jjson, NULL);
        std::string out_str;
    
        Json::CharReaderBuilder b;
        Json::CharReader *reader(b.newCharReader());
        Json::Value root;
        JSONCPP_STRING errs;
        bool ok = reader->parse(json_str, json_str + std::strlen(json_str), &root, &errs);
        if (ok && errs.size() == 0) {
            std::string name = root["name"].asString();
            std::string age = root["age"].asString();
            std::string sex = root["sex"].asString();
            std::string type = root["type"].asString();
            out_str = "name: " + name + "\nage: " + age + "\nsex:" + sex + "\ntype: " + type + "\n";
        }
        env->ReleaseStringUTFChars(jjson, json_str);
        return env->NewStringUTF(out_str.c_str());
    }
    复制代码
  2. 修改NativeFun类如下:

    package com.xong.andcmake.jni;
    
    /**
     * Create by xong on 2018/9/28
     */
    public class NativeFun {
    
        static {
            System.loadLibrary("native_hello");
        }
    
        public static native String outputJsonCode(String name, String age, String sex, String type);
    
        public static native String parseJsonCode(String json_str);
    }
    
    复制代码
  3. 测试:

    package com.xong.andcmake;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    import com.xong.andcmake.jni.NativeFun;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            TextView tv_native_content = findViewById(R.id.tv_native_content);
            String outPutJson = NativeFun.outputJsonCode("xong", "21", "man", "code");
            String parseJson = NativeFun.parseJsonCode(outPutJson);
            tv_native_content.setText("生成的Json:\n" + outPutJson + "\n解析:" + parseJson);
        }
    }
    复制代码

    结果如下图:

    关于在Android中使用CMake你所需要了解的一切(二)

编译成库文件

OK,集成成功,但是太复杂,太麻烦了,每次要写那么一堆配置文件,少一个都不行,还要挨个的去改 include 想想都可怕,那么可不可以把这个jsoncpp打成库呢?那么我们就要考虑如下:

  1. 必须使用CMake,不使用编写mk的方式;
  2. 在任何系统上都可以,不可在编译库的时候切换到其他系统;

好吧,基于以上两点,百度搜了一波,发现…GG,没有符合的哎,用CMake就得去 Linux 下面,且需要自己构建 工具 链,要不然就是…mk…。再去Google搜一搜,发现还是这样的,难道,不存在?再去GitHub搜,发现没有相关的,无可奈何,去Google提供的sample中找一找吧,哈!还真有发现,链接: hello-libs

编译so动态库

  1. 修改cpp目录为:

    关于在Android中使用CMake你所需要了解的一切(二)
  2. 修改../cpp/jsoncpp/目录中的CMakeLists.txt如下:

    cmake_minimum_required(VERSION 3.4.1)
    
    set(CMAKE_VERBOSE_MAKEFILE on)
    
    add_library(
    		# 库名字
    		jsoncpp
            # 库类型
    		SHARED
    		# 库包含的资源
            src/json_tool.h
            src/json_reader.cpp
            src/json_valueiterator.inl
            src/json_value.cpp
            src/json_writer.cpp
            src/version.h.in)
    
    # 导出目录 此处的设置 导出主目录在 Project/export文件夹内。
    set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export)
    
    set_target_properties(
    		# 库名字
            jsoncpp
            # 设置输出.so动态库的路径 
            PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${export_dir}/libsojsoncpp/lib/${ANDROID_ABI}")
    
    add_custom_command(
    		# POST_BUILD 处 有三个值可选
            # 分别是:
            # PRE_BUILD:在 hello 运行其他规则前执行
            # PRE_LINK:在编译源文件之后但在 链接其他二进制文件 或 运行静态库的库管理器 或 归档工具 之前执行
            # POST_BUILD:最后执行
            TARGET jsoncpp POST_BUILD
            
            # 拷贝命令 将 ${CMAKE_CURRENT_SOURCE_DIR}/src/json/allocator.h 文件拷贝到 ${export_dir}/libsojsoncpp/include/json/ 文件夹内 且名字和之前的相同
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/allocator.h" "${export_dir}/libsojsoncpp/include/json/allocator.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/config.h" "${export_dir}/libsojsoncpp/include/json/config.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/forwards.h" "${export_dir}/libsojsoncpp/include/json/forwards.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/features.h" "${export_dir}/libsojsoncpp/include/json/features.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/value.h" "${export_dir}/libsojsoncpp/include/json/value.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/reader.h" "${export_dir}/libsojsoncpp/include/json/reader.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/writer.h" "${export_dir}/libsojsoncpp/include/json/writer.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/assertions.h" "${export_dir}/libsojsoncpp/include/json/assertions.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/autolink.h"  "${export_dir}/libsojsoncpp/include/json/autolink.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/json.h"  "${export_dir}/libsojsoncpp/include/json/json.h"
    
            COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/src/json/version.h"  "${export_dir}/libsojsoncpp/include/json/version.h"
    
            )
    
    复制代码
  3. 修改 ../cpp/CMakeLists.txt如下:

    cmake_minimum_required(VERSION 3.4.1)
    
    set(CMAKE_VERBOSE_MAKEFILE on)
    
    # 设置资源主目录 CMAKE_CURRENT_SOURCE_DIR 代表当前CMakeLists.txt 所在的目录
    set(lib_src_DIR ${CMAKE_CURRENT_SOURCE_DIR})
    
    # 设置CMake编译后文件的存放的临时目录
    set(lib_build_DIR $ENV{HOME}/tmp)
    
    # 得到 lib_build_DIR 文件夹内文件
    file(MAKE_DIRECTORY ${lib_build_DIR})
    
    # 添加子目录
    add_subdirectory(${lib_src_DIR}/jsoncpp ${lib_build_DIR}/jsoncpp)
    
    复制代码
  4. 修改 ../app/build.gradle如下:

    apply plugin: 'com.android.application'
    
    android {
        ...
        defaultConfig {
    		...
            externalNativeBuild {
                cmake {
                    // 这里的名字最好和 ../cpp/jsoncpp/CMakeLists.txt 中设置的名字相同
                    targets 'jsoncpp'
                }
            ...
            }
        }
    	...
        externalNativeBuild {
            cmake {
                path 'src/main/cpp/CMakeLists.txt'
            }
        }
    }
    复制代码

说明:点击Build/Make Project(或者 Make Module 'app') 会在 项目根目录下 新建 export 文件夹 在里面会存放 库所需的头文件和so动态库。编译后如下:

关于在Android中使用CMake你所需要了解的一切(二)

so和头文件都生成了,但是我们在写../cpp/jsoncpp/CMakeLists.txt 文件时,也发现了,将所需的头文件导出到指定目录时有点儿费劲,只是名字换了下,若是用代码来写的话,一个for循环就可以了,那么在CMakeLists.txt中,可不可以实现类似的呢?哈哈,那当然是肯定的了,最终修改如下:

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_VERBOSE_MAKEFILE on)

add_library(
		jsoncpp 
		SHARED
        src/json_tool.h
        src/json_reader.cpp
        src/json_valueiterator.inl
        src/json_value.cpp
        src/json_writer.cpp
        src/version.h.in)

set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export)

set_target_properties(
        jsoncpp
        PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${export_dir}/libsojsoncpp/lib/${ANDROID_ABI}")

add_custom_command(
        TARGET jsoncpp POST_BUILD
        # 将 ${CMAKE_CURRENT_SOURCE_DIR}/src/json 文件夹下的文件 导出到 ${export_dir}/libajsoncpp/include/json/ 文件夹内
        COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/json" "${export_dir}/libsojsoncpp/include/json/")

复制代码

将之前生成的export文件夹删除,重新build发现是可以的。

OK,动态库可以编译成功,那么讲道理,静态库也是一样的,来尝试下编译静态库库。

编译a静态库

在以上编译so动态库的前提下,修改../cpp/jsoncpp/CMakeLists.txt如下:

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_VERBOSE_MAKEFILE on)

add_library(
        jsoncpp
        # 将 库 类型 由 SHARED 修改为 STATIC
        STATIC
        src/json_tool.h
        src/json_reader.cpp
        src/json_valueiterator.inl
        src/json_value.cpp
        src/json_writer.cpp
        src/version.h.in)

set(export_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../export)

set_target_properties(
        jsoncpp
        # 将 LIBRARY_OUTPUT_DIRECTORY 修改为 ARCHIVE_OUTPUT_DIRECTORY
        # 方便查看 生成的a文件目录修改一下 即 将 libsojsoncpp 修改为 libajsoncpp
        PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${export_dir}/libajsoncpp/lib/${ANDROID_ABI}")

add_custom_command(
        TARGET jsoncpp POST_BUILD
        COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/src/json" "${export_dir}/libajsoncpp/include/json/"
)
复制代码

修改完成后,Build/Make Project(或者 Make Module 'app') 会在 Project/export目录下生成:

关于在Android中使用CMake你所需要了解的一切(二)

这样编译.a静态库和.so动态库就完成了。

下篇我们讲如何链接 生成的so动态库和a静态库,以及动态库和静态库的区别;点击调转到下一篇:

CMake链接a静态库以及so动态库及动态库和静态库的区别

Demo链接: UseCmakeBuildLib

END


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

プログラミングコンテストチャレンジブック

プログラミングコンテストチャレンジブック

秋葉 拓哉、岩田 陽一、北川 宜稔 / 毎日コミュニケーションズ / 2010-09-11 / JPY 34.44

現在、プログラミングコンテストは数多く開催されています。Google Code Jam、TopCoder、ACM/ICPCなどの名前を聞いたことがある人も少なくないでしょう。本書で扱うのはそれらのような、問題を正確にできるだけ多く解くことを競うプログラミングコンテストです。 プログラミングコンテストは気軽に参加することができます。例えば、Google Code JamやTopCoderはイン......一起来看看 《プログラミングコンテストチャレンジブック》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

SHA 加密
SHA 加密

SHA 加密工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换