代管式命名空间

摘要

简介

在 Weave SDK 中,托管命名空间用于为 Weave SDK 开发者和集成者提供宣传的指南和辅助文本,以说明在 SDK 中如何指定特定 API 集,以便他们可以规划和预测不同 Weave SDK 版本的迁移路径,并可能为给定模块管理多个并发 Weave API。

职务

代管式命名空间可以采用以下四种方式之一进行管理:

开发

任何使用“开发”标识管理的命名空间,向开发者和集成者表明,其中的 API 处于积极开发中,可能会发生更改,且不受官方支持。除非专门指示集成商使用这些 API,否则通常不建议集成商使用这些 API。

下一个

任何使用“Next”标识管理的命名空间会向开发者和集成者表明,虽然其中所含的 API 基本上已经完成积极开发,但可能仍可能会发生变化,并支持用于早期评估。如此指定的 API 代表了 Weave SDK API 中的下一代发展前沿,在不久的将来还会成为当前的默认默认 API。

从 API 和无线传输协议的角度来看,向后兼容性可能存在,但在指定的 API 中无法保证向后兼容。

指定“Next”代管式命名空间可以提示开发者和集成者未来版本中的当前默认 API 会是什么,从而了解 Weave SDK 的发展方向。

指定下一个代管式命名空间是可选的,这样代管式命名空间可以在不使用它的情况下完成整个生命周期(请参阅代管式命名空间生命周期)。

当前

对于 Weave SDK 的相应部分或模块,任何使用 Current 标识或任何非代管式命名空间管理的任何命名空间(例如,缺少代管式命名空间标识)均表示当前官方支持的默认 API。虽然仍有可能持续改进此类 API,但更改主要是增量和向后兼容性,因此 API 和无线传输方式均应得到维护。

当前的代管式命名空间指定为可选操作,因此代管式命名空间可能会在不使用它的情况下完成整个生命周期(请参阅代管式命名空间生命周期)。实际上,任何非代管式命名空间都隐式为当前命名空间。

旧式

任何使用“旧版”标识管理的命名空间会向开发者和集成者表明,其中包含的 API 已弃用,取而代之的是新的当前 API。这些 API 代表当前的 API。

如此指定的 API 将在下一个主要的 Weave SDK 版本中完全消失;因此,如果开发者和集成商打算继续保持 Weave SDK 版本的前沿技术,则应制定从这些 API 迁移的计划。

代管式命名空间生命周期

下图说明了代管式命名空间从开发(可能)过渡到旧版时的生命周期:

.-------------.      .- - - .      .- - - - -.      .--------.
| Development | -.->   Next   -.->   Current   ---> | Legacy |
'-------------'  |   '- - - '  |   ' - - - - '      '--------'
                 |             |
                 '-------------'

如果使用,则代管式命名空间生命周期将从“开发”标识开始。

当开发完成且代码准备好进行评估和集成时,标识将迁移至“Next”或“Current”。或者,可以完全删除该标识,并且不再使用受管命名空间,从而有效地使该标识隐式为当前有效。

如果该代码与当前代码共存,且尚未取代当前代码,则相应标识应迁移到 Next。如果相应代码将取代当前代码,则相应标识应迁移至当前代码。

使用“下一个”标识,在代码经过所需数量的发布和评估周期后,该标识会变为“当前”,或者同样可能会完全失去该标识。

使用“当前”标识时,如果相应代码将被新代码取代,但仍需要在多个发布周期内进行维护,则该标识会变为“旧版”。

从旧版标识中,代码最终会从 Weave SDK 中完全移除。

使用代管式命名空间

Weave SDK 用户可以以开发者身份(扩展和维护现有代码)或以集成商身份(将 Weave 集成到自己的应用、平台和系统代码中)与代管式命名空间进行交互。以下两部分从这两个角度详细介绍了处理 Weave 代管式命名空间的建议。

以开发者身份使用代管式命名空间

Weave SDK 开发者的重点是增强和开发新的 Weave SDK API 和功能,同时在许多情况下为现有的 API 和功能部署提供支持。

如果无法在同一 API 中以向后兼容的方式同时满足这两个重点领域,则代管式命名空间提供了一种机制来并行管理这些 API,且不会中断现有的 API 和功能部署。

作为一个可行的示例,假设 Weave 配置文件 Mercury 目前位于以下非代管式命名空间层次结构下:

namespace nl {
namespace Weave {
namespace Profiles {
namespace Mercury {

// ...

}; // namespace Mercury
}; // namespace Profiles
}; // namespace Weave
}; // namespace nl

和以下公开标头:

  • Weave/Profiles/Mercury/Mercury.hpp
  • Weave/Profiles/Mercury/Bar.hpp
  • Weave/Profiles/Mercury/Foo.hpp
  • Weave/Profiles/Mercury/Foobar.hpp

