|
QtCanpool 3.3.0
|
本页说明 QtCanpool 的分层方式,以及**写代码时必须遵守的约定**。新增库或新增模块前建议先读一遍。
依赖是单向的:上层可以依赖下层,下层永远不知道上层的存在。
三点值得留意:
qxcore 只依赖 Qt Core,因此任何库都可以用它,包括不涉及界面的模块—— i18n(QxCore::QxTranslator)正因此放在这一层,而不是放在 qxapp。qxtheme **刻意不依赖 qxribbon**:内置样式表位于 qxribbon 的资源包中,靠 Qt 的进程级资源 在运行时按路径读取。这样 qxribbon 一侧零改动,非 Ribbon 应用也能使用主题引擎。| 目录 | 说明 |
|---|---|
cmake/ | CMake 构建框架(QtCanpoolAPI.cmake 是核心,提供下面那套函数) |
src/libs/ | 基础类库,每个库一个子目录,一个库一个命名空间 |
src/modules/ | 实用代码,规模尚未达到独立库 |
src/plugins/ | 基础插件 |
src/shared/ | 跨模块共享代码 |
demos/ | 综合示例(CMake) |
examples/ | 控件级示例(CMake,由 WITH_EXAMPLES 控制) |
tests/ | 单元测试(CTest) |
doc/ | 文档:设计文档、指南页面(doc/pages/)与文档站点构建(doc/CMakeLists.txt) |
projects/ | 项目模板,可在此持续添加自己的项目 |
scripts/ | 辅助脚本 |
thirdparty/ | 第三方库使用案例 |
每个库拥有独立命名空间,由该库的 *_global.h 定义。**始终通过宏使用,不要手写 namespace**:
| 库 | 命名空间 | 宏前缀 |
|---|---|---|
| qxcore | QxCore | QX_CORE_ |
| qxtheme | QxTheme | QX_THEME_ |
| qxwindow | QxWindow | QX_WINDOW_ |
| qxribbon | QxRibbon | QX_RIBBON_ |
| qxdock | QxDock | QX_DOCK_ |
| qxapp | QxApp | QX_APP_ |
每个库提供四个宏:
| 宏 | 用途 |
|---|---|
QX_CORE_BEGIN_NAMESPACE / QX_CORE_END_NAMESPACE | 头文件与源文件中包裹声明 |
QX_CORE_USE_NAMESPACE | using namespace QxCore;,仅用于 .cpp |
QX_CORE_PREPEND_NAMESPACE(name) | 需要显式限定名字时使用,例如 QX_CORE_PREPEND_NAMESPACE(QxSettings) * |
定义 QX_CORE_NAMESPACE_DISABLE 可以完全关闭命名空间(宏会展开为空), 因此所有跨库引用都必须写成宏,否则关闭命名空间后编译不过。
导出符号由 QX_CORE_EXPORT 一类宏控制:add_qtc_library() 会自动为库本身定义 QX_CORE_LIBRARY,消费方由此得到 Q_DECL_IMPORT。静态库场景下定义 QX_CORE_LIBRARY_STATIC 即可。
公开类一律使用 d-pointer,把实现细节从公开头文件中挪走。宏家族在 *_global.h 中提供 (QX_DECLARE_PRIVATE 等在同一处定义,因此任何库都能直接用):
| 宏 | 位置 | 作用 |
|---|---|---|
QX_DECLARE_PRIVATE(Class) | 类尾部(private: 之后) | 声明 ClassPrivate *d_ptr 与 Q_DECLARE_PRIVATE |
QX_DECLARE_PUBLIC(Class) | 私有类中 | 声明回指公开对象的 q_ptr |
QX_INIT_PRIVATE(Class) | 构造函数 | 创建私有对象并回指 |
QX_FINI_PRIVATE() | 析构函数 | 删除私有对象并置空 |
Q_Q(Class) / Q_D(Class) | 成员函数 | 取得 q / d 指针 |
**注意**:
QX_FINI_PRIVATE()后面要写分号。漏掉时 clang-format 会把析构函数体折成一行, 看起来像是格式问题,实际是少了一个;。
新增库、示例、测试时使用框架提供的函数,不要手写 add_library / add_executable: 它们负责翻译、rpath、AUTOMOC、默认编译定义以及**自动安装与导出**。
| 函数 | 用途 |
|---|---|
add_qtc_library(name ...) | 定义一个库 |
extend_qtc_library(target ...) | 为已定义的库追加源文件或依赖(常用于按平台分支) |
add_qtc_executable(name ...) | 定义一个可执行程序 |
add_qtc_test(name ...) | 定义并注册一个 CTest 测试 |
add_qtc_documentation(qdocconf) | qdoc 文档通道(遗留,当前未使用) |
add_qtc_library() 常用参数:
| 参数 | 说明 |
|---|---|
VERSION / COMPAT_VERSION | 库版本,也决定安装目录与导出文件名 |
DEFINES | 私有编译定义(库自身可见,通常写 QX_CORE_LIBRARY) |
PUBLIC_DEFINES | 公开编译定义 |
DEPENDS | 私有依赖(仅实现需要) |
PUBLIC_DEPENDS | 公开依赖(**公开头文件里出现了该库的类型时必须用它**) |
INCLUDES / PUBLIC_INCLUDES | 私有 / 公开包含目录 |
SOURCES | 源文件列表 |
CONDITION | 条件构建,不成立时整个库被跳过 |
add_qtc_test() 的 DEPENDS 会在目标不存在时自动跳过该测试, 因此关闭某个组件开关时不需要同步修改测试列表。
新文件使用 SPDX 标识,年份取实际创建年份;贡献者可在其后追加自己的版权行:
.md 等文档文件不受此限格式化由仓库根目录的 .clang-format 定义,**CI 中作为强制门禁**:
#pragma once,或与既有文件保持一致的宏卫哨type(scope): subject,提交信息使用英文;scope 取库名、ci、test、docs 等公开 API 使用 Doxygen 风格注释,因此文档站点可以直接从源码生成:
/** ... *//*! ... */,简短描述放在首行,细节另起段落\a name 引用参数,@code / @endcode 包裹示例