是否有标准方法允许静态库的使用者定义库中使用的函数(C) 问题

是否有标准方法允许静态库的使用者定义库中使用的函数(C) 问题,c,compilation,linker,embedded,static-libraries,C,Compilation,Linker,Embedded,Static Libraries,是否有一种“惯用”或标准方法(在C语言中)允许静态库的使用者在定义良好的点“注入”自定义代码,以提供特定于使用者的行为? 背景 我在一个项目上写了很多代码,我遇到了这样的需要…例如,我在一个定制的SOM板上为一个微控制器写代码,它可以插入到不同的主板上,每个主板上都有不同的传感器和执行器。我们编写了一个引导加载程序,根据SOM插入的主板,它可以检测并引导知道如何使用该主板的正确应用程序 所有这些应用程序可能都希望共享公共组件,但也要定义自己的非共享自定义组件 因此,该项目的结构为“多目标项目”,

是否有一种“惯用”或标准方法(在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/
目录中的项目应该编译为静态库,并针对两个应用程序映像进行链接但是,如果
通用/可重用的业务逻辑
中的某些内容需要依赖于应用程序“导出”的函数,该怎么办?
大多数
可重用的业务逻辑
代码确实是可移植的,但它最终可能需要调用自定义的
应用程序发送()
函数,该函数根据是针对app1还是app2(在应用层定义)链接而变化

尝试解决方案 我想象这样做的方式是让
通用/可重用\u业务逻辑层调用一个未实现的函数,该函数可以在链接时解析。因此,通用层中的函数将定义
外部某些类型的应用程序发送(某些类型)
asextern在公共头文件中,然后在整个代码中自由使用它。同时,公共业务逻辑的使用者app1和app2需要定义各自的此功能实现,以便构建


但这感觉既混乱又错误。有没有更好或更惯用的方法来完成我要做的事情

我见过两种方法中的一种:

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

第二个就是您已经尝试过的——特定于项目的标题。本质上,公共代码只有一个头/一组头,声明目标特定代码将需要实现的函数的原型(通常与公共代码本身使用的头分开),这些头由各个实现使用,每个实现都定义了所需的函数。库将丢失特定于目标的函数的定义,但这并不会真正改变什么-只要在链接最终可执行文件时有一个所有已使用函数的定义,就不会有任何问题。对于你正在解决的问题,这既不是一个不寻常的解决方案,也不是一个特别糟糕的解决方案;这些工具非常明确地支持它,并且能够在不产生任何开销的情况下解决问题——生成的二进制文件与将可重用组件全部复制到每个项目中并直接使用的情况相同,而无需这样做

第二个选项的一个变体是使用弱符号(至少在GCC中声明为
\uuuuu attribute\uuuuu((弱))
,并且在不同的编译器下可能声明不同)-这让您拥有特定于目标的功能的默认实现,包括在库本身中-这实际上不会改变任何东西,但是,如果大多数目标只需要一个“默认”实现,而有些则需要特定的差异,那么这可能很有用——这样,您就可以避免为所有将使用它的实现重新编写默认值


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

在我们的汽车ECU中,我们使用AUTOSAR及其通过MCAL进行的抽象以及基于通道和RTE的更高层硬件抽象和服务以及软件组件及其端口和接口

AUTOSAR的另一个特性是预编译、链接时和后期生成配置之间的可能分离

所以您可以从标准实现中分离配置

这还允许物理通道(有线硬件)和映射到物理通道的逻辑通道,以及基于其通道ID的逻辑通道行为。此外,帧/PDU由PDUID及其在每个配置中配置的调用进行抽象

在引导/启动阶段,我们有一个特定的检测机制,例如,可以使用一个通用的“未知”配置,该配置允许在部分关闭和重新配置最终启动初始化和配置后进行检测,例如,重新配置左/右ECU的通信堆栈(包括在通道之间的一个或两个ECU中布线,转动通道,因为它未连接在另一个ECU上),在两个ECU上都有PWM输出,在一个位置用于驱动蜂鸣器,同时驱动另一个ECU上的加热器或LED

AUTOSAR CompileRableStraction允许提取编译器差异,例如
\uuuu属性
\pragma
@far
/
apps/
    app1/ 
        app1_layer1/
        app1_layer2/
        config/      <-- driver/business logic config app1
        main.c

    app2/
        app2_layer1/
        app2_layer2/
        config/      <-- driver/business logic config app2
        main.c