首页 > 解决方案 > 是否有标准方法允许静态库的使用者定义库中使用的函数(C)

问题描述

问题

是否有“惯用”或标准方式(在 C 中)允许静态库的消费者在定义明确的点将自定义代码“注入”到其中,以便提供特定于消费者的行为?

背景

我在一个项目中编写的大量代码中遇到了这样的需求......例如,我正在为能够插入的自定义 SOM 板上的微控制器编写代码各种不同的主板,每个主板上都有各种不同的传感器和执行器。我们编写了一个引导加载程序,根据 SOM 插入的主板,它可以检测并引导知道如何使用该主板的正确应用程序。

所有这些应用程序都可能希望共享公共组件,但也定义自己的非共享自定义组件。

因此,该项目被构造为“多目标项目”,其中我们的组织类似于以下内容:

lib/
  somelib1/
  somelib2/

common/
  chip_drivers // from silicon vendor
  SOM_drivers  // HW drivers for stuff on the SOM
  reuseable_business_logic // don't want to copy-paste into each app

apps/
  app1/ 
    app1_layer1/
    app1_layer2/
    main.c

  app2/
    app2_layer1/
    app2_layer2/
    main.c

我想lib/common/目录中的项目应该编译为静态库并链接到两个应用程序图像。但是,如果某些东西common/reusable_business_logic需要依赖于应用程序“导出”的函数怎么办?大多数reusable_business_logic代码是真正可移植的,但是它最终可能需要调用一个自定义app_send()函数,该函数取决于它是链接到 app1 还是 app2(在应用程序层定义)。

尝试的解决方案

我想象这样做的方式是让common/reusable_business_logic层调用一个未实现的函数,该函数可以在链接时解决。因此,公共层中的函数将在公共头文件中定义extern some_type app_send(some_type)extern,然后在整个代码中自由使用。同时,共同业务逻辑的消费者 app1 和 app2 需要自己定义该功能的实现才能构建。

但这感觉混乱和错误。有没有更好或更惯用的方法来完成我打算做的事情?

标签: ccompilationlinkerembeddedstatic-libraries

解决方案


我已经看到这是通过以下两种方式之一完成的:

首先,正如评论中提到的,回调。这是非常广泛使用且易于实现的。在初始化时将函数指针传递给公共代码可能是一种完全有效的方法,尽管它确实引入了可能不需要关注的状态。

其次几乎是您已经尝试过的 - 项目特定的标题。本质上,公共代码只有一个标头/一组标头,声明目标特定代码需要实现的函数的原型(通常与公共代码本身使用的标头分开),并且这些标头由各个实现,每个实现都定义了所需的功能。该库将缺少目标特定函数的定义,但这并没有真正改变任何东西 - 只要在最终可执行文件被链接时对所有使用的函数都有定义,真的应该'不会有任何问题。对于您正在解决的问题,这既不是罕见的解决方案,也不是特别糟糕的解决方案;工具非常明确地支持它,

第二个选项的一个变体是使用弱符号(__attribute__((weak))至少在 GCC 中声明,并且可能在不同的编译器下以不同的方式声明) - 这使您可以拥有目标特定功能的默认实现,包含在库本身中 - 这确实没有t 改变任何东西,但如果大多数目标只需要“默认”实现,但有些需要特定差异,则可能很有用 - 这样,您可以避免为所有将使用它的实现重写默认值。

当我不得不将第二个选项用于您所描述的情况时,我个人更喜欢第二个选项,因为在运行时出现问题的可能性较低,但在某些情况下,第一个选项可能更灵活,因为函数指针可以被交换以在运行时而不是编译时更改功能。


推荐阅读