﻿/*
	© 2013-2014 FrankHB.

	This file is part of the YSLib project, and may only be used,
	modified, and distributed under the terms of the YSLib project
	license, LICENSE.TXT.  By continuing to use, modify, or distribute
	this file you indicate that you have read the license and
	understand and accept it fully.
*/

/*!	\file ProjectRules.txt
\ingroup Documentation
\brief 项目组织和管理规则。
\version r342
\author FrankHB <frankhb1989@gmail.com>
\since build 381
\par 创建时间:
	2013-02-14 17:59:49 +0800
\par 修改时间:
	2014-05-12 10:48 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	Documentation::ProjectRules
*/


/*

@0 体例和适用范围：
引用标记参见 [Documentation::CommonRules @@0.1] 。
本文档适用范围为项目范围， 参见 @1 。

@1 项目范围：
 YSLib 项目(the YSLib project) 是以库为主要产出的项目。
除非另有说明，本文档在任意修订后对同一项目构建版本(@2.2) 及之后的版本生效；本条规则适用追溯无限制。

@1.1 顶级子项目：
 YBase ： YSLib 基础库。
 YFramework ： YSLib 框架库。
 YSTest ： YSTest 测试项目，是包含测试代码的应用程序项目，包含示例（当前为 YReader ）。

@1.2 平台环境：
使用的平台除了配置管理(@2.1) 需另行说明外，由 YFramework 特定部分的实现定义。其它部分除另有说明(@3.3) 外，都保持平台中立([Documentation::CommonRules @@2.2.2.1]) 。
使用 ISO C++ 作为主要开发语言。具体的环境限定（语言版本和语言实现等）参见 [Documentation::Designation @@1.3.2] 。
运行开发环境的平台称为构建平台(build platform) ，运行最终目标代码的平台称为目标平台(target platform) ，被目标平台代码生成直接依赖的平台称为宿主平台(host platform) 。
若平台之间不出现语言实现和环境的相互依赖，则这些平台相互独立。总是保持相互独立的一组平台称为独立平台(independent platform) 。
实际的平台实现可能复用部分实现，配置之间可存在依赖（如继承关系）。这些在项目中所有被配置的平台称为公共平台(common platform) ，其中能对应生成输出的称为具体平台(concrete platform) ，否则为抽象平台(abstract platform) 。

@1.3 依赖结构：
 YFramework 依赖于 YBase 。
 YSTest 依赖于 YBase 和 YFramework 。
具体的框架依赖架构见 "/doc/vsd" 。
文件组织依赖见 @3.3 。
不由 YSLib 项目提供的库称为外部依赖项。

@2 项目管理：
默认使用迭代增量式开发。
如无特别说明，不修改外部依赖项。
以下是非外部依赖项设计和管理约定。
注意具体的 IDE （集成开发环境）等工具不一定支持以下所有项。

@2.1 配置管理：
适用于各个子项目。
各目标平台统一包含的基本配置为 debug 和 release （注意大小写），分别对应于调试和发布。
对于有其它生成目标的平台可以追加配置。

@2.2 版本控制：
此规则用于对 YSLib 项目中的文件的修订和项目发布的顺序标识提供的一种简便方式。适用于任意非外部依赖项。
被版本库识别并归档的文件称为托管文件。
任意托管文件的被版本库识别的改动都是项目的修订。除此之外，存档与临时文件的临时版本记录区域不视为文件修订。
项目构建版本号独立于文件版本号。

@2.2.1 项目构建：
自 build 132 起使用版本控制工具。

@2.2.1.1 构建版本：
以 (release) rev （缩写 r ）加整数序号表示用于在构建之间迭代的编译版本。一个编译版本具有一次或多次修订后的一个或多个配置的一次构建。

@2.2.1.2 提交版本：
以 build （缩写 b ）加整数序号表示经过完整构建的公开提交版本。一个提交版本应至少具有一次（各个平台）所有配置的全部重新构建。
原则上一个提交版本具有至少 X = min{8, 2 + ∑A(i)} 个编译版本，其中最后的连续几个版本作为各个配置的提交发布版本，参数含义如下：
 i 表示完整支持的平台， A 是 i 的函数；对于独立实现， A(i) = 4 ；对于宿主环境（操作系统内核及应用虚拟机等运行时环境其中任一）和之前宿主实现不共享实现的新的宿主实现， A(i) = 3 ；否则 A(i) = 2 。
对于现有配置， A(DS) = 4 ； A(MinGW32) = 3 ； A(Android) = 3 ； X = 12 。

@2.2.1.3 库提交版本：
包含库源代码的文件的修改的提交版本称为库提交版本。
大部分提交版本应为库提交版本。
库提交版本应尽量避免回退。

@2.2.1.4 主分支版本：
在主要开发路径分支（主分支）上的库提交版本称为主分支版本。
除此之外，主分支版本也可以仅包含库的文档改进，但应在提交记录说明。
主分支版本应保证所有程序（非文档）目标能在所有支持的平台（注意不包括正在移植中的目标）上成功构建，否则为工程缺陷(@2.3.3) 。
仅包含库的程序或文档以外修订的版本，不是主分支版本。
主分支版本禁止回退。

@2.2.1.5 发布版本：
在主分支的基础上的特定版本或分支打包发布的版本。
除主分支版本要求(@2.2.1.4) 外，同时要求正式支持的移植版本能成功构建及更新日志（ "ChangeLog.*" 文件）和当前进度保持同步，否则为工程缺陷(@2.3.3) 。

@2.2.2 文件创建和修改时间：
文件创建时间应不晚于最早的提交时间。
分支版本使用新的文件创建时间，但父文件不再存在时都继承父文件创建时间。
文件修改时间应保证和对应提交时间一致，除非最近一次修订是回滚前一次操作。
当从其它分支合并或提交未在版本库中的文件时，文件创建时间可早于提交时间。

@2.2.3 文件版本号：
文件版本号表示版本的修订行数，即增加、删除、修改或移动的行的有效计数。
有多种计数时以较小者为准（如移动优先于修改）。
版本说明（版本号）、修改时间的修改不列入计数。
注意修订的版本不一定提交，因此相邻提交版本之间版本号的变动可以大于（但不得小于）直接比较提交版本之间的差异得到的计数。
除非一次修订仅涉及空行（这里指仅含空白符的行），对空行的修改不列入计数。
自 build 334 起严格执行（之前大部分文件版本号在新增时加入偏移而偏大）。
文件版本号以 Doxygen 指令 \version 标示。

@2.2.4 实体版本标识：
表示抽象的实体被引入时和文件版本关联的版本，适用范围较文件版本号更广。
实体包括源代码（文本）文件实体和程序实体（ ISO C++ 定义的实体，参见 ISO/IEC 14882 Clause 3 ）以及宏（名称为和 ISO C++ 宏名通用的标识符，包括 ISO C++ 的宏）。
实体版本标识首要用于跟踪实体的修订，其次关注公开接口的可使用性。当实体迁移时接口兼容性可能发生变化但版本不变；或补充兼容接口后，兼容接口使用新的版本标识。
更新实体版本标识的充分必要条件是存在名称变更或以下约定的其它变更的修订。
当从其它分支合并或提交未在版本库中的文件时，实体版本标识可早于提交版本。
实体版本标记以 Doxygen 指令 \since 标示。

@2.2.4.1 实体转移：
项目内部转移忽略以下变更：
对于文件，忽略目录路径和作为非公开接口（非公开头文件）的文件名的变更（注意虽然 YFramework 使用 YFM_* 代替包含头文件路径，但公开供用户包含的头文件名和目录名仍属于公开接口）；
对于代码中的宏和实体，忽略所在命名空间（若存在）、文件名及头文件公开性(@3.3) 变更。
项目间转移不忽略任何变更，按删除和添加处理。

@2.2.4.2 同名实体变更：
相同实体在条件编译指令的至少一个条件分支下存在，变更分支（包括增加及减少但仍然存在的条件分支）不视为实体变更。
对于重载，不视为相同实体；
对于模板特化，不视为相同实体。
被 using 声明（注意不含 typedef 声明、 using 指示、友元声明和别名声明）指定的前提下（注意不包括 using 声明和非 using 声明之间的变更）的等价名称变换不视为名称变更。
别名声明和 typedef 的等价变换不视为变更。
包括所有实体名称的链接（或对应实现的符号(symbol) 可见性(visibility)）变更（注意仅仅变换 inline 或 constexpr 而省略指定符号可见性不视为变更）；除此以外忽略所有 ISO C++ 或实现扩展的属性(attribute) 变更。
对于宏，包括参数列表变更。
对于所有实体，包括实际引起语义变化的存储类限定符（ static 、 extern 、 mutable 等）变更。
对于函数、函数模板和模板特化，包括类型（注意类型等价性，参见 [Documentation::CommonRules @@5.12.1] ）、显式指定的异常规范和不等效（等效包括 nullptr 修改为 {} 等；涉及名称变更的修改不等效）的默认参数变更，但已约定不属于公开接口的除外；不包括函数限定符（ inline 、 virtual 、explicit ）和 constexpr 的变更。
对于枚举器，包括显式指定值的增加、删除或修改，不包括调换顺序等导致的隐式值的变更。
对于类成员，包括访问权限变更。
对于在类定义内初始化的类的数据成员和首次声明时初始化的命名空间作用域变量，包括不等效的初值符变更。
不包括 typedef 名称和别名声明中被声明标识符以外的变更。
不包括函数或模版的形式参数名称变更。

@2.2.5 声明独立版本标识：
 typedef 声明、 using 声明、 using 指示 、友元声明和别名声明可独立加注版本，以声明的名称确定版本一致性。
 static_assert 声明可独立加注版本，以记号序列等价性确定版本一致性。

@2.2.6 头文件包含守护宏(include guard marco) ：
除非重复包含不影响语义，否则应使用特定名称的宏以保证头文件不被包含超过一次。
一般包含模式如下：

#ifndef 宏名
#define 宏名 非零整数字面量

//被保护的代码，常以 #include 起始。

#endif

不同头文件应使用不同的宏名。
具体宏名由实现定义。一般应使用特定保留前缀（但不应与标准名称冲突，除非实现标准库，参见 [Documentation::CommonRules @@5.3.2.2.2] ）。可能包含模块命名空间(@3.2) 的名称。

@2.2.7 发布(releasing) 和发行(publishing) ：
目前为 PreAlpha 测试阶段，无发布和发行计划。

@2.3 问题跟踪(issue tracking) 和管理：

@2.3.1 问题记录：
和项目运行和质量直接相关的问题应被记录。记录内容参见 [Documentation::Meta] 。
间接的问题和备忘可记录于汇总的年度报告(annual report) 中。

@2.3.2 工程描述文档(enginerring description document) ：
以工程方式控制项目运行和质量的规则描述文档称为工程描述文档，包括本文档和 [Documentation::Designation] 。

@2.3.3 缺陷(defect) ：
不符合且明显有碍于项目目标的问题是缺陷，包括错误(error) 和故障(fault) 。
错误是被证明对于预期目的或结果不合适的计划导致的缺陷。错误以外的缺陷是故障。
工程描述文档(@2.3.2) 的规则描述是确认缺陷的充分非必要条件。
违反工程文档的缺陷、错误和故障依次为工程缺陷(engineering defect) 、工程故障(engineering fault) 和工程错误(engineering error)。
工程缺陷应在提交版本(@2.2.1.2) 中标注。

@2.4 文档管理：
除了正式发布的版本，允许文档落后于实际项目中其它部分的进度。

@2.5 质量保证：
静态验证优先于测试。
默认使用部分整体回归测试代替所有单元测试，以避免过大的测试维护的开销。

@2.6 版本库(repository) 规则：
除了版本控制(@2.2) 外版本库管理根据本节约定。
本节文件限制仅作用于被版本控制系统跟踪的文件，不包括未被跟踪的版本控制自身的数据（如 Mercurial 的 /.hg 和 Git 的 /.git）或其它文件。
注意一些专版本控制的文件（如 Mercurial 的 .hgignore 和 .hgtags 和 Git 的 .gitignore）一般属于被跟踪的文件。

@2.6.1 版本管理工具：
当前使用 Mercurial(hg) 管理版本库，使用 hg-git 制作 Git 镜像。
不使用未被分布式版本控制程序广泛实现的特性。
若需使用 hook ，需要在文档中约定。

@2.6.2 文件系统限制：
注意版本控制工具可能只跟踪文件。避免可能无法实现的操作，例如跟踪空目录。
不使用没有被普遍移植的文件系统特性，包括 NTFS 备选流、加密、目录链接(junction) 等。
不使用文件系统支持的硬链接(hard link) ，避免对特定文件系统和路径的限制。
不使用文件系统支持的符号链接(symbolic link) ，避免对特定文件的限制。若有必要且可实现，在文档中约定后可以通过其它方式模拟。
不在文件系统层次使用元数据（如权限设置，包括 POSIX ACL 和 NTFS ACL ）。若需要此类配置，保存为元数据文件。

@2.6.3 内容转换特性限制：
对于文本文件限制内容转换特性以保证不同版本库之间的一致性。
不使用自动行末字符(EOL) 转换（主要是 LF/CR+LF ）。注意 Windows 上的 Git 可能自动使用 autocrlf 配置，应予关闭（配置为 false ）。
不使用自动编码转换。

@3 组织约定：

@3.1 单元(unit) ：
编译单元简称单元，是一组包含源代码的文本文件，包含一个不作为头文件包含的源文件（默认后缀名 .cpp ）和若干个被这个源文件直接或间接包含的头文件，经过预处理后成为翻译单元(translation unit) 。
编译单元可以包含类/结构体等类型，以及 API（Application Programming Interface ，应用程序编程接口）的实现。
单元可以作为测试的基本单位之一，即进行单元测试(unit testing) 。

@3.2 模块和模块命名空间：
此处模块特指静态的组织构成单位。注意和一般意义的模块（参见 [Documentation::CommonRules @@3.7.1] ）之间的区别与联系。
一个单元或无源文件对应的头文件称为模块(module) 。一个模块目录是某个抽象路径中的模块的集合。
一个模块仅可属于一个模块目录。
模块和模块目录以类 C++ qualified-id 语法组成的名称表示，形式定义如下：
name-expression:
	identifier
	identifier ( name-expression )
simple-module-name:
	name-expression
module-namespace-name:
	name-expression
	module-namespace-name :: name-expression
module-namespace-qualifier:
	module-namespace-name ::
nested-module-name:
	module-namespace-qualifier simple-module-name
module-path:
	simple-module-name
	module-namespace-name
	nested-module-name
 identifier 规则同 ISO C++ 标识符。
如无特别指明，以下使用的模块名称都是简单模块名 simple-module-name 。
 :: 、 ( 和 ) 两边的空白仅作区分记号的示意，实际使用时和标识符之间不保留空格。
对于清晰的上下文，可以使用部分的模块名称。特别地，在标识库的组件时顶级的标识符（表示库的名称）通常省略。
顶级子项目(@1.1) 不作为模块命名空间；其并集作为全局模块命名空间。

@3.3 文件组织：
和模块目录对应的用于存储源文件的文件系统中的一组目录称为模块目录。模块对应其中的文件。
除非另行指定，模块命名空间的名称和对应的主要模块目录（在文件系统的对应称为原始目录）名称相同。对模块不限制名称一致。
每个二级子项目中关于特定独立平台(@1.2) 配置适用的部分称为平台扩展，在原始目录下存储为单独的子目录，目录名称为平台配置名称，项目文件名称一般为项目名称加后缀 "_平台配置名称" 。
相同或不同顶级子项目中，平台特定的目录中的文件可依赖于对应的原始目录，原始目录的文件不依赖于这些目录中的文件。这保证顶级子项目可以在不更改依赖性的前提下直接被拆分为独立项目。
顶级子项目之间内部的文件仅存在单向依赖，具体依赖和项目相关，参见 [Documentation::YFramework @@2] 和 [Documentation::Designation @@5.2.1.2]。
此外，第三方依赖项项目独占顶级子项目并列的文件系统目录 "/3rdparty" 。

@3.3.1 源文件组织：
典型情况下，每个顶级子项目的根模块目录包含存储公开头文件 "/include" 和存储其它源文件的 "/source"，以下分别按模块命名空间组织为文件系统的目录。
 "/include" 中的头文件是公开头文件，它的内容是公开的接口。公开头文件和 "/source" 中的不作为头文件包含的源文件对应组成的模块，称为公开模块。
 "/source" 包含的头文件不是公开头文件，它的内容不是公开的接口。非公开头文件可能和同一个目录下的其它源文件组成模块，称为非公开模块。
命名参见 @3.4 。

@3.4 文件名和目录名：
本节适用于代码和相关目录，不适用于文档和相关目录。

@3.4.1 长度和可包含的字符：
除 @3.4.2 列出的例外，同 Boost 限制，参见 http://www.boost.org/development/requirements.html#Directory_structure 。
 build 275 前在此之上有更强的保证：支持 8.3 文件名兼容性，文件名不使用大写字母，目录名不超过 8 个字符）。
考虑可移植性，在每一个目录下，保证其中所有文件名和目录名中的所有字符使用 std::tolower 转换后得到的文件名不重复。

@3.4.2 可包含字符例外：
除了 YBase([Documentation::Designation @@5.2.1]) ，在文件名（但对于存在扩展名的文件名，不包含扩展名部分）和目录名中允许使用大写字母。

@3.4.3 头文件扩展名：
一般使用 h ，但设计时即确定不需要作为独立翻译单元的实现文件（如仅包含模板的实现或元编程设施）的头文件使用 hpp 。

@3.4.4 文件包含：
本节约定 #include 等使用的字符序列。
不使用文件系统中的绝对路径。
统一使用 "/" 作为文件路径分隔符。
实现搜索的根路径为子项目(@1.1) 所在的各个目录(@3.3) 。
本节约定的完整路径是指实现搜索的根路径起始的相对路径；最简相对路径指不包含自指 "." ，以尽量少的 ".." 跳转表示的相对路径。
对于包含当前项目外的文件（包括外部的库文件），使用 <完整路径> 。
对于包含当前项目中的相同子项目文件，使用 "最简相对路径" 。注意对于同一个项目的不同平台配置指定原始目录(@3.3) 时路径会较原始目录内部的包含路径复杂。
对于其它文件，使用 "完整路径" 。

@3.5 命名空间：
库和用户程序的代码在逻辑上最终属于一定的命名空间([Documentation::NPL @@4.3.4]) ，对应 C++ 等语言的命名空间特性。（对于没有命名空间特性的语言如 C ，则相当于使用全局命名空间，或另行约定以标识符中的前缀等方式作为替代）。
语言支持的命名空间特性通常具有单一根（一般称为全局命名空间）的树形层次体系。直接从属于全局命名空间的子命名空间称为顶层命名空间。
和模块名称(@3.2) 或源文件的目录名(@3.4) 不同，命名空间的组织方式更多对于用户公开不同层次的接口，而不是主要供库维护者组织代码的持久储存形式。注意语言可以只提供命名空间特性，而源文件及目录的组织由环境实现，可能另行约定。
因此，顶层命名空间不需要和库或程序组件的模块或目录名严格对应。但使用一致的对应名称往往有利于简化设计，便于维护和使用。
 YSLib 项目中各个库对命名空间的使用由库约定。

@4 程序部署：
使用 YFramework 和 YBase 需要维持目录结构。其它暂略。
关于 YReader 的部署配置参见 [Documentation::YSLib @@10] 。

@5 用户配置：
暂略。

*/
////

