将单元添加到项目正在从项目源中删除编译器指令

Posted

技术标签:

【中文标题】将单元添加到项目正在从项目源中删除编译器指令【英文标题】:Add unit to project is removing a compiler directive from the project source 【发布时间】:2013-10-16 18:30:55 【问题描述】:

应该这样工作还是我做错了什么?

我的项目源中有这段代码:

  $IFDEF DEBUG
  ADebugUnit,
  $ELSE
  ARelaseUnit,
  $ENDIF

我希望在调试模式下使用 ADebugUnit,但在发布模式下编译时使用 AReleaseUnit。这很好用,除非我选择向项目添加新单元。当我这样做时,它基本上会处理代码,并且只保留与项目当前设置的任何配置相关的单元。

例如,如果配置设置为调试,那么在我的项目中添加一个新单元后,上面的代码将更改为:

ADebugUnit,

或者,如果我的配置设置为发布,添加新单元后将更改为以下内容:

ARelaseUnit,

添加新单元后,我必须始终将其恢复为条件语句。有没有办法在不添加新单元干扰的情况下完成此操作?

【问题讨论】:

我编写自己的 .dpr 文件并撤消 IDE 所做的更改。 VCS 有帮助。 .dpr 文件中的某些内容需要有条件。 不幸的是,IDE 也并不总是能完成干净的工作,而且经常会破坏整个项目文件。我什至看到它将uses 子句复制得更远,所以它被复制了。 我想声明我们有一份 Delphi XE5 副本,我们正在评估并在该环境中试一试,它可以按预期工作,因为我可以将条件包含在项目源并在 IDE 中使用添加单元选项,它不会删除条件编译器指令。这是我原本期望在 Delphi XE2 中工作的,但事实并非如此。 是的。与 DRP/DPK 相关时,Delphi IDE 确实搞砸了。 【参考方案1】:

问题在于 DPR 将不尊重使用列表中的任何 $ifdef,并且实际上会在重新写入使用列表作为响应时将它们删除(如您所见)到某些 IDE 操作。

一种选择是永远不要使用那些 IDE 操作,例如“添加/删除单元”等,并且只手动管理 DPR 使用列表。

或者稍加注意,您也许可以使用单元别名来实现您想要的。

根据构建配置(调试或发布)考虑您希望使用的两个单元:

DebugUnit.pas ReleaseUnit.pas

在您的项目选项中添加 Unit Alias 用于:

调试配置:

  UnitToUse=DebugUnit

RELEASE配置:

  UnitToUse=ReleaseUnit

在您的 DPR 中添加一个条目到使用列表中:

  uses
    UnitToUse,

DPR 中的此条目无法使用“in '”语法识别文件名,而必须依赖于项目搜索路径中所需的实际单元。

您通常会使用 DebugUnitReleaseUnit 的任何地方,请参阅 UnitToUse。显然,别名的名称完全取决于您。

如果这两个单元具有相同的接口“合同”,那么您的构建将通过更改目标配置在这两个单元之间切换。

如果他们有不同的接口契约,那么你仍然可以在你的应用程序代码中使用$ifdef指令来处理任何一个单元UnitToUse的内容> 酌情指代,例如

uses
  UnitToUse;


procedure DoSomethingInvolvingAliasedUnit;
begin
  $ifdef DEBUG
    // code which relies on the debug unit
  $else
    // code which relies on the release unit
  $endif
end;

【讨论】:

【参考方案2】:

IDE 拥有大部分 DPR 文件。小心你对它所做的事情,否则你会冒着你所观察到的风险(或者更糟 - 根据更改的性质,IDE 有时可能决定根本不允许编译该文件!)。

除其他外,这意味着您不能有条件地在 DPR 文件中包含单位。无论您试图解决什么问题,您都必须找到另一种解决方案。

例如,也许您可​​以在项目的其他地方使用该单元,而不是 DPR 文件。

或者也许您可以将两个单元合并为一个,然后对其内容进行条件编译。

或者,也许您可​​以一直使用调试代码,因为这会增加您发布测试过的相同代码的机会。

或者,如果此问题仅在您使用“添加单元”对话框时出现,您可以放弃该对话框并手动编辑 DPR 文件。将单元添加到项目中没有其他神奇之处,除了 uses 子句被重写,正如您所注意到的。

【讨论】:

同意,这是一个 PITA。有一些东西在 *.DPR 文件中不起作用,或者 IDE 偶尔会丢弃它们。这是其中之一。最好的建议是尽可能多地投入另一个单元。 @Rob - 我们可以根据需要手动添加单位,这就是我们解决它的方式(或事后修复它)。虽然我们正在考虑完全消除条件,这将是理想的解决方案。【参考方案3】:

为了建立 Rob 的答案,每当我遇到需要执行此类操作的情况时,我都会将所有 DPR 代码迁移到另一个单元,例如 AppInit.pas

unit AppInit;

interface

uses
  Vcl.Forms,
  Unit1,
$IFDEF DEBUG
  ADebugUnit
$ELSE
  AReleaseUnit
$ENDIF
  ;

procedure RunApp;

implementation

procedure RunApp;
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.Title := 'Sample Application';
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end;

end.

那么你的项目单元就只有

program SampleApp;

uses
  Vcl.Forms,
  Unit1 in 'Unit1.pas' Form1,
  AppInit in 'AppInit.pas';

$R *.res

begin
  RunApp;
end.

这样做的缺点是 IDE 会混淆它是什么类型的应用程序,当您转到 Project > Options 时,某些功能将被禁用,例如 VCL 样式。有了正确的编码,这样的事情仍然可以实现。

PS - 请原谅我 100% 直接将它写到 *** 中,如果我在该代码中搞砸了,非常抱歉。

【讨论】:

以上是关于将单元添加到项目正在从项目源中删除编译器指令的主要内容,如果未能解决你的问题,请参考以下文章

如何将未编译的 .mlmodel 添加到 Xcode UnitTests 包

自动删除 Delphi IFDEf 编译器指令

短字符串的 Delphi 编译器指令不起作用?

共享项目 - 未编译

Xcode 中编译源代码的目的是啥?

如何从 CMake 或 make 输出编译依赖项?