首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IAR EWARM中的条件链接

IAR EWARM中的条件链接
EN

Stack Overflow用户
提问于 2019-03-04 20:20:36
回答 3查看 956关注 0票数 1

我使用IAR 8.10.1,它使用ILINK链接器。

我有一个共同的标题,两个编译单元使用。它包括具有外部链接的函数的原型,并构成一个API。根据构建的配置方式,我希望模块A或B与我的应用程序的其余部分链接。

代码语言:javascript
复制
[ Common_Header.h ]
    |         |
    |         +----- [Module_A.c] ---> [Module_A.o]
    |
    +--------------- [Module_B.c] ---> [Module_B.o]

不知何故,我想将一个参数传递给ilinkarm.exe,以包括Module_A.o。

我在过去使用过的其他IAR工具链使用了XLINK链接器。XLINK有一个-A选项,我认为这与我所需要的类似。

本质上,我希望Module_B中的函数定义被当作是__weak,而Module_A是活动的,反之亦然。

如果可能的话,我希望避免将#pragma weak放在代码中。我需要能够用几个不同的工具链编译这段代码。因此,我需要用类似于#ifdef __ICCARM__的东西来包装任何这样的沼气。此外,我还需要定义一些额外的预处理符号,以便在一个模块处于活动状态时有条件地使另一个模块弱。这都是复杂的问题,我更希望避免出现在代码中。

此外,当module_B处于活动状态时,我不希望将module_A排除在构建之外。我希望这两个模块都能编译。如果有人对接口和module_A进行了更改,但未能更新module_B,我希望他们得到一个编译器错误。这将使module_B不会随着接口的发展而陷入孤立和中断的状态,我们的注意力集中在module_A上。

我已经复习了EWARM_DevelopmentGuide.ENU.pdf,我找不到一个命令行选项,它似乎可以做我想做的事情。我想知道是否存在这样的选择,我已经错过了,或者是否有另一种方式来完成我想要的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-03-18 17:45:59

最后,我使用了类似于user694733建议的弱链接。但我的方法有点不同。

我在模块A和B的顶部加了一个这样的块。

代码语言:javascript
复制
#if (defined __ICCARM__)
    #if(defined USE_MODULE_A) && (1 == USE_MODULE_A)
        // do nothing, make definitions in this file strong
    #elif(defined USE_MODULE_B) && (1 == USE_MODULE_B)
        #pragma weak foo_fn
        #pragma weak bar_fn
        #pragma weak baz_fn
        #pragma weak qux_fn
    #else
        #error USE_MODULE_A or USE_MODULE_B must be defined.
    #endif
#endif

这种方法不需要我用MY_WEAK来装饰每个函数原型。所以这些非标准的东西都被聚在一起了。

我不喜欢使用__weak / #pragma弱的几样东西:

我不喜欢的第一件事是,它增加了两个模块之间的耦合。如果两个符号都没有定义,那么两个模块都会有弱定义。在那个时候,你怎么知道哪一个会被使用?因此,每个模块都必须存在另一个模块,或者至少有一个以上的选项。我本可以使用单个定义,只需更改值,但我选择了这样做,以便名称具有描述性。

我不喜欢的第二件事是,我把代码中的东西弄得乱七八糟,这是一个关于如何构建项目的工件。我想把这种逻辑拉出来,并在实际可行的时候把它放到建设系统中。

第三,它不是完全可移植的,必须用#if (defined __ICCARM__)关闭。

但这将是我所使用的,除非我找到更好的方法来完成这对我。如果发生这种情况,我会发帖/接受其他答案。

票数 1
EN

Stack Overflow用户

发布于 2019-03-05 15:18:10

这并不是一个完整的答案,因为我没有你的编译器的新版本,但更多的是一个可能的解决办法。

Module_A.c

代码语言:javascript
复制
#if MODULE_A_SELECTED
    #define MY_WEAK
#else
    #define MY_WEAK __weak
#endif

MY_WEAK void foo(void) { ... }
 ...

Module_B.c

代码语言:javascript
复制
#if MODULE_B_SELECTED
    #define MY_WEAK
#else
    #define MY_WEAK __weak
#endif

MY_WEAK void foo(void) { ... }
 ...

然后根据需要在配置中定义MODULE_*_SELECTED

票数 1
EN

Stack Overflow用户

发布于 2019-03-05 17:03:08

不需要依赖特定于链接器的支持或IDE特定的构建管理。一个完全可移植的解决方案是用不同的符号名定义A和B实现,然后使用有条件定义的宏来选择所需的实现。

示例:

代码语言:javascript
复制
#if defined USE_IMPLEMENTATION_A
    #define doSomething implementationA_doSomething

#elif defined USE_IMPLEMENTATION_B
    #define doSomething implementationB_doSomething

#else
    #error API implementation not defined
#endif

int implementationA_doSomething( void ) ;
int implementationB_doSomething( void ) ;

这样,实现A和B都将被编译,但是只使用宏doSomething而不是特定于实现的函数名来使用所选的API。

我不知道ILINK有多聪明,但是通过将实现放在单独的翻译单元(即.c文件)中,链接器应该能够从链接中消除未使用的函数。如果不是,如果您将对象代码放置在静态链接库(.lib或.a)中,则肯定会这样做。

为了解决维护两个除了名称空间前缀之外相同的实现文件的问题,您可以使用以下原型创建一个虚拟头文件:

代码语言:javascript
复制
int NAMESPACE_doSomething( void ) ;

然后使用像sed这样的工具来生成实现原型头,例如:

代码语言:javascript
复制
sed -i 's/NAMESPACE/api_a/g' api_dummy.h > api_a.h    
sed -i 's/NAMESPACE/api_b/g' api_dummy.h > api_b.h

然后有一个api.h文件,其中包含(片段):

代码语言:javascript
复制
#if defined USE_IMPLEMENTATION_A
    #define doSomething api_a_doSomething

#elif defined USE_IMPLEMENTATION_B
    #define doSomething api_b_doSomething

#else
    #error API implementation not defined
#endif

#include api_a.h
#include api_b.h

您可以进一步编写代码生成器,从函数名列表生成api.h。在您喜欢的脚本语言甚至C语言中,这不会太困难。您可以编写这样的生成器来获取命令行参数:

代码语言:javascript
复制
generate_api <input> <output> <namespace1> <namespace2> ... <namespaceN>

那就叫它:

代码语言:javascript
复制
generate_api functions.txt api.h api_a api_b

您甚至可以使用虚拟头中的NAMESPACE_文本来为<input>生成函数名列表,这样就可以从单个虚拟头生成整个API头集。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54990942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档