处理弃用

弃用通常用于允许 API 随时间演进,通过逐步淘汰不再流行的 API 函数并用更新、更强大的替代方案替换它们。本页解释了 GNOME 堆栈中的库如何处理弃用,以及它们为应用程序开发者(也就是您)提供的处理弃用的机制。

需要记住的一点是,“已弃用”并不意味着“已损坏”或“不可用”。无需立即用其替代方案替换每个已弃用的函数。相关库的下一个主要版本(弃用 API 可能被删除的时间点)可能还有数年时间。在此之前,继续使用这些函数是完全可以的。

基础

如何识别一个函数已被弃用? 近几年来,GNOME 库在它们的头文件中以如下方式标注弃用:

GLIB_DEPRECATED_IN_2_26
void         g_completion_clear_items   (GCompletion*    cmp);

GLIB_DEPRECATED_IN_2_40_FOR(g_settings_schema_key_get_range)
GVariant *   g_settings_get_range        (GSettings   *settings,
                                          const gchar *key);

GDK_DEPRECATED_IN_3_10
void     gtk_window_reshow_with_initial_size (GtkWindow *window);

这些标注在 GLib 头文件中定义为宏,它们会扩展为函数属性,导致 C 编译器在使用这些函数时发出警告。

此外,已弃用函数的文档注释包含一个 Deprecated: 标签

/**
 * g_completion_clear_items:
 * @cmp: the #GCompletion.
 *
 * Removes all items from the #GCompletion. The items are not freed, so if the
 * memory was dynamically allocated, it should be freed after calling this
 * function.
 *
 * Deprecated:2.26: Rarely used API
 */

/**
 * g_settings_get_range:
 * @settings: a #GSettings
 * @key: the key to query the range of
 *
 * Queries the range of a key.
 *
 * Since: 2.28
 *
 * Deprecated: 2.40: Use g_settings_schema_key_get_range() instead.
 */

/**
 * gtk_window_reshow_with_initial_size:
 * @window: a #GtkWindow
 *
 * Hides @window, then reshows it, resetting the
 * default size and position of the window. Used
 * by GUI builders only.
 *
 * Deprecated: 3.10: GUI builders can call gtk_widget_hide(),
 *   gtk_widget_unrealize() and then gtk_widget_show() on @window
 *   themselves, if they still need this functionality.
 */

注意

如果您是库维护者:重要的是“Deprecated”标签不仅包含符号被弃用的版本,还包含如何用非弃用的 API 替换该符号的说明(如果存在替换方案)。

弃用警告

最终,GDK_DEPRECATED_IN_3_10 宏会扩展为一个编译器属性——例如 GCC 中的 __attribute__((__deprecated__))——这会导致现代编译器在编译程序时发出警告;例如

$ make testheaderbar
CC       testheaderbar.o
testheaderbar.c: In function ‘main’:
testheaderbar.c:192:3: warning: ‘gtk_window_reshow_with_initial_size’ is deprecated (declared at ../gtk/gtkwindow.h:419) [-Wdeprecated-declarations]
  gtk_window_reshow_with_initial_size (GTK_WINDOW (window));
  ^
CCLD     testheaderbar

请注意,这只是一个警告:程序仍然成功构建了。

提示

当您决定将代码移植到远离已弃用符号时,您可以要求编译器将弃用警告转换为错误;例如,使用 GCC,您可以将 -Werror=deprecated-declarations 添加到您的编译器标志中。

忽略所有弃用警告

如果您想忽略弃用警告,您可以告诉编译器不要发出警告——例如,使用 GCC,您可以将 -Wno-deprecated-declarations 添加到您的编译器标志中。或者,您可以禁用您正在使用的库的弃用警告——例如,通过将以下内容添加到您的 meson.build 文件中

add_project_arguments([
    '-DGLIB_DISABLE_DEPRECATION_WARNINGS',
    '-DGTK_DISABLE_DEPRECATION_WARNINGS',
  ],
  language: 'c',
)

提供弃用标注的每个库都应提供禁用它们的方法。

选择性地忽略弃用警告

有时,即使您的代码在其他方面没有弃用,避免某些已弃用的函数也是不切实际的。在这种情况下,您可能不想禁用所有弃用警告,而是仅选择性地标记使用已弃用函数的代码部分

G_GNUC_BEGIN_IGNORE_DEPRECATIONS

gtk_window_reshow_with_initial_size (window);

G_GNUC_END_IGNORE_DEPRECATIONS

针对特定库版本

如果您的应用程序是针对某个版本的库开发的,例如 GLib 2.56,并且您希望确保它继续适用于该版本的 GLib 以及更新版本,那么您需要担心两件事。

GLib 的新版本可能会弃用您正在使用的 API。您没有理由停止使用它,因为它在 2.56 中没有被弃用(并且替换方案可能在 2.56 中不可用),但您也希望在较新的 GLib 版本下构建您的应用程序而不会出现警告。

即使您的开发系统具有较新版本的 GLib,您也希望避免使用 GLib 在 2.56 之后引入的 API,以使您的应用程序在具有 GLib 2.56 的系统上正常工作。

GNOME 堆栈中的弃用和 API 添加都经过版本控制,这使您可以通过定义应用程序预期工作的 API 版本范围来实现这些目标。这通过一对宏来完成,这些宏通常在您的 meson.build 文件中定义

add_project_arguments([
    '-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_56',
    '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_56',
  ],
  language: 'c',
)

每个库都有自己的宏。对于 GLib,它们是 GLIB_VERSION_MIN_REQUIREDGLIB_VERSION_MAX_ALLOWED。对于 GTK,它们是 GDK_VERSION_MIN_REQUIREDGDK_VERSION_MAX_ALLOWED

这些宏的定义必须以二进制格式编码主版本号和次版本号。您可以选择使用预定义的数值,例如 GLIB_VERSION_2_56GDK_VERSION_3_10,或者使用 G_ENCODE_VERSION 宏,如下所示

#define GLIB_VERSION_MIN_REQUIRED G_ENCODE_VERSION(2,56)

重要提示

必须在包含相应库的头文件之前定义 MIN_REQUIREDMAX_ALLOWED 宏。

其他参考资料