awtk/docs/how_to_use_3rd_libs.md
2023-01-29 17:38:58 +08:00

188 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 如何引用第三方库
本文基于 AWTK 模板工程介绍如何在 SCons 编译脚本中引用第三方库。
> 注:这里所说的 AWTK 模板工程指 AWTK Designer 创建的常规工程,工程目录下有一个 SConstruct 文件,它是 SCons 编译脚本,遵顼 Python 语法,下文中的操作基本都通过编辑该文件实现。
## 1 引用第三方库的源码文件
如果第三方库提供的是源码文件,那么通常我们需要做以下两件事:
1. 将第三方库源码的头文件路径添加到工程中,方便编译时能找到库中的函数声明。
2. 把源码文件加入工程编译,方便链接时能找到库中的函数定义。
假设此处有一个名为 xxx 的第三方库,它提供了 xxx.h 和 xxx.c 两个文件,按照约定的规则,我们将它放在 AWTK 工程的 3rd/xxx 目录中,结构如下:
```bash
3rd
xxx
xxx.h
xxx.c
...
SConstruct
```
### 1.1 添加头文件路径
在工程的 SConstruct 脚本文件中调用 helper.add_cpppath 函数添加库的头文件路径,传入参数为数组,此处的路径为:工程目录/3rd/xxx如果有其他路径也可以在数组中添加新的元素代码如下
```python
# 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](https://github.com/zlgopen/awtk/blob/master/docs/app_helper_usage.md)。
### 1.2 把源码文件加入工程编译
在工程的 src/SConscript 脚本文件中,将 3rd/xxx 目录下的源码文件添加到 sources 数组中即可把它们编译到可执行程序中,代码如下:
```python
# 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=1SConstruct 脚本代码如下,其他两个函数用法也是类似的:
```python
# 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 目录中,结构如下:
```bash
3rd
xxx
bin
xxx.dll # 动态库文件
xxx.lib # 动态库的导出列表
lib
xxx.lib # 静态库文件
src
xxx.h
...
SConstruct
```
在工程的 SConstruct 脚本文件中,引用动态库的方式如下:
```python
# 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 第三方库的根目录。建议使用相对于应用程序的相对路径。如:
```python
"root" : '../awtk-mvvm',
```
- shared_libs 第三方库提供的动态库列表(数组),不带扩展名和 lib 前缀。如:
```python
"shared_libs" : ["a","b","c"]
```
- static_libs 第三方库提供的静态库库列表(数组),不带扩展名和 lib 前缀。如:
```python
"static_libs" : ["a","b","c"]
```
- libpath 库所在的路径,相对于前面指定的 root 路径。缺省为:["lib", "bin"]。如:
```python
"libpath" : ["lib", "bin"]
```
- cpppath 头文件所在的路径,相对于前面指定的 root 路径。缺省为:["src"]。如:
```python
"cpppath" : ["includes", "src"]
```
- cflags C 语言的预处理参数(可选)。如:
```python
"cflags" : " -DNDEBUG=1 "
```
- cxxflags C++语言的预处理参数(可选)。
- ccflags C/C++语言的预处理参数(可选)。
### 2.3 完整示例
- [awtk-mvvm-c-hello](https://github.com/zlgopen/awtk-mvvm-c-hello/blob/master/SConstruct)