Cygwin+NDK编译curl+openssl源码库(静态)

本文详细介绍了如何使用Cygwin+NDK环境编译curl及openssl源码库,包括搭建编译环境、修改Android.mk文件、生成配置文件等步骤,并提供了编译好的库文件的应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Cygwin+NDK编译curl源码库   

1、curl相关链接 

    主页:http://www.curl.haxx.se/

    下载:http://curl.haxx.se/download/curl-7.37.1.tar.gz

2、openssl相关链接 

下载:http://download.youkuaiyun.com/detail/lsq19871207/7730949

3、编译参考的地址: 
http://blog.youkuaiyun.com/choujs/archive/2010/02/10/5304978.aspx

http://blog.youkuaiyun.com/liushilei/archive/2010/04/15/5488107.aspx 

http://curl.haxx.se/mail/lib-2009-12/0071.html

http://blog.youkuaiyun.com/someonea/article/details/6312213

4、编译

4.1 、编译环境搭建

   本文建立在Cgywin+NDK编译环境已搭建好的基础之上(我的是 Cygwin +android-ndk32-r10),安装目录如下:

    D:/NDK

       android-ndk-r10

       cygwin64

4.2 编译openssl

4.2.1 建立OpenSSL工程目录

    在NDK安装目录下建立如下目录:D:\NDK\android-ndk-r10\apps\OpenSSL,把从http://download.youkuaiyun.com/detail/lsq19871207/7730949下载的OpenSSL1.0.1cForAndroid.zip解压到上述目录路径下,目录结构如下图所示:


4.2.2编译openssl静态库

openssl默认编译成动态库.so文件,如果想编译成静态库.o文件,需要修改相应的Android.mk文件:

(1)OpenSSL/crypto/Android.mk:

a把“target” 和“host shared library”的编译选项统统注释掉,只留下“host static library”编译选项,并把include $(BUILD_SHARED_LIBRARY) 修改为 include$(BUILD_STATIC_LIBRARY)

b另外还需要连接libz,加上下面的一句

LOCAL_LDLIBS += -lz

c、Android.mk文件大致如下:

LOCAL_PATH:=$(call my-dir)
arm_cflags :=-DOPENSSL_BN_ASM_MONT -DAES_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM
arm_src_files := \
   aes/asm/aes-armv4.S \
   bn/asm/armv4-mont.S \
   sha/asm/sha1-armv4-large.S \
   sha/asm/sha256-armv4.S \
   sha/asm/sha512-armv4.S
non_arm_src_files := aes/aes_core.c
local_src_files := \
    cryptlib.c\
    mem.c\
    mem_clr.c\
    mem_dbg.c\
    ………\
    ………\
………\
local_c_includes := \
    $(NDK_PROJECT_PATH) \
    $(NDK_PROJECT_PATH)/crypto/asn1 \
    $(NDK_PROJECT_PATH)/crypto/evp \
    $(NDK_PROJECT_PATH)/include \
    $(NDK_PROJECT_PATH)/include/openssl \
    $(NDK_PROJECT_PATH)/../include
local_c_flags := -DNO_WINDOWS_BRAINDEATH
include$(CLEAR_VARS)
include$(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES += $(local_src_files)
LOCAL_CFLAGS += $(local_c_flags)-DPURIFY
LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_SRC_FILES += $(non_arm_src_files)
LOCAL_LDLIBS += -lz
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:=libcrypto
include $(BUILD_STATIC_LIBRARY)


(2)OpenSSL/ssl/Android.mk:

a把所有的include$(BUILD_SHARED_LIBRARY) 修改为 include$(BUILD_STATIC_LIBRARY)

b、ssl需要crypto的支持,因此需要引用libcrypto库

    LOCAL_STATIC_LIBRARIES+= libcrypto

cssltest还需要连接libz,并且需要crypto和ssl库的支持,因此加上下面的两句

    LOCAL_STATIC_LIBRARIES = libcryptolibssl

LOCAL_LDLIBS += -lz

d、Android.mk文件大致如下:

LOCAL_PATH:=$(call my-dir)
local_c_includes := \
    $(NDK_PROJECT_PATH) \
    $(NDK_PROJECT_PATH)/include \
    $(NDK_PROJECT_PATH)/crypto \
    $(NDK_PROJECT_PATH)/../include
local_src_files:= \
    s2_meth.c\
    s2_srvr.c\
    s2_clnt.c\
    ………\
    ………\
………\
include$(CLEAR_VARS)
include$(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES += $(local_src_files)
LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_STATIC_LIBRARIES += libcrypto
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE:=libssl
include$(BUILD_STATIC_LIBRARY)
 
ifeq($(WITH_HOST_DALVIK),true)
   include $(CLEAR_VARS)
   include $(LOCAL_PATH)/../android-config.mk
   LOCAL_SRC_FILES +=$(local_src_files)
   LOCAL_C_INCLUDES +=$(local_c_includes)
   LOCAL_STATIC_LIBRARIES += libcrypto
   LOCAL_MODULE_TAGS :=optional
   LOCAL_MODULE:=libssl
   include $(BUILD_STATIC_LIBRARY)
endif
 
# ssltest
include$(CLEAR_VARS)
include$(LOCAL_PATH)/../android-config.mk
LOCAL_SRC_FILES:= ssltest.c
LOCAL_C_INCLUDES += $(local_c_includes)
LOCAL_STATIC_LIBRARIES = libssl libcrypto
LOCAL_LDLIBS += -lz
LOCAL_MODULE:=ssltest
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)


(3)OpenSSL/app/Android.mk:

aopenssl需要连接libz,并且需要crypto和ssl库的支持,因此加上下面几句:

       LOCAL_STATIC_LIBRARIES = \

Libcrypto\

libssl

LOCAL_LDLIBS += -lz

b、Android.mk文件大致如下:

LOCAL_PATH:=$(call my-dir)
include$(CLEAR_VARS)
LOCAL_SRC_FILES:= \
    app_rand.c\
    apps.c\
    asn1pars.c\
    ca.c\
    ciphers.c\
    ………\
    ………\
………\
LOCAL_STATIC_LIBRARIES := \
    libssl\
    libcrypto
LOCAL_C_INCLUDES := \
    $(NDK_PROJECT_PATH) \
    $(NDK_PROJECT_PATH)/include \
    $(NDK_PROJECT_PATH)/../include
LOCAL_CFLAGS := -DMONOLITH
include$(LOCAL_PATH)/../android-config.mk
LOCAL_CFLAGS += -DOPENSSL_NO_DTLS1
LOCAL_MODULE:=openssl
LOCAL_MODULE_TAGS := tests
LOCAL_LDLIBS += -lz
include $(BUILD_EXECUTABLE)


(4)OpenSSL/jni/Application.mk:

默认只生成armeabi版本的静态库,如果需要生成armeabi-v7a或者x86版本的静态库,需要手动修改OpenSSL/jni/Application.mk文件:

APP_ABI :=armeabi armeabi-v7a x86
APP_PROJECT_PATH := $(shell pwd)
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/Android.mk

注意:android-config.mk文件预定义了一些宏,万不可注释掉,否则编译的过程中会出现由于宏开关问题造成的函数找不到错误!

4.2.3执行编译

    启动cygwin,命令行输入 “cd /cygdrive/d/ndk/android-ndk-r10/apps/OpenSSL”即可进入到刚刚建立的工程目录,执行“ndk-build”命令,即可编译。备注:cd /cygdrive表示进入当前Cygwin安装的磁盘,这时候执行ls命令,仅显示Cygwin安装路径的盘符;例如我的安装路径在d盘下,所以“cd/cygdrive/d”就直接进入到d盘了;

4.3 编译curl

4.3.1 建立工程目录

       在NDK安装目录下建立如下目录:D:\NDK\android-ndk-r10\apps\curl\jni,把下载的curl-7.37.1.tar.gz解压到D:\NDK\android-ndk-r10\apps\curl\jni目录下,目录结构如下图所示:


注意:一定要新建jni目录,并把curl源码文件放到jni目录下,否则编译的时候会出现Android NDK: Could not find application project directory !错误,原因就是在于Application.mk文件必须放在jni文件夹下

 4.3.2 生成curl_config.h文件

         1、要创建一个头文件curl_config.h。创建方法在jni/packages/Android/Android.mk文件头部的注释里有说明。启动Cygwin,命令行输入 “cd /cygdrive/d/ndk/android-ndk-r10/apps/curl/jni/”即可进入到刚刚建立的工程目录。

    2、进入cd /cygdrive/d/ndk/android-ndk-r10/apps/curl/jni/后,执行”./configure“命令,经过漫长的checking后即可在jni/lib目录下生成curl_config.h文件

4.3.3、修改curl_config.h文件

    (1) configure找不到openssl,所以所生成的配置文件是不使用openssl的,关于openssl相关的宏默认都是关闭状态,因此我们需要打开相关openssl的宏:

    打开:HAVE_LIBSSL(#define HAVE_LIBSSL 1) HAVE_OPENSSL_CRYPTO_HHAVE_OPENSSL_ERR_HHAVE_OPENSSL_PEM_H HAVE_OPENSSL_PKCS12_HHAVE_OPENSSL_RSA_HHAVE_OPENSSL_SSL_H HAVE_OPENSSL_X509_HUSE_OPENSSLUSE_SSLEAY

注意:android没有编译openssl中的 engine,因此关掉HAVE_OPENSSL_ENGINE_H

    (2) 注释掉宏定义HAVE_MALLOC_H和HAVE_IOCTL

    (3) 注释掉宏 HAVE_GETPWUID_R 、HAVE_GETEUID、HAVE_GETPWUID,否则编译的时候会出现类似:/lib/netrc.c:84: error: undefined reference to 'getpwuid_r'之类的错误

    (4) 64位和32位宏控制:把SIZEOF_LONG 、SIZEOF_OFF_TSIZEOF_SIZE_T、SIZEOF_TIME_T、SIZEOF_VOIDP做如下修改,否则会出现类似”cur/curlrules.h:134: error: size ofarray __curl_rule_01__ is negative“之类的编译错误

/* The size of `long', as computed by sizeof. */
#ifdef __arch64__
#define SIZEOF_LONG 8
#else
#define SIZEOF_LONG 4
#endif
 
/* The size of `off_t', as computed by sizeof. */
#ifdef __arch64__
#define SIZEOF_OFF_T 8
#else
#define SIZEOF_OFF_T 4
#endif
 
/* The size of `size_t', as computed by sizeof. */
#ifdef __arch64__
#define SIZEOF_SIZE_T 8
#else
#define SIZEOF_SIZE_T 4
#endif
 
/* The size of `time_t', as computed by sizeof. */
#ifdef __arch64__
#define SIZEOF_TIME_T 8
#else
#define SIZEOF_TIME_T 4
#endif
 
/* The size of `void*', as computed by sizeof. */
#ifdef __arch64__
#define SIZEOF_VOIDP 8
#else
#define SIZEOF_VOIDP 4
#endif


4.3.4、建立openssl头文件目录以及库文件目录

(1)openssl头文件

把openssl源码库中的crypto和openssl目录文件夹拷贝到d/ndk/android-ndk-r10/apps/curl/jni/include目录下(curl头文件目录)

(2)openssl库文件

   d/ndk/android-ndk-r10/apps/curl/jni/目录下新建_library/static_a文件夹,并把编译好的openssl的三种版本的库文件拷贝到其中,如下图所示:


 

4.3.5、建立Aandroid.mk和Application.mk文件

1、在d/ndk/android-ndk-r10/apps/curl/jni/目录下新建Application.mk文件:

APP_ABI := armeabi armeabi-v7a x86     //依自己情况而定
APP_STL := stlport_static
APP_CPPFLAGS := -fexceptions -frtti
APP_CPPFLAGS+=-std=c++11

2、把d/ndk/android-ndk-r10/apps/curl/jni/ packages/Android/Android.mk文件拷贝到d/ndk/android-ndk-r10/apps/curl/jni/目录下,并做如下修改:

(1)LOCAL_PATH := $(call my-dir)/../..”改成 “LOCAL_PATH := $(call my-dir)

(2)添加对libcrypto.a和libssl.a不同版本库的引用

完整的Android.mk文件大致如下:

LOCAL_PATH :=$(call my-dir)
 
########################libArm################################
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include/crypto
LOCAL_MODULE    := libcryptoArm
LOCAL_SRC_FILES := _library/static_a/armeabi-v7a/libcrypto.a
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include/openssl
LOCAL_MODULE    := libsslArm
LOCAL_SRC_FILES = _library/static_a/armeabi-v7a/libssl.a
include$(PREBUILT_STATIC_LIBRARY)
########################libArm#################################
 
########################libx86#################################
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include/crypto
LOCAL_MODULE    := libcryptox86
LOCAL_SRC_FILES := _library/static_a/x86/libcrypto.a
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include/openssl
LOCAL_MODULE    := libsslx86
LOCAL_SRC_FILES = _library/static_a/x86/libssl.a
include$(PREBUILT_STATIC_LIBRARY)
############################libx86###############################
 
common_CFLAGS := -Wpointer-arith -Wwrite-strings -Wunused -Winline\
 -Wnested-externs -Wmissing-declarations-Wmissing-prototypes\
 -Wno-long-long -Wfloat-equal -Wno-multichar-Wsign-compare\
 -Wno-format-nonliteral -Wendif-labels-Wstrict-prototypes\
 -Wdeclaration-after-statement-Wno-system-headers -DHAVE_CONFIG_H\
 
##################################################
# Build the libcurl library
include$(CLEAR_VARS)
include$(LOCAL_PATH)/lib/Makefile.inc
CURL_HEADERS := \
    curlbuild.h\
    curl.h\
    curlrules.h\
    curlver.h\
    easy.h\
    mprintf.h\
    multi.h\
    stdcheaders.h\
    typecheck-gcc.h\
 
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_SRC_FILES := $(addprefix $(LOCAL_PATH)/lib/,$(CSOURCES))
LOCAL_STATIC_LIBRARIES := libcryptoArm libsslArm libcryptox86 libsslx86
LOCAL_CFLAGS += $(common_CFLAGS)
 
LOCAL_COPY_HEADERS_TO := libcurl/curl
LOCAL_COPY_HEADERS := $(addprefix include/curl/,$(CURL_HEADERS))
LOCAL_MODULE:=libcurl
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)


4.3.6执行编译

    启动cygwin,命令行输入 “cd /cygdrive/d/ndk/android-ndk-r10/apps/url/jni”即可进入到刚刚建立的工程目录,执行“ndk-build”命令,即可编译

 

5、curl的应用

需要应用curl库函数的话,仅仅需要把curl库的“Include”文件夹和自己刚刚编译好的libcurl.a、libssl.a、libcrypto.a文件拷贝到自己的工程相应目录下,并在工程的Aandroid.mk文件中添加引用即可。例如:

LOCAL_PATH :=$(call my-dir)
 
########################libArm################################
include$(CLEAR_VARS)
LOCAL_MODULE    := libcryptoArm
LOCAL_SRC_FILES := _library/armeabi-v7a/libcrypto.a
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_MODULE    := libsslArm
LOCAL_SRC_FILES = _library/armeabi-v7a/libssl.a
LOCAL_STATIC_LIBRARIES := libcryptoArm
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/curl
LOCAL_MODULE    := libcurlArm
LOCAL_SRC_FILES := _library/armeabi-v7a/libcurl.a
LOCAL_STATIC_LIBRARIES := libcryptoArm libsslArm
include$(PREBUILT_STATIC_LIBRARY)
##############################################################
 
########################libx86################################
include$(CLEAR_VARS)
LOCAL_MODULE    := libcryptox86
LOCAL_SRC_FILES := _library/x86/libcrypto.a
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_MODULE    := libsslx86
LOCAL_SRC_FILES = _library/x86/libssl.a
LOCAL_STATIC_LIBRARIES := libcryptox86
include$(PREBUILT_STATIC_LIBRARY)
 
include$(CLEAR_VARS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/curl/Include
LOCAL_MODULE    := libcurlx86
LOCAL_SRC_FILES := _library/x86/libcurl.a
LOCAL_STATIC_LIBRARIES := libcryptox86 libsslx86
include$(PREBUILT_STATIC_LIBRARY)
##############################################################
 
include$(CLEAR_VARS)
MY_SRCS :=…………
 
LOCAL_SRC_FILES := $(addprefix Source/,$(MY_SRCS))
LOCAL_C_INCLUDES = $(LOCAL_PATH)/Include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/curl/Include
LOCAL_MODULE    := xxxxxx
LOCAL_SRC_FILES += xxxx.cpp
LOCAL_STATIC_LIBRARIES := libcurlArm libcurlx86
LOCAL_LDLIBS += -lz
LOCAL_LDLIBS += -llog
include$(BUILD_SHARED_LIBRARY)


 

 

<think>好的,我现在要帮用户了解如何使用CygwinNDK编译C文件生成动态库。首先,我需要回忆一下CygwinNDK各自的作用。Cygwin是一个在Windows上模拟Linux环境的工具,而NDK是Android Native Development Kit,用于开发Android应用的本地代码部分。用户可能是在Windows环境下,想要编译出Android可用的动态库,所以需要结合这两个工具。 首先,用户可能需要安装Cygwin。我应该列出安装步骤,包括下载setup-x86_64.exe,选择必要的开发包,比如gcc、make、automake等。然后,安装NDK,用户需要从官网下载并解压,或者通过Android Studio获取路径。这里可能需要提醒用户注意NDK的版本和路径是否正确。 接下来是环境变量配置。用户需要将Cygwin的bin目录和NDK的toolchains目录添加到PATH中,这样在Cygwin终端里才能找到对应的编译工具。例如,指定交叉编译器的路径,比如arm-linux-androideabi-gcc,这可能根据不同的Android架构有所不同,需要根据用户的实际情况调整。 然后,编写C源代码。用户需要创建一个简单的C文件,比如hello.c,里面包含一个或多个函数,用于生成动态库。这里可能需要提醒用户注意函数的可见性,是否需要使用__attribute__((visibility("default")))来确保符号导出。 编写Android.mk和Application.mk文件是NDK构建的关键步骤。Android.mk负责定义模块,指定源文件、编译选项和输出类型(这里是动态库)。Application.mk则配置应用级别的设置,比如目标平台架构。需要确保用户正确设置这些文件的内容,特别是LOCAL_MODULE和LOCAL_SRC_FILES的路径是否正确。 接下来是编译步骤,使用ndk-build命令。需要指导用户在Cygwin终端中切换到项目目录,执行ndk-build命令,并检查输出是否成功生成.so文件。这里可能需要提醒用户注意处理可能的错误,比如路径错误、权限问题或者编译选项不正确。 最后,验证生成的动态库。用户可能需要将.so文件导入Android项目,并通过JNI调用相关函数。这部分可能需要进一步指导,但用户当前的问题可能集中在编译过程,所以可能不需要深入讲解Android集成部分。 过程中可能遇到的常见问题包括:环境变量配置错误、NDK版本不兼容、架构选择不正确、源文件路径错误等。需要提醒用户仔细检查这些部分,确保每一步都正确执行。此外,如果用户的目标架构不是armeabi-v7a,可能需要修改Application.mk中的APP_ABI,比如arm64-v8a或x86。 总的来说,步骤需要分阶段说明,确保用户能够逐步跟随操作。同时,强调路径和配置的正确性,避免因为环境问题导致编译失败。可能需要建议用户在遇到问题时查看NDK的文档或社区支持,以解决特定的编译错误。</think>以下是在Windows系统使用Cygwin+NDK编译C文件生成动态库的分步指南: --- ### **1. 环境准备** #### 1.1 安装Cygwin 1. 下载Cygwin安装器:访问[cygwin.com](https://www.cygwin.com/) 2. 运行`setup-x86_64.exe` 3. 选择镜像源(如`http://mirrors.kernel.org`) 4. 安装必要包: - `gcc-core` (C编译) - `make` (构建工具) - `automake`/`autoconf` (可选) - `libtool` (库工具) #### 1.2 安装Android NDK 1. 下载NDK:从[Android开发者网站](https://developer.android.com/ndk/downloads)获取 2. 解压到目录(如`C:\android-ndk-r25b`) --- ### **2. 配置环境变量** 在Cygwin终端中执行: ```bash # 设置NDK路径(根据实际路径修改) export NDK_HOME=/cygdrive/c/android-ndk-r25b # 添加工具链到PATH export PATH=$NDK_HOME/toolchains/llvm/prebuilt/windows-x86_64/bin:$PATH ``` --- ### **3. 编写C代码** 创建文件`hello.c`: ```c #include <stdio.h> __attribute__((visibility("default"))) void hello() { printf("Hello from dynamic library!\n"); } ``` --- ### **4. 配置NDK构建文件** #### 4.1 创建`Android.mk` ```makefile LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c LOCAL_CFLAGS := -fPIC include $(BUILD_SHARED_LIBRARY) ``` #### 4.2 创建`Application.mk` ```makefile APP_ABI := armeabi-v7a # 目标CPU架构 APP_PLATFORM := android-21 # 最低API级别 ``` --- ### **5. 编译动态库** 在Cygwin终端执行: ```bash # 切换到项目目录 cd /cygdrive/c/projects/hello # 执行NDK编译 $NDK_HOME/ndk-build NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk ``` --- ### **6. 验证输出** - 生成的动态库路径: ```bash ./libs/armeabi-v7a/libhello.so ``` - 使用`file`命令验证: ```bash file libs/armeabi-v7a/libhello.so # 正确输出应显示"ELF 32-bit LSB shared object, ARM..." ``` --- ### **常见问题处理** | 问题现象 | 解决方法 | |---------------------------|-----------------------------------| | `undefined reference` | 检查函数是否添加`visibility`属性 | | `invalid ABI` | 检查`Application.mk`中的`APP_ABI`| | `command not found` | 确认PATH环境变量包含NDK工具链 | | `permission denied` | 使用`chmod +x`赋予执行权限 | --- ### **关键概念解释** 1. **交叉编译**:在x86平台生成ARM架构二进制文件 2. **ABI兼容性**:需匹配Android设备的CPU架构(armeabi-v7a/arm64-v8a/x86等) 3. **符号可见性**:通过`__attribute__((visibility))`控制导出函数 如需集成到Android项目,需通过`System.loadLibrary("hello")`加载动态库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值