6.3 KiB
如何引用第三方库
本文基于 AWTK 模板工程介绍如何在 SCons 编译脚本中引用第三方库。
注:这里所说的 AWTK 模板工程指 AWTK Designer 创建的常规工程,工程目录下有一个 SConstruct 文件,它是 SCons 编译脚本,遵顼 Python 语法,下文中的操作基本都通过编辑该文件实现。
1 引用第三方库的源码文件
如果第三方库提供的是源码文件,那么通常我们需要做以下两件事:
- 将第三方库源码的头文件路径添加到工程中,方便编译时能找到库中的函数声明。
- 把源码文件加入工程编译,方便链接时能找到库中的函数定义。
假设此处有一个名为 xxx 的第三方库,它提供了 xxx.h 和 xxx.c 两个文件,按照约定的规则,我们将它放在 AWTK 工程的 3rd/xxx 目录中,结构如下:
3rd
xxx
xxx.h
xxx.c
...
SConstruct
1.1 添加头文件路径
在工程的 SConstruct 脚本文件中调用 helper.add_cpppath 函数添加库的头文件路径,传入参数为数组,此处的路径为:工程目录/3rd/xxx,如果有其他路径也可以在数组中添加新的元素,代码如下:
# SConstruct
import os
import scripts.app_helper as app
...
# 构建 xxx 库的头文件路径:工程目录/3rd/xxx
XXX_PATH = [os.path.join(helper.APP_ROOT, '3rd', 'xxx')]
# 添加头文件路径,并链式调用 call 函数同步数据
helper.add_cpppath(XXX_PATH).call(DefaultEnvironment)
SConscriptFiles = ['src/SConscript', 'tests/SConscript']
helper.SConscript(SConscriptFiles)
注:在调用 helper.add_cpppath 函数后,需要调用 call 函数同步这些数据,call 函数支持链式调用,需要放到最后,且只需调用一次,更多 helper 对象中的相关函数请参考:利用 app_helper 编写 SConstruct。
1.2 把源码文件加入工程编译
在工程的 src/SConscript 脚本文件中,将 3rd/xxx 目录下的源码文件添加到 sources 数组中即可把它们编译到可执行程序中,代码如下:
# src/SConstruct
import os
import sys
import platform
...
# 添加 src 目录下的所有 .c 文件,符号 * 为通配符
sources = Glob('**/*.c') + Glob('*.c')
# 添加 3rd/xxx 目录下的所有 .c 文件
sources += Glob('../3rd/xxx/*.c')
# 将 sources 中的所有文件编译为 bin/demo 程序
env.Program(os.path.join(BIN_DIR, 'demo'), sources, LIBS = env['LIBS'])
1.3 扩展用法(添加预处理参数、链接参数)
在工程的 SConstruct 脚本文件中调用 helper 对象中的以下函数可以添加预处理参数、链接参数:
- add_ccflags:增加 C 预处理参数。
- add_cxxflags:增加 C++ 预处理参数。
- add_linkflags:增加链接参数。
例如此处添加 C 预处理参数(定义宏NDEBUG=1),SConstruct 脚本代码如下,其他两个函数用法也是类似的:
# SConstruct
...
XXX_PATH = [os.path.join(helper.APP_ROOT, '3rd', 'xxx')]
helper.add_cpppath(XXX_PATH).add_ccflags(' -DNDEBUG=1 ').call(DefaultEnvironment)
...
2 引用第三方库编译好的库文件
引用第三方库时,更常见的应该是直接引用编译好的库文件(动态库或静态库),此时在工程的 SConstruct 中描述依赖关系即可。具体方式为:先定义依赖描述,再调用 set_deps 将依赖描述设置到 helper 对象中。
2.1 常规用法
需要注意的是,使用本节方法引用第三方库时,默认按照 AWTK 约定的规则存放第三方库的代码文件和库文件,规则如下:
- 第三方库的代码文件需要放在库路径 src 目录中。
- 第三方库的动态库文件需要放在库路径的 bin 目录中。
- 第三方库的静态库文件需要放在库路径的 lib 目录中。
注:如果想自定义上述文件的路径,则需额外指定 cpppath 和 libpath 参数,详见下文。
假设此处有一个名为 xxx 的第三方库,它提供了头文件 xxx.h 和相关的库文件,按照约定的规则,我们将它放在 AWTK 工程的 3rd/xxx 目录中,结构如下:
3rd
xxx
bin
xxx.dll # 动态库文件
xxx.lib # 动态库的导出列表
lib
xxx.lib # 静态库文件
src
xxx.h
...
SConstruct
在工程的 SConstruct 脚本文件中,引用动态库的方式如下:
# SConstruct
...
DEPENDS_LIBS = [
{
"root" : '3rd/xxx', # 第三方库路径,支持绝对路径和相对路径。
'shared_libs': ['xxx'], # 引用的动态库名称,动态库文件必须放在 root/bin 目录下。
'static_libs': [] # 引用的静态库名称,静态库文件必须放在 root/lib 目录下。
}
]
# 设置依赖库,默认会添加以下路径:
# 1.头文件路径(root/src)
# 2.库文件路径(root/bin、root/lib)
helper.set_deps(DEPENDS_LIBS)
...
helper.call(DefaultEnvironment)
注:helper.set_deps 一定要在 helper.call 之前调用,call 函数支持链式调用,需要放到最后,且只需调用一次。
2.2 依赖描述参数
DEPENDS_LIBS 是一个数组,可以添加多个第三方依赖库,每个元素是一个依赖描述对象,可以指定以下参数:
- root 第三方库的根目录。建议使用相对于应用程序的相对路径。如:
"root" : '../awtk-mvvm',
- shared_libs 第三方库提供的动态库列表(数组),不带扩展名和 lib 前缀。如:
"shared_libs" : ["a","b","c"]
- static_libs 第三方库提供的静态库库列表(数组),不带扩展名和 lib 前缀。如:
"static_libs" : ["a","b","c"]
- libpath 库所在的路径,相对于前面指定的 root 路径。缺省为:["lib", "bin"]。如:
"libpath" : ["lib", "bin"]
- cpppath 头文件所在的路径,相对于前面指定的 root 路径。缺省为:["src"]。如:
"cpppath" : ["includes", "src"]
- cflags C 语言的预处理参数(可选)。如:
"cflags" : " -DNDEBUG=1 "
-
cxxflags C++语言的预处理参数(可选)。
-
ccflags C/C++语言的预处理参数(可选)。