Transmission Android CmakeList编译过程


简介

上一篇文章中介绍了怎么样在ubuntu下面的采用Ndk,交叉编译链,编译transmission,这篇文章将介绍怎么在Android Studio下面采用CmakeList的方式来编译transmission库,至于为什么要在
android Studio中编译是为了我们开发的方便,在Android Studio中采用最新的CmakeList编译的化,是支持断点调试代码,方便我们阅读,修改代码

移植Transmission遇到的问题

既然要移植到Android Studio下面,那么就涉及到要编译哪些文件,还有编译需要的链接的参数,定义的宏等,这些都是我们需要采集的
因为Transmission是采用autoconf来维护,自动的生成Makefile的,所以我们可以参考Ubuntu交叉编译之后产生Makefile文件,从里面采集我们需要的这些信息

还记得前面一篇文章中介绍到在编译libevent库的时候采用的NDKr10e ,那是因为Ndk11以上有对这些函数做调整,但是在Android Studio中如果想采用CmakeList来编译的化,最低的Ndk版本不能低于r12要不然会提示下面的这些错误

CMake Error at D:/sdk/sdk/cmake/3.6.4111459/android.toolchain.cmake:345 (message):
  Missing file:
  D:/sdk/android-ndk-r10e-windows-x86_64/android-ndk-r10e/source.properties.
  Please use NDK r12+.
Call Stack (most recent call first):
  D:/sdk/sdk/cmake/3.6.4111459/share/cmake-3.6/Modules/CMakeDetermineSystem.cmake:98 (include)
  CMakeLists.txt
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage

所以我们必须要将libevent库采用Ndr12以上来编译,那么这就意味着,我们不能逃避在编译libevent库试出现的 找不到arc4random_addrandom实现的问题,更多的详细信息可以参考

https://github.com/android-ndk/ndk/issues/48
通过上面介绍可知,ndk中是有头文件的,但是确找不到对应的实现,下面介绍怎么解决这个问题,这个函数触发是在evutil_rand.c文件中,有这样的代码

evutil_rand.c 中有这样的实现

#ifdef EVENT__HAVE_ARC4RANDOM
.....
#else /* !EVENT__HAVE_ARC4RANDOM { */
....
#include "./arc4random.c"
....
#endif /* } !EVENT__HAVE_ARC4RANDOM */

其中arc4random.c文件中就有定义这个函数
#ifndef ARC4RANDOM_NOADDRANDOM
ARC4RANDOM_EXPORT void
arc4random_addrandom(const unsigned char *dat, int datlen)
{
    int j;
    ARC4_LOCK_();
    if (!rs_initialized)
        arc4_stir();
    for (j = 0; j < datlen; j += 256) {
        /* arc4_addrandom() ignores all but the first 256 bytes of
         * its input.  We want to make sure to look at ALL the
         * data in 'dat', just in case the user is doing something
         * crazy like passing us all the files in /var/log. */
        arc4_addrandom(dat + j, datlen - j);
    }
    ARC4_UNLOCK_();
}
#endif

evutil_rand.c文件中,有这样的代码,这就是触发调用的入口
void
evutil_secure_rng_add_bytes(const char *buf, size_t n)
{
    arc4random_addrandom((unsigned char*)buf,
        n>(size_t)INT_MAX ? INT_MAX : (int)n);
}

通过上面可以知道,如果EVENT__HAVE_ARC4RANDOM = 0,也即是没有定义这个宏的时候,就会将arc4random.c 包含进来,这样 arc4random_addrandom 就会有定义了,下面查看一下这个宏是怎么产生的,由于transmission是采用autoconf来维护的,在他生成makefile文件之前,要先通过configure文件的检查,这个文件主要是检查当前的系统的环境,下面是configure.ac文件的内容

dnl Checks for library functions.
AC_CHECK_FUNCS([ \
  accept4 \
  arc4random \
  arc4random_buf \
  eventfd \
  ...
])
AC_CHECK_FUNCS:检查C标准库中是否存在函数。 如果找到,则定义预处理器宏HAVE_ [function]。它生成一个测试程序,声明一个具有相同名称的函数,然后编译并链接它。

关于autocof语法可以参考 https://aheadsnail.github.io/2018/04/11/AutoConfig-%E5%B8%B8%E8%A7%81%E7%9A%84%E5%AE%8F%E8%AF%A6%E8%A7%A3/

所以上面会去检查系统是否中是否有arc4random 函数,如果有就会定义宏,这些宏生成在event-config.h文件中
/* Define to 1 if you have the `arc4random' function. */
#define EVENT__HAVE_ARC4RANDOM 1
/* Define to 1 if you have the `arc4random_buf' function. */
#define EVENT__HAVE_ARC4RANDOM_BUF 1

通过生成的event-config.h文件可以知道,系统是可以检测到这个函数的,所以会将EVENT__HAVE_ARC4RANDOM 置为1,这样在使用的时候,就会以为有这个函数存在去使用系统的函数,但本质是这个函数
在NDK中是只有声明,并没有定义,所以会在编译libevent库的时候出现找不到实现的问题,系统的函数这个检测我们是没有办法干预的,但是我们可以在使用这个宏的时候,手动的让这个宏改为0,这样
就会以为系统没有这个函数,libevent自己定义这个函数,因为会走 #include "./arc4random.c"

下面是修改的内容:
#undef EVENT__HAVE_ARC4RANDOM //手动的取消这个宏
#ifdef EVENT__HAVE_ARC4RANDOM
....
修改完之后,重新进行编译,发现又出现了

从错误的信息可以看出来,这个函数的定义跟系统的这个对应的这个函数重定义了,系统的函数肯定是不能修改的,那么我们就有必要修改libevent库的函数,就改一个名字而已,下面是修改的内容

arc4random.c中总的要修改下面的内容
#ifndef ARC4RANDOM_NOADDRANDOM
ARC4RANDOM_EXPORT void
my_arc4random_addrandom(const unsigned char *dat, int datlen)
{
    int j;
    ARC4_LOCK_();
    if (!rs_initialized)
        arc4_stir();
    for (j = 0; j < datlen; j += 256) {
        /* arc4_addrandom() ignores all but the first 256 bytes of
         * its input.  We want to make sure to look at ALL the
         * data in 'dat', just in case the user is doing something
         * crazy like passing us all the files in /var/log. */
        arc4_addrandom(dat + j, datlen - j);
    }
    ARC4_UNLOCK_();
}
#endif

evutil_rand.c中总的要修改的内容:
#undef EVENT__HAVE_ARC4RANDOM //手动的取消这个宏
#ifdef EVENT__HAVE_ARC4RANDOM
....

void
evutil_secure_rng_add_bytes(const char *buf, size_t n)
{
    my_arc4random_addrandom((unsigned char*)buf,
        n>(size_t)INT_MAX ? INT_MAX : (int)n);
}

修改完之后,重新编译,通过了,至此这个库已经修改完成

编译transmission,遇到下面的这个问题

经查阅这个函数也是NDK的一个坑,详细信息可以参考
endpowent https://github.com/android-ndk/ndk/issues/77

这个函数在系统的头文件pwd.h文件中,跟他一起配套使用的方式是getpwuid,endpwent函数一般用来关闭用getpwent打开的密码文件。从上面的文章中可知这个函数是没有实现的,那我们可以在Android的源码中查找这个函数,因为这个是系统的库,那么这个函数肯定存在android的源码中

查找的结果

其中有这样的查询结果 /bionic/libc/bionic/ndk_cruft.cpp:void endpwent() { },我们可以进入对应的目录找到这个文件,下面是关键的内容

// This was never implemented in bionic, only needed for ABI compatibility with the NDK.
// In the M time frame, over 1000 apps have a reference to this!
void endpwent() { }

// This was removed from BSD.
void arc4random_stir(void) {
  // The current implementation stirs itself as needed.
}

// This was removed from BSD.
void arc4random_addrandom(unsigned char*, int) {
  // The current implementation adds randomness as needed.
}

可以看到这些函数都是连接找不到实现的,都在同一个文件,而跟endpwent 配套使用的 getpwuid 函数的实现是在 ./bionic/libc/bionic/stubs.cpp 目录
passwd* getpwuid(uid_t uid) { // NOLINT: implementing bad function.
  passwd_state_t* state = g_passwd_tls_buffer.get();
  if (state == NULL) {
    return NULL;
  }

  passwd* pw = android_id_to_passwd(state, uid);
  if (pw != NULL) {
    return pw;
  }
  // Handle OEM range.
  pw = oem_id_to_passwd(uid, state);
  if (pw != NULL) {
    return pw;
  }
  return app_id_to_passwd(uid, state);
}

可以看到这个函数是有实现的,而且这个函数跟前面的endpwent并不在同一个文件,而且在查找google的测试代码中,也并没有调用endpwent 这个函数,下面是测试的代码
static void check_getpwuid_r(const char* username, uid_t uid, uid_type_t uid_type) {
  passwd pwd_storage;
  char buf[512];
  int result;

  errno = 0;
  passwd* pwd = NULL;
  result = getpwuid_r(uid, &pwd_storage, buf, sizeof(buf), &pwd);
  ASSERT_EQ(0, result);
  ASSERT_EQ(0, errno);
  SCOPED_TRACE("getpwuid_r");
  check_passwd(pwd, username, uid, uid_type);
}

通过上面的内容,我们可以直接,简单的将这个函数屏蔽掉,这样就可以编译通过了,最终生成下面的内容

Android CmakeList的编写

cmake_minimum_required(VERSION 3.4.1)

#设置变量 自定义变量使用SET(OBJ_NAME xxxx),使用时${OBJ_NAME}
set(My_ARIC_SRC ${CMAKE_SOURCE_DIR}/src/main/cpp/src)
#message( WARNING  "${My_ARIC_SRC}")

#定义宏
add_definitions( -Din_addr_t=uint32_t
 -D__android__
 -Din_port_t=uint16_t
 -D__TRANSMISSION__
 -DPACKAGE_DATA_DIR="${CMAKE_SOURCE_DIR}"
 -DPACKAGE_NAME=\"transmission\"
 -DPACKAGE_TARNAME=\"transmission\"
 -DPACKAGE_VERSION=\"2.94\"
 -DPACKAGE_STRING=\"transmission\ 2.94\"
 -DPACKAGE_BUGREPORT=\"https://github.com/transmission/transmission\"
 -DPACKAGE_URL=\"\"
 -DPACKAGE=\"transmission\"
 -DVERSION=\"2.94\"
 -DSTDC_HEADERS=1
 -DHAVE_SYS_TYPES_H=1
 -DHAVE_SYS_STAT_H=1
 -DHAVE_STDLIB_H=1
 -DHAVE_STRING_H=1
 -DHAVE_MEMORY_H=1
 -DHAVE_STRINGS_H=1
 -DHAVE_INTTYPES_H=1
 -DHAVE_STDINT_H=1
 -DHAVE_UNISTD_H=1
 -DHAVE_DLFCN_H=1
 -DLT_OBJDIR=\".libs/\"
 -DSTDC_HEADERS=1
 -DTIME_WITH_SYS_TIME=1
 -DHAVE_STDBOOL_H=1
 -DHAVE_PREAD=1
 -DHAVE_PWRITE=1
 -DHAVE_STRLCPY=1
 -DHAVE_DAEMON=1
 -DHAVE_DIRNAME=1
 -DHAVE_BASENAME=1
 -DHAVE_STRCASECMP=1
 -DHAVE_LOCALTIME_R=1
 -DHAVE_MEMMEM=1
 -DHAVE_STRSEP=1
 -DHAVE_SYSLOG=1
 -DHAVE_VALLOC=1
 -DHAVE_POSIX_MEMALIGN=1
 -DHAVE_MKDTEMP=1
 -DHAVE_PTHREAD=1
 -DHAVE_GETMNTENT=1
 -DHAVE_DECL_POSIX_FADVISE=0
 -DWITH_UTP=1
 -DGETTEXT_PACKAGE=\"transmission-gtk\"
 -DHAVE_LOCALE_H=1
 -DHAVE_LC_MESSAGES=1
 -DTR_LIGHTWEIGHT=1
 -DENABLE_STRNATPMPERR
 )

#添加头文件的查找目录
include_directories(
${CMAKE_SOURCE_DIR}/src/main/cpp/src/include
${CMAKE_SOURCE_DIR}/src/main/cpp/src/include/libtransmission
${CMAKE_SOURCE_DIR}/src/main/cpp/src/third-party/libb64
${CMAKE_SOURCE_DIR}/src/main/cpp/src/third-party/libutp
${CMAKE_SOURCE_DIR}/src/main/cpp/src/third-party
${CMAKE_SOURCE_DIR}/src/main/cpp/src/third-party/libnatpmp
)

#用来输出参数 ${CMAKE_SOURCE_DIR} 代表的就为CmakeList的路径,这里即为app目录
#message( WARNING  "${CMAKE_SOURCE_DIR}")

#add_library():添加库,分为两种,一种是需要编译为库的代码,一种是已经编译好的库文件。 一般.so文件,还有STATIC,一般.a文件。IMPORTED表示引用的不是生成的。
add_library( open-event
             STATIC
             IMPORTED)

# set_target_properties:对于已经编译好的so文件需要引入,所以需要设置 这里cares是名字,然后是PROPERTIES IMPORTED_LOCATION加上库的路径。
set_target_properties( open-event
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libevent.a )

add_library( open-event_core
             STATIC
             IMPORTED)

set_target_properties( open-event_core
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libevent_core.a )

add_library( open-event_extra
             STATIC
             IMPORTED)

set_target_properties( open-event_extra
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libevent_extra.a )

add_library( open-event_openssl
             STATIC
             IMPORTED)

set_target_properties( open-event_openssl
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libevent_openssl.a )

add_library( open-event_potheads
             STATIC
             IMPORTED)

set_target_properties( open-event_potheads
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libevent_pthreads.a )

# 添加两个预编译库
add_library(openssl-crypto
    STATIC
    IMPORTED)

set_target_properties(openssl-crypto
                      PROPERTIES IMPORTED_LOCATION
                      ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libcrypto.a )

add_library(openssl-ssl
  STATIC
  IMPORTED)

set_target_properties(openssl-ssl
                    PROPERTIES IMPORTED_LOCATION
                    ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libssl.a )

add_library( open-curl
             STATIC
             IMPORTED)

set_target_properties( open-curl
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libcurl.a )

add_library( open-z
             STATIC
             IMPORTED)

set_target_properties( open-z
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/cpp/lib/libz.a )

#dht的源码
set(dht_src ${My_ARIC_SRC}/third-party/dht/dht.c )

#libb64的源码
set(bb64_src ${My_ARIC_SRC}/third-party/libb64/cdecode.c  ${My_ARIC_SRC}/third-party/libb64/cencode.c )

#libnatpmp的源码
set(natpmp_src ${My_ARIC_SRC}/third-party/libnatpmp/getgateway.c
        ${My_ARIC_SRC}/third-party/libnatpmp/natpmp.c
        ${My_ARIC_SRC}/third-party/libnatpmp/wingettimeofday.c )

#libutp的源码
set(utp_src ${My_ARIC_SRC}/third-party/libutp/utp.cpp  ${My_ARIC_SRC}/third-party/libutp/utp_utils.cpp )

#miniupnp的源码
set(miniupnp_src ${My_ARIC_SRC}/third-party/miniupnp/connecthostport.c
       ${My_ARIC_SRC}/third-party/miniupnp/igd_desc_parse.c
       ${My_ARIC_SRC}/third-party/miniupnp/minisoap.c
       ${My_ARIC_SRC}/third-party/miniupnp/minissdpc.c
       ${My_ARIC_SRC}/third-party/miniupnp/miniupnpc.c
       ${My_ARIC_SRC}/third-party/miniupnp/miniwget.c
       ${My_ARIC_SRC}/third-party/miniupnp/minixml.c
       ${My_ARIC_SRC}/third-party/miniupnp/portlistingparse.c
       ${My_ARIC_SRC}/third-party/miniupnp/receivedata.c
       ${My_ARIC_SRC}/third-party/miniupnp/upnpcommands.c
       ${My_ARIC_SRC}/third-party/miniupnp/upnpreplyparse.c
       )

#libtransmission的源码
set(libtransmission_src
        ${My_ARIC_SRC}/libtransmission/announcer.c
        ${My_ARIC_SRC}/libtransmission/announcer-http.c
        ${My_ARIC_SRC}/libtransmission/announcer-udp.c
        ${My_ARIC_SRC}/libtransmission/bandwidth.c
        ${My_ARIC_SRC}/libtransmission/bitfield.c
        ${My_ARIC_SRC}/libtransmission/blocklist.c
        ${My_ARIC_SRC}/libtransmission/cache.c
        ${My_ARIC_SRC}/libtransmission/clients.c
        ${My_ARIC_SRC}/libtransmission/completion.c
        ${My_ARIC_SRC}/libtransmission/ConvertUTF.c
        ${My_ARIC_SRC}/libtransmission/crypto.c
        ${My_ARIC_SRC}/libtransmission/crypto-utils.c
        ${My_ARIC_SRC}/libtransmission/crypto-utils-fallback.c
        ${My_ARIC_SRC}/libtransmission/error.c
        ${My_ARIC_SRC}/libtransmission/fdlimit.c
        ${My_ARIC_SRC}/libtransmission/file.c
        ${My_ARIC_SRC}/libtransmission/handshake.c
        ${My_ARIC_SRC}/libtransmission/history.c
        ${My_ARIC_SRC}/libtransmission/inout.c
        ${My_ARIC_SRC}/libtransmission/list.c
        ${My_ARIC_SRC}/libtransmission/log.c
        ${My_ARIC_SRC}/libtransmission/magnet.c
        ${My_ARIC_SRC}/libtransmission/makemeta.c
        ${My_ARIC_SRC}/libtransmission/metainfo.c
        ${My_ARIC_SRC}/libtransmission/natpmp.c
        ${My_ARIC_SRC}/libtransmission/net.c
        ${My_ARIC_SRC}/libtransmission/peer-io.c
        ${My_ARIC_SRC}/libtransmission/peer-mgr.c
        ${My_ARIC_SRC}/libtransmission/peer-msgs.c
        ${My_ARIC_SRC}/libtransmission/platform.c
        ${My_ARIC_SRC}/libtransmission/platform-quota.c
        ${My_ARIC_SRC}/libtransmission/port-forwarding.c
        ${My_ARIC_SRC}/libtransmission/ptrarray.c
        ${My_ARIC_SRC}/libtransmission/quark.c
        ${My_ARIC_SRC}/libtransmission/resume.c
        ${My_ARIC_SRC}/libtransmission/rpcimpl.c
        ${My_ARIC_SRC}/libtransmission/rpc-server.c
        ${My_ARIC_SRC}/libtransmission/session.c
        ${My_ARIC_SRC}/libtransmission/stats.c
        ${My_ARIC_SRC}/libtransmission/torrent.c
        ${My_ARIC_SRC}/libtransmission/torrent-ctor.c
        ${My_ARIC_SRC}/libtransmission/torrent-magnet.c
        ${My_ARIC_SRC}/libtransmission/tr-dht.c
        ${My_ARIC_SRC}/libtransmission/tr-lpd.c
        ${My_ARIC_SRC}/libtransmission/tr-udp.c
        ${My_ARIC_SRC}/libtransmission/tr-utp.c
        ${My_ARIC_SRC}/libtransmission/tr-getopt.c
        ${My_ARIC_SRC}/libtransmission/trevent.c
        ${My_ARIC_SRC}/libtransmission/upnp.c
        ${My_ARIC_SRC}/libtransmission/utils.c
        ${My_ARIC_SRC}/libtransmission/variant.c
        ${My_ARIC_SRC}/libtransmission/variant-benc.c
        ${My_ARIC_SRC}/libtransmission/variant-json.c
        ${My_ARIC_SRC}/libtransmission/verify.c
        ${My_ARIC_SRC}/libtransmission/watchdir.c
        ${My_ARIC_SRC}/libtransmission/watchdir-generic.c
        ${My_ARIC_SRC}/libtransmission/web.c
        ${My_ARIC_SRC}/libtransmission/webseed.c
        ${My_ARIC_SRC}/libtransmission/wildmat.c
        ${My_ARIC_SRC}/libtransmission/watchdir-inotify.c
        ${My_ARIC_SRC}/libtransmission/file-posix.c
        ${My_ARIC_SRC}/libtransmission/crypto-utils-openssl.c
        )


#daemon的源码
set(daemon_src ${My_ARIC_SRC}/daemon/daemon.c
 ${My_ARIC_SRC}/daemon/daemon-posix.c
 ${My_ARIC_SRC}/daemon/remote.c )

#cli的源码
set(cli_src ${My_ARIC_SRC}/cli/cli.c )

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 )

add_library( # Sets the name of the library.
             transmission

             # Sets the library as a shared library.
             SHARED

            ${dht_src}
            ${bb64_src}
            ${natpmp_src}
            ${utp_src}
            ${miniupnp_src}
            ${libtransmission_src}
            ${daemon_src}
            ${cli_src}

            #自己的源码文件
            src/main/cpp/jni_interface.cpp
            )


#链接库文件,第一个代表要生成的target,后面的item为要连接的item,对于如果是通过 IMPORTED_NO_SONAME的方式来导入的
#这里注意不推荐使用全路径的方式来导入,一般要通过set_target_properties来指定
target_link_libraries( transmission

                       # Links the target library to the log library
                       # included in the NDK.

                       ${log-lib}
                       open-z
                       open-event
                       open-event_core
                       open-event_extra
                       open-event_openssl
                       open-event_potheads
                       open-curl
                       #最后一个openssl 库文件要放在最后来连接。。。要不然会出现找不到函数的定义问题。。。注意
                       openssl-ssl openssl-crypto
                       )

目录工程为:

编译的结果为:

验证是否可以真的下载

官网的transmission中有一个cli模块,这个是一个命令行模式的,通过了解他的代码,需要传递的参数,大致下了个简单的demo,验证是否可以真的下载

@Override
public void onClick(View view)
{
    switch (view.getId())
    {
        case R.id.but_start:
            //是否有权限
            if (PermissionManager.getInstance().isHasNecessaryPermissions(this))
            {
                String[] commands = new String[3];
                //第一个参数
                //设置下载文件保存的目录
                commands[0] = "-w=" + FileUtils.getTransmissionDataPath();
                commands[1] = "-g=" + FileUtils.getTransmissionConfigPath();
                //设置种子文件的路径
                commands[2] = FileUtils.getTransmissionTorrentPath();
                Transmission.initTransmission(commands);
            }
            else
            {
                Toast.makeText(MainActivity.this,"没有权限",Toast.LENGTH_SHORT).show();
            }
            break;
    }
}
上面是传递的参数,至于这些要传递什么参数,只能去看cli.c的代码,上面是我了解之后,需要传递的参数

/**
 * 初始化Transmission
*/
public static native int initTransmission(String[] pArgs);

/**
 * 初始化Transmission,开启线程
 * @param env
 * @param jstr
 */
JNIEXPORT jint JNICALL Java_com_example_com_transmissionandroidproject_Transmission_initTransmission
        (JNIEnv * env, jclass jstr,jobjectArray pArgs)
{
    //pArgs 传递的是命令参数
    argc = env->GetArrayLength(pArgs);
    LOGD("pArgs length %d", argc);

    //将java对应的每一个参数解析到char * argv数组中
    for (int i = 0; i < argc; i++) {
        jstring js = (jstring) env->GetObjectArrayElement(pArgs, i);
        argv[i] = (char *) env->GetStringUTFChars(js, 0);
        LOGD("pArgs argv %s", argv[i]);
    }

    int rev = 0;
    //2创建子线程,用于下载,检测等,创建成功之后,就会执行run的回调
    if (pthread_create(&pthread_tid, NULL, run, NULL)) {
        //创建失败
        LOGD("cannot create the thread\n");
        pthread_detach(pthread_tid);
        rev = 1;
        return rev;
    }
    return rev;
}

对应的C源码实现

extern "C" {
extern int cli_tr_main(int argc, char *argv[]);
}

/**
 * 线程执行的方法回调
 * @param pVoid
 * @return
 */
void *run(void *pVoid) {
    cli_tr_main(argc, argv);
    return NULL;
}

//命令行的入口函数 这个是cli.c文件的main 函数,这里直接改了个函数名
int cli_tr_main (int argc, char * argv[])
{
  tr_session  * h;
  tr_ctor     * ctor;
  tr_torrent  * tor = NULL;
  tr_variant       settings;
  const char  * configDir;
  uint8_t     * fileContents;
  size_t        fileLength;
  const char  * str;

  .....
}

下面是下载的结果,可以看出来,我们的移植是没有出现问题的


文章作者: AheadSnail
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AheadSnail !
评论
  目录