托管式命名空间

摘要

简介

在 Weave SDK 中使用托管命名空间,以便为 Weave SDK 开发者和集成商提供关于在 SDK 中指定特定 API 集的通告指南和辅助文本,以便他们可以规划和预测其跨 Weave SDK 版本的迁移路径,并可能管理针对指定模块的多个并发 Weave API。

标识

代管式命名空间可以作为以下四种类别之一进行管理:

开发

使用开发标识管理的任何命名空间都向开发者和集成商表明,其中包含的 API 正处于积极开发中,可能会发生更改,并且尚未获得正式支持。通常不鼓励集成商使用这些 API,除非经特别指示。

下一步

对于任何使用“Next”标识进行管理的命名空间,都向开发者和集成商表明,其中包含的 API 虽然基本已完成积极开发,但仍可能发生变化,并且可能仍受支持以进行早期评估。如此指定的 API 代表了 Weave SDK API 的下一阶段发展方向,并在近期或不久的将来在主要版本周期内成为当前的默认 API。

从 API 和无线协议的角度来看,向后兼容性都可能存在,但在 API 中并不保证一定能实现。

Next 代管式命名空间标识通过提示未来版本中会成为当前默认 API 的功能,有效地为开发者和集成商提供了了解 Weave SDK 发展方向的视图。

指定“下一个代管式命名空间”是可选的,以便代管式命名空间可以在不使用它的整个生命周期中转换(请参阅代管式命名空间生命周期)。

当前

使用当前指定的名称或任何非托管命名空间(即缺少指定的托管命名空间)管理的任何命名空间都代表 Weave SDK 的相应部分或模块当前、默认且官方支持的 API。虽然我们可能仍会对此类 API 进行持续增强,但相关更改在很大程度上是增量和向后兼容性的,API 和无线下载都应该得到维护。

指定当前代管命名空间是可选的,这样,代管命名空间就可以在整个生命周期中转换,而无需使用该命名空间(请参阅代管式命名空间生命周期)。事实上,任何非托管命名空间都隐式地为 Current。

旧版

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

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

代管式命名空间生命周期

下图说明了托管命名空间从开发阶段并可能转换到旧版时的生命周期:

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

如果使用,则托管命名空间生命周期以“开发”标识开始。

当开发完成且代码可用于评估和集成时,标识会迁移到 Next 或 Current。或者,也可以完全丢弃该标识,不再使用受管理的命名空间,从而有效地使该标识隐式成为 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”标头。大多数集成商只是将模块“umbrella”如下所示:

#include 

然而,水星公司的发展现在已经到了开发下一代 API 的必要性,可能还需要开发与现有部署不向后兼容的线上传输协议。使用代管式命名空间可以帮助实现这一点,而不会破坏这些现有部署。

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

为了继续支持当前版本的 API 和功能以用于现有已部署的集成,第一项任务是迁移当前代码:

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

请注意,除了移动文件外,还应重命名已移动文件的标头 include 保护,并可能使用“_CURRENT”装饰它们,因为名称相似的新文件将在下面创建其位置。

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

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

#include <Weave/Support/ManagedNamespace.hpp>

#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

如果仅创建了当前指定的托管命名空间,而没有创建开发或下一个指定的托管命名空间来与之一起创建,则这些文件的内容只需由一个头文件 include guard 和用于指定新移动的同名头文件的 include 指令组成:

#ifndef _WEAVE_MERCURY_BAR_HPP
#define _WEAVE_MERCURY_BAR_HPP

#include 

#endif // _WEAVE_MERCURY_BAR_HPP

但是,如果要创建开发或下一个指定的托管命名空间,以适应新的、不兼容的开发,则需要完成一些稍微复杂一些的操作。

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

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

#include <Weave/Support/ManagedNamespace.hpp>

#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 的基础上开始构建新功能和 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 <Weave/Support/ManagedNamespace.hpp>

#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 会经历托管生命周期

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

#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Current

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

#include 

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

#define WEAVE_CONFIG_MERCURY_NAMESPACE kWeaveManagedNamespace_Legacy