This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 编译器/TMS320DM6435:生成程序级优化库(包括具有另一个构建选项的文件)时的链接器问题

Guru**** 2538930 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/571678/compiler-tms320dm6435-linker-problem-when-generating-a-program-level-optimized-library-including-a-file-with-another-build-option

部件号:TMS320DM6435

工具/软件:TI C/C++编译器

你好

我在构建包含一些库的主项目时遇到了问题,其中一个库(pf_drv_dm6435xp_eabi)是程序级优化的,并且具有另一个生成选项的文件。

如果我在CCS6下生成发行主项目,并且工作空间中的库的生成设置为debug,则生成将失败并出现链接器错误。 但是,主项目中库的依赖关系是固定的,以发布为基础,而不是调试为基础。

如果我将库(pf_drv_dm6435xp_eabi)切换为释放并重构建它,则可以很好地生成整个主项目。 奇怪!

第一步失败的问题是编译器在程序级优化库中编译2个文件。 还不错! 但链接程序工作错误。 它会生成第一个文件并将其始终链接到第二个文件。 因此函数的定义在库中加倍,并且主项目的链接程序调用错误。

在重建的第二步中,此文件未链接到第二个目标文件。 为什么? 您知道问题吗? 可以帮帮我吗?

我的问题是,我们的Jenkins通过命令行调用构建流程,并遇到错误。 我没有机会重建它。  我可以在Jenkins上构建发行版本。

 

主构建结束时的链接器消息为:

错误#1.0056万:重新定义符号"GpioFraming_waitBegin":首次定义在"C:/Jenkins Slave/workspace/rnd/FA/IVC/DSP_projects/PXV_SIL_DM64brche/PF_DRV_DV_DRV_lib/pref/pref_64brind_DPS_64f_D




以下是我的软件版本:

CCS6:  6.1。2.0.0015万
TI编译器:7.4 .................................................................17.

此致,

Thomas

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很遗憾,我不确定发生了什么。  我将提供有关错误消息的一些基本背景信息。  这应该有助于您更好地理解事情。

    假设您创建了名为custom.lib的库,其中包含这两个源文件。

    /* one.c */
    
    void one () {/* code here */}
    void never called(){/* code here */}
    
    /* two.c */
    
    void two() {/* code here */}
    void never called(){/* code here */} 

    假定主应用程序代码调用函数one()和twi(),但不调用never调用()。  在这种情况下,您会收到与您遇到的错误信息类似的错误信息。  符号never被调用()被定义两次,一次用于链接程序从库custom.lib引入的每个对象模块。

    在您的案例中,可能导致类似情况的一个因素是...

    Thomas Caspari 说:
    我在构建包含一些库的主项目时遇到问题,其中一个库(pf_drv_dm6435xp_eabi)是程序级优化的

    我非常确定,您的意思是库的源文件都是使用单个调用cl6x生成的,并且 使用了选项--program_lever_compile (或-pm表示简称)。  如果是这种情况,我建议您停止使用 --program_lever_compile。  构建库时不适合使用该选项。  您希望对象库在大多数情况下为每个文件定义一个函数。  然后,让链接程序仅提取被调用的函数/文件。  

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好George

    是的,您对最后的陈述是正确的。 我使用cl6x和选项–pm构建库。 好的,我看到您说库不适合使用此选项,但我不明白为什么? 如果我删除此选项,这将有助于解决我的问题,但我不知道此编译代码是否与–pm一起工作。

    但我将解释一个发生了什么的示例,因为您的示例不正确。

    假设我要创建具有5个文件的库,文件名为:one.c,two.c….five.c. 该库具有编译器标志–o=2,但我不想对文件one.c进行优化,并为其提供选项-0=0
    如果我对库使用选项–pm,编译器将启动并编译文件one.c并生成one.obj文件。 然后,它通过编译文件2.c到5.c来创建一个2.obj文件。 最后,它将2个对象文件one.obj和2.obj链接到库链接文件。 完成并确定。

    问题是,编译器错误地生成了第一个one.obj,但two.obj不正确! 因为它还将文件one.c包含在two.obj中。 在这种情况下,我从one.c中获得了一个包含两次代码的库,并且在我的主应用程序的最终版本中出现了双重定义错误。

    构建方式与我在CCS6下构建项目的方式不同。
    示例:

    我要使用在发行版本中具有选项标志–pm的库生成项目。 我将这两个项目文件都导入到CCS6中,并在主项目中为调试版本设置对库的依赖关系调试版本,为发行版本将依赖关系发行版导入到库中。
    在CCS6中,主发行版处于活动状态,而对于库,则为调试版本。 这应该不是问题,因为如果我启动主项目的生成,它首先编译库为Release (依赖关系已设置),然后编译主项目。 但在这种情况下,我得到了我上面描述的问题。
    我是否先调整库项目文件以发布并开始我的主项目的编译过程,它正确编译了库,我没有遇到问题。 为什么? 我不明白为什么软件会处理这种情况? 它对两个版本都使用相同的编译器选项,但在第一种情况下,它会将one.c代码链接2次到库中。

    好的,我希望你能理解这里的问题,以及我无法理解的问题。 我将在这里讨论从我们的库中删除生成选项–pm,但事实上,CCS6使用不同的内容编译同一个库项目会犯任何错误。

    感谢George的迅速回复!

    此致,

    Thomas
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我对拖延表示歉意。

    我怀疑您误解了选项--program_lever_compile (或简称-pm)的用途。  请参阅 C6000编译器手册 中标题为 “程序级优化”的部分。  激励思想的目的是揭示不可能的优化机会。  这是通过将以下三个部分组合在一起来实现的:--program_level_compile,--opt_level=3,以及同时生成多个文件。

    将其与代码库的用途进行对比。  这是不能更不同的。  库提供一组相关的函数。  库的用户只调用库中所需的函数。  库中的所有函数在一个程序中使用的情况很少(几乎是从不)。  因此,不可能满足其中一个要求,以实现由--program_lever_compile驱动的优化。  您不能一次生成所有文件。  库文件始终是单独构建的。

    因此,虽然在构建库时可以使用--program_level_compile --opt_level=3,但由于主应用程序代码不是同时生成的,因此只使用--opt_level=3就不能完成任何操作。

    因此,在构建库时,请停止使用--program_lever_compile。  我相信这将减少问题的数量。  它甚至可以解决所有这些问题。  

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好,George

    (披露:Thomas和我是同事)

    我不认为我完全同意您的观点。 据我所知,-pm会做两件事:

    1. 它将在源文件之间实现过程间优化(由-O3启用)
    2. 它假定所有调用站点都是可见的,除非以不同的方式指定(例如,通过#pragma FUNC_EXT_CALL或--call_假 定值),因此它将传播常量,消除参数等

    我认为大多数库都将从文件间优化中受益匪浅(除非整个实现在单个文件中提供,这可能不是组织代码的最明智的方式)。 此外,所有未公开公开的函数都将从2中受益,因为库外不会对这些函数进行任何调用。

    编译器文档(spru187u)中的以下摘录似乎建议您也可以并且应该对库使用-pm:

    您可以控制使用--program_level_compile --opt_level=3调用的程序级优化,
    使用--call_假 设选项。 具体来说,--call_假 设选项指明中的IF函数
    其他模块可以调用模块的外部函数或修改模块的外部变量。

    在同一文档中,模块定义如下:

    所有源文件都编译为一个称为模块的中间文件

    (强调我的)。

    如果一个应用程序可以包含多个模块(否则--call_假 设将毫无意义),则模块是使用-pm编译的源文件的任意集合,因此它很可能是一个库或其中的一部分。

    现在,我们的其中一个文件应该使用不同的优化设置进行编译,根据编译器文档(spru187u),这应该会导致构建系统单独编译该文件:

    在Code Composer Studio中,当使用--program_lever_compile选项时,具有相同选项的C和C++文件将一起编译。 但是,如果任何文件具有未被选择为项目范围选项的特定文件选项,则该文件将单独编译。

    这在过去很好,直到最近,我们开始看到Thomas在我们的一些CCS安装中提到的链接器错误(它在其他CCS上仍然正常工作),在这里,文件被编译(然后被放入库档案)两次,一次是单独编译的, 作为-pm创建的中间文件的一部分。 对我来说,这似乎是一个错误。

    此致

    Markus

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    经过进一步思考,我同意这一点。

    问题是,编译器错误地生成了第一个one.obj,但tw2.obj不正确! 因为它还将文件one.c包含在two.obj中。 在这种情况下,我从one.c中获得了一个包含两次代码的库,并且在我的主应用程序的最终版本中出现了双重定义错误。

    ...可能是由于CCS如何生成使用--program_lever_compile的项目的一些问题。  因此,如果您提交有问题的项目,我将不胜感激。

    至于是否有必要将--program_lever_compile应用到库... 对于大多数代码库,在大多数情况下,使用--program_lever_compile是没有意义的。  但你似乎想对它采取非常积极的态度。  在这种情况下,我还有另一项建议要考虑。  我从未见过有人这样做。  但我相信它会起作用。  Wiki文章 机械增压优化 讨论了如何将--program_level_compile --opt_level=3应用于相关的代码子集。  注意:本文使用的是这些选项中较旧的短格式:-pm -o3。  考虑将库源代码分成几个子集相关代码,并使用所述的生成选项。  每个子集生成一个对象文件。  然后将这些目标文件组合到一个库中。  一个缺点是您无法使用CCS进行构建。  CCS不支持以这种方式构建库。

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引述用户="George mock"]

    因此,如果您提交有问题的项目,我将不胜感激。

    [/引述]

    更好的是,我可以用我所附的一个很小的例子来重现这个问题。

    该示例包含一个库项目"Lib"和一个可执行项目"Main",其中Main依赖于Lib。

    库项目包含两个源文件lib1.c和lib2.c,每个源文件都实现了库函数g()和f()中的一个函数。

    项目的优化设置为调试配置的"-O0"和发布配置的"-O3 -pm",但lib2.c除外,即使对于发布配置,lib2.c的文件特定设置也为"-O0"。

    我们还注意到另外两件事:

    1. 仅当在工作区中,Lib的活动配置为“调试”,而Main的活动配置为“发行”时,才会出现该问题。 然后,如果生成Main,则Lib的Release配置作为依赖项被拉入,但lib2.c以某种方式被编译两次。 如果您将Lib的活动配置设置为"发布",则问题消失(遗憾的是,这也会影响无外设版本,因此我们无法通过简单选择正确的配置来解决问题)
    2. 当我设置示例工作区时,我可以重现该问题,但犯了一个我想修复的愚蠢错误,所以我重新开始了。 虽然我很确定我对项目做了同样的更改,但这次我没有重现问题。 于是我又重新开始了,瞧,问题又重新出现了。 除非我第二次做了错误的事情,否则我想知道我更改设置的顺序是否对该问题有任何影响。

    此致

    Markus

    e2e.ti.com/.../ProgramMode.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    很遗憾,我无法再现此问题。  我尝试了几种不同的变体。  我总是得到一个干净的版本。

    请提供有关如何设置和构建这两个项目的详细分步说明。  我怀疑一些微小的细节是什么导致事情出错。  我意识到这是困难的,但我想不出另一种方法来捕捉这一关键细节。

    谢谢,此致,

    -George

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好George

    今天,我从Markus那里获得了zip文件,并将其内容保存到一个新的分目录中。 然后,我启动了新的CCS7,创建了一个新的工作空间,并将项目(lib和main)导入到我的工作空间中。 然后,我完成了以下步骤,而不是更多:

     1.右键单击“主程序”和“生成配置->设置为活动->释放”
     2.开始构建"主要"项目

    就这些。 这表明我的PC上存在相同的问题。 我将为您附加控制台输出。 我希望这将帮助您产生错误。

    代码编辑器工作室版本: 版本:7.0 .0.0.0042万
    编译器版本:                        TI 7.4 Tm16.

    其他信息:Markus和我在不同的计算机上使用CCS6编译器6.1 .2.0.0015万 版时出现相同的错误。

    谢谢,此致

    Thomas

    /cfs/file/__key/communityserver-discussions-组件文件/81/2275.console_2D00_output_2D00_ccs7.txt

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您提供准确的指导。  我可以重现该问题。  我在 SDOWP系统中提交了CCSEIDE-3068以解决此问题。  欢迎您使用我签名中下面的SDOWP链接进行关注。

    谢谢,此致,

    -George