其中 Mercury.hpp 是模块“umbrella”标头。大多数集成商只会包含模块“伞形”标头,如下所示:

#include 

然而,Mercury 的开发阶段已经达到这样一个点:需要开发新一代 API,可能还需要开发不向后兼容现有部署的无线协议。使用代管式命名空间有助于在不破坏这些现有部署的情况下实现这一点。

将现有命名空间移至当前命名空间

为了继续为当前已部署的集成版本的 API 和功能提供支持,第一个任务是移动当前代码:

% cd src/lib/profiles/mercury
% mkdir Current
% mv Mercury.hpp Bar.hpp Foo.hpp Foobar.hpp *.cpp Current/

请注意,除了移动文件之外,还应重命名文件头包含的受移动文件保护,并可能使用“_CURRENT”对其进行装饰,因为名称相似的新文件将在下方创建。

移动代码后,下一步是使用适当标识(此处为“Current”)管理命名空间。首先,创建一个将托管命名空间定义为“Current/MercuryManagednamespace.hpp”的标头。如果有多个头文件,那么创建此类头文件比在每个头文件中重复和复制此内容更可取。

% cat << EOF > Current/MercuryManagedNamespace.hpp
#ifndef _WEAVE_MERCURY_MANAGEDNAMESPACE_CURRENT_HPP
#define _WEAVE_MERCURY_MANAGEDNAMESPACE_CURRENT_HPP

#include 

#if defined(WEAVE_CONFIG_MERCURY_NAMESPACE) && WEAVE_CONFIG_MERCURY_NAMESPACE != kWeaveManagedNamespace_Current
#error Compiling Weave Mercury current-designation managed namespace file with WEAVE_CONFIG_MERCURY_NAMESPACE defined != kWeaveManagedNamespace_Current
#endif

#ifndef WEAVE_CONFIG_MERCURY_NAMESPACE
#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Current
#endif

namespace nl {
namespace Weave {
namespace Profiles {

namespace WeaveMakeManagedNamespaceIdentifier(Mercury, kWeaveManagedNamespaceDesignation_Current) { };

namespace Mercury = WeaveMakeManagedNamespaceIdentifier(Mercury, kWeaveManagedNamespaceDesignation_Current);

}; // namespace Profiles
}; // namespace Weave
}; // namespace nl

#endif // _WEAVE_MERCURY_MANAGEDNAMESPACE_CURRENT_HPP
EOF

接下来,将此标头添加到现有标头中的其他特定于模块的 include 指令之前。例如:

#include 

#include 

创建兼容性标头

但是,将现有标头移到新位置并仅管理其命名空间不足以确保现有部署在不更改的情况下正常运行,因为它们都使用 include 指令,指定刚才移动的标头。

为了解决此问题,必须创建名称与刚刚移动的兼容性封装容器标头的兼容性封装容器标头。

% touch Mercury.hpp Bar.hpp Foo.hpp Foobar.hpp

如果只创建 Current 指定的代管式命名空间,而未创建与之对应的 Development 或 Next 指定的代管式命名空间,则这些文件的内容只需包含 guard 和 include 指令(用于指定新迁移的同名标头):

#ifndef _WEAVE_MERCURY_BAR_HPP
#define _WEAVE_MERCURY_BAR_HPP

#include 

#endif // _WEAVE_MERCURY_BAR_HPP

但是,如果要同时创建“Development”或“Next”指定的代管式命名空间来适应新的不兼容开发,则需完成稍微复杂一些的情况。

和之前一样,创建了托管命名空间配置的标头,此处为 MercuryManaged 命名空间.hpp。同样,如果有多个头文件,此方法比在每个头文件中重复和复制此内容更可取。

% cat << EOF > MercuryManagedNamespace.hpp
#ifndef _WEAVE_MERCURY_MANAGEDNAMESPACE_HPP
#define _WEAVE_MERCURY_MANAGEDNAMESPACE_HPP

#include 

#if defined(WEAVE_CONFIG_MERCURY_NAMESPACE)                             \
  && (WEAVE_CONFIG_MERCURY_NAMESPACE != kWeaveManagedNamespace_Current) \
  && (WEAVE_CONFIG_MERCURY_NAMESPACE != kWeaveManagedNamespace_Development)
#error "WEAVE_CONFIG_MERCURY_NAMESPACE defined, but not as namespace kWeaveManagedNamespace_Current or kWeaveManagedNamespace_Development"
#endif

#if !defined(WEAVE_CONFIG_MERCURY_NAMESPACE)
#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Current
#endif

#endif // _WEAVE_MERCURY_MANAGEDNAMESPACE_HPP
EOF

请注意,如果未定义任何配置,这会根据需要默认将代管式命名空间指定为“Current”。

添加此标头后,现在可以修改兼容性封装容器标头,使其包含:

#include 

#if WEAVE_CONFIG_MERCURY_NAMESPACE == kWeaveManagedNamespace_Development
#include 
#else
#include 
#endif // WEAVE_CONFIG_MERCURY_NAMESPACE == kWeaveManagedNamespace_Development

或者任何适合当前命名空间管理使用场景的内容。

创建开发内容

至此,基础架构就已准备就绪,可以开始构建新功能和 API,同时保留现有功能。

% mkdir Development
% touch Development/Mercury.hpp Development/Bar.hpp Development/Foo.hpp Development/Foobar.hpp
% cat << EOF > Development/MercuryManagedNamespace.hpp
#ifndef _WEAVE_MERCURY_MANAGEDNAMESPACE_DEVELOPMENT_HPP
#define _WEAVE_MERCURY_MANAGEDNAMESPACE_DEVELOPMENT_HPP

#include 

#if defined(WEAVE_CONFIG_MERCURY_NAMESPACE) && WEAVE_CONFIG_MERCURY_NAMESPACE != kWeaveManagedNamespace_Development
#error Compiling Weave Mercury development-designated managed namespace file with WEAVE_CONFIG_MERCURY_NAMESPACE defined != kWeaveManagedNamespace_Development
#endif

#ifndef WEAVE_CONFIG_MERCURY_NAMESPACE
#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Development
#endif

namespace nl {
namespace Weave {
namespace Profiles {

namespace WeaveMakeManagedNamespaceIdentifier(Mercury, kWeaveManagedNamespaceDesignation_Development) { };

namespace Mercury = WeaveMakeManagedNamespaceIdentifier(Mercury, kWeaveManagedNamespaceDesignation_Development);

}; // namespace Profiles
}; // namespace Weave
}; // namespace nl

#endif // _WEAVE_MERCURY_MANAGEDNAMESPACE_DEVELOPMENT_HPP
EOF

当然,如果某个模块比此处展示的示例简单得多,并且没有很多类、源文件、文件或标头,那么只需在同一个头文件中实现所有这些操作,无需移动文件,也无需创建多个独立的配置和兼容性标头。不过,在这个复杂的示例中,应该可以为从复杂到简单的托管命名空间解决方案提供灵感。

使用代管式命名空间作为集成商

Weave SDK 集成商的主要工作是添加适当的 Weave SDK 公共 API 标头,并针对这些标头集成和开发应用。

再举一个实际的例子,假设 Weave 个人资料 Mercury 有指定的受管命名空间 Next-、Current- 和 Legacy,其公开标头的结构如下所示:

  • Weave/Profiles/Mercury/Mercury.hpp
  • Weave/Profiles/Mercury/Bar.hpp
  • Weave/Profiles/Mercury/Foo.hpp
  • Weave/Profiles/Mercury/Foobar.hpp
  • Weave/Profiles/Mercury/Next/Mercury.hpp
  • Weave/Profiles/Mercury/Next/Bar.hpp
  • Weave/Profiles/Mercury/Next/Foo.hpp
  • Weave/Profiles/Mercury/Next/Foobar.hpp
  • Weave/Profiles/Mercury/Current/Mercury.hpp
  • Weave/Profiles/Mercury/Current/Bar.hpp
  • Weave/Profiles/Mercury/Current/Foo.hpp
  • Weave/Profiles/Mercury/Current/Foobar.hpp
  • Weave/Profiles/Mercury/Legacy/Mercury.hpp
  • Weave/Profiles/Mercury/Legacy/Bar.hpp
  • Weave/Profiles/Mercury/Legacy/Foo.hpp
  • Weave/Profiles/Mercury/Legacy/Foobar.hpp

其中 Mercury.hpp 是模块“umbrella”标头。

除非当前的用例促使在 Weave 中明确添加命名空间管理的模块,例如:

#include 

最好通过非受管默认路径(例如 Weave/Profiles/Mercury/Mercury.hpp)引用 Weave 模块的公开头文件。这样做可以遵循 API 开发的进度,而无需随着项目的 include 指令不断更改,因为这些 API 经过受管理lifecycle

按照此策略,部署随后可以通过在 C/C++ 预处理器中指定所需的配置,以不同的代管式命名空间标识(例如“当前”标识)重新定位其代码。这可以在命令行、源代码、配置或前缀标头中完成:

#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Current

并使用非受管 / 非限定包含路径:

#include 

当目标 API 的受管命名空间标识发生变化(例如从“当前”更改为“旧版”)时(以及时),只需调整预处理器定义即可进行重新定位:

#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Legacy