Delphi的编译指令

一个程序从无到有的过程是这样的: 编辑代码 -> 预处理 -> 编译(成dcu等) -> 链接(为exe等).

一、什么是预处理?
譬如 VCL 中有很多代码是兼容 Linux 的, 在 Windows 下就需要在编译之前预处理掉那些 for Linux 的代码.
1、判断操作系统: 其中的 "MSWINDOWS" 和 "LINUX" 就是 Delphi 预定义的 "条件标识符".

begin
  {$IFDEF MSWINDOWS}
    ShowMessage('Windows');
  {$ENDIF}

  {$IFDEF LINUX}
    ShowMessage('Linux');
  {$ENDIF}
end;

2、自定义条件标识符(DEFINE): 下面例子中自定义了条件标识符: Nobird; 标识符和定义它的指令都不区分大小写, 但大家一般惯用大写.

begin
  {$DEFINE Nobird}
  {$IFDEF Nobird}
    ShowMessage('标识符 Nobird 已定义');
  {$ELSE}
    ShowMessage('标识符 Nobird 未定义');
  {$ENDIF}
end;

3、取消条件标识符的定义(UNDEF):

begin
  {$DEFINE Nobird}
  {$IFDEF Nobird}
    ShowMessage('确认标识符 Nobird 是否定义');
  {$ENDIF}

  {$UNDEF Nobird}
  {$IFDEF Nobird}
    ShowMessage('再次确认标识符 Nobird 是否定义');
  {$ENDIF}
end;

4、取消定义的简单办法: 在 {$...} 的 $ 前面随便加点什么, 让它变成 "注释", 譬如: {.$}

begin
  {.$DEFINE Nobird}
  {$IFDEF Nobird}
    ShowMessage('确认标识符 Nobird 是否定义');
  {$ENDIF}

  {.$UNDEF Nobird}
  {$IFDEF Nobird}
    ShowMessage('再次确认标识符 Nobird 是否定义');
  {$ENDIF}
end;

5、调试编译指令时特别要注意的: Delphi 有个常识: 如果单元代码没有改变, 相应的 dcu 不会重新生成!

因此, 为了有准确的调试结果, 执行前先用 Shift+F9 强制编译当前工程, 然后再 Run;
强制编译所有相关单元也可以, 方法: Project -> Build all project.

当然修改下代码也很方便, 譬如在代码中打个空格再退回来.
6、测试预定义的 Debug 和 Release: 当我们当新建一个工程, Delphi 默认的是调试(Debug)状态, 当我们发布软件时应该切换到发布(Release)状态.
两种状态下编译指令是有区别的, 在 Release 状态下发布的 dcu 或 exe 会更小、更优化.

Debug 和 Release 的切换方法:
进入 Project Manager -> Build Configurations, 在 Debug 或 Release 上双击, 或从右键 Activate.

下面的代码可以检测到这种改变, 不过要注意上面提到的 Shift+F9 或 Project -> Build all project.

begin
  {$IFDEF DEBUG}
    ShowMessage('调试模式');
  {$ENDIF}

  {$IFDEF RELEASE}
    ShowMessage('发布模式');
  {$ENDIF}
end;

7、编译指令写在哪?: 编译指令可以写在代码页的任何地方, 不过在代码的不同区域有时也会不同;

譬如: {$APPTYPE GUI} 和 {$APPTYPE CONSOLE} 就只能写在工程文件里才有效.

{$APPTYPE GUI} 和 {$APPTYPE CONSOLE} 分别表示窗口工程和控制台工程.
其中 {$APPTYPE GUI} 是默认的, 所以很少见到它.

它甚至可以嵌入到代码行当中, 譬如 ActnColorMaps 单元就有这么一句:

begin
  SystemParametersInfo(SPI_GETFLATMENU, 0, {$IFNDEF CLR}@{$ENDIF}FlatMenus, 0);
end;

8、条件标识符的有效范围: Delphi 预定义的条件标识符都是全局的, 我们用 {$DEFINE ...} 自定义的标识符都是局部的.

如何自定义全局的标识符呢?
Project -> Options... -> 选定 Delphi Compiler -> 点击 Conditional defines 右边小按钮 -> 添加.

不过这和系统预定义的还是有区别, 咱们自定义的只能用于当前文件.

如何定义每个文件都可以使用的标识符呢?
从 Project -> Options... 定义后, 马上选择左下角的 Default.

这和系统预定义的还是有区别, 因为这只能左右以后的文件, 管不着以前存在的文件.
如何...没办法了.

其他编译指令, 譬如在 Debug 或 Release 中的设置也都是这样; 也就是说: 每个文件都有相对独立的编译设置.

看到 Project -> Options... 马上明白了编译指令的设置方法有两种:
1、使用 {$...} 在代码中嵌入;
2、从 Project -> Options... 设置.

但在代码中嵌入有时是不可替代的, 譬如现在讨论的条件编译.
9、编译指令有多少?: 现在谈到的还只是条件编译, 实际应用最多的是开关编译; 在任一代码页执行快捷键 Ctrl+O+O , 然后看看最上面...

下面列出了这些默认设置:

{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
{$MINSTACKSIZE $00004000}
{$MAXSTACKSIZE $00100000}
{$IMAGEBASE $00400000}
{$APPTYPE GUI}
{$WARN SYMBOL_DEPRECATED ON}
{$WARN SYMBOL_LIBRARY ON}
{$WARN SYMBOL_PLATFORM ON}
{$WARN SYMBOL_EXPERIMENTAL ON}
{$WARN UNIT_LIBRARY ON}
{$WARN UNIT_PLATFORM ON}
{$WARN UNIT_DEPRECATED ON}
{$WARN UNIT_EXPERIMENTAL ON}
{$WARN HRESULT_COMPAT ON}
{$WARN HIDING_MEMBER ON}
{$WARN HIDDEN_VIRTUAL ON}
{$WARN GARBAGE ON}
{$WARN BOUNDS_ERROR ON}
{$WARN ZERO_NIL_COMPAT ON}
{$WARN STRING_CONST_TRUNCED ON}
{$WARN FOR_LOOP_VAR_VARPAR ON}
{$WARN TYPED_CONST_VARPAR ON}
{$WARN ASG_TO_TYPED_CONST ON}
{$WARN CASE_LABEL_RANGE ON}
{$WARN FOR_VARIABLE ON}
{$WARN CONSTRUCTING_ABSTRACT ON}
{$WARN COMPARISON_FALSE ON}
{$WARN COMPARISON_TRUE ON}
{$WARN COMPARING_SIGNED_UNSIGNED ON}
{$WARN COMBINING_SIGNED_UNSIGNED ON}
{$WARN UNSUPPORTED_CONSTRUCT ON}
{$WARN FILE_OPEN ON}
{$WARN FILE_OPEN_UNITSRC ON}
{$WARN BAD_GLOBAL_SYMBOL ON}
{$WARN DUPLICATE_CTOR_DTOR ON}
{$WARN INVALID_DIRECTIVE ON}
{$WARN PACKAGE_NO_LINK ON}
{$WARN PACKAGED_THREADVAR ON}
{$WARN IMPLICIT_IMPORT ON}
{$WARN HPPEMIT_IGNORED ON}
{$WARN NO_RETVAL ON}
{$WARN USE_BEFORE_DEF ON}
{$WARN FOR_LOOP_VAR_UNDEF ON}
{$WARN UNIT_NAME_MISMATCH ON}
{$WARN NO_CFG_FILE_FOUND ON}
{$WARN IMPLICIT_VARIANTS ON}
{$WARN UNICODE_TO_LOCALE ON}
{$WARN LOCALE_TO_UNICODE ON}
{$WARN IMAGEBASE_MULTIPLE ON}
{$WARN SUSPICIOUS_TYPECAST ON}
{$WARN PRIVATE_PROPACCESSOR ON}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$WARN OPTION_TRUNCATED ON}
{$WARN WIDECHAR_REDUCED ON}
{$WARN DUPLICATES_IGNORED ON}
{$WARN UNIT_INIT_SEQ ON}
{$WARN LOCAL_PINVOKE ON}
{$WARN MESSAGE_DIRECTIVE ON}
{$WARN TYPEINFO_IMPLICITLY_ADDED ON}
{$WARN RLINK_WARNING ON}
{$WARN IMPLICIT_STRING_CAST ON}
{$WARN IMPLICIT_STRING_CAST_LOSS ON}
{$WARN EXPLICIT_STRING_CAST OFF}
{$WARN EXPLICIT_STRING_CAST_LOSS OFF}
{$WARN CVT_WCHAR_TO_ACHAR OFF}
{$WARN CVT_NARROWING_STRING_LOST OFF}
{$WARN CVT_ACHAR_TO_WCHAR OFF}
{$WARN CVT_WIDENING_STRING_LOST OFF}
{$WARN XML_WHITESPACE_NOT_ALLOWED ON}
{$WARN XML_UNKNOWN_ENTITY ON}
{$WARN XML_INVALID_NAME_START ON}
{$WARN XML_INVALID_NAME ON}
{$WARN XML_EXPECTED_CHARACTER ON}
{$WARN XML_CREF_NO_RESOLVE ON}
{$WARN XML_NO_PARM ON}
{$WARN XML_NO_MATCHING_PARM ON}

二、条件语句的更多用法

1. $IFDEF 等同于 $IF DEFINED(...) : 它们的结束分别是: $ENDIF、$IFEND; 例子中的 VER200 是 Delphi 2009 的标识.

begin
  {$IFDEF VER200}
    ShowMessage('这是 Delphi 2009');
  {$ENDIF}

  {$IF DEFINED(VER200)}
    ShowMessage('这是 Delphi 2009');
  {$IFEND}
end;

2. $IFNDEF 等同于 $IF NOT DEFINED(...) : 它们的结束分别是: $ENDIF、$IFEND; 例子中的 VER150 是 Delphi 7 的标识.

begin
  {$IFNDEF VER150}
    ShowMessage('这不是 Delphi 7');
  {$ENDIF}

  {$IF NOT DEFINED(VER150)}
    ShowMessage('这不是 Delphi 7');
  {$IFEND}
end;

3. 可以使用 or 和 and:

begin
  {$DEFINE AAA}
  {$DEFINE BBB}

  {$IF DEFINED(AAA) OR DEFINED(BBB)}
    ShowMessage('条件标识符 AAA 和 BBB 其中一个定义了');
  {$IFEND}

  {$IF DEFINED(AAA) AND DEFINED(BBB)}
    ShowMessage('条件标识符 AAA 和 BBB 都定义了');
  {$IFEND}
end;

4. 可以使用 System 单元里的常量: 我测试了 System 单元里的很多常量都没问题.

begin
  ShowMessage(FloatToStr(CompilerVersion)); {在 Delphi 2009 中, CompilerVersion = 20.0}

  {$IF CompilerVersion >= 17.0}
    ShowMessage('这是 Delphi 2005 或以上的版本');
  {$IFEND}
end;

5. 使用 $IFOPT 判断编译开关: Delphi 挺好玩, 26个字母分别安排成不同的开关指令(用 Ctrl+o+o 查看, 当然开关指令不止这些);
$IFOPT 可以判断这些指令是否打开.
这个指令不是很常用, 我看了一下 2009 的 VCL 源码, 总共才用了 6 次.

begin
  {$IFOPT B+}
    ShowMessage('指令 B 已打开');
  {$ELSE}
    ShowMessage('指令 B 已关闭');
  {$ENDIF}

  {$B+}
  {$IFOPT B+}
    ShowMessage('Ok!');
  {$ENDIF}
end;

指令及默认值 可选值 范围 注释 举例
{$A8}

{$ALIGN8}

{$A+},{$A-},

{$A1},{$A2},{$A4},{$A8};

{$ALIGN ON},{$ALIGN OFF},

{$ALIGN 1},{$ALIGN 2},

{$ALIGN 4},{$ALIGN 8}

Local    
{$APPTYPE GUI} {$APPTYPE GUI},

{$APPTYPE CONSOLE}

Global    
{$B-}

{$BOOLEVAL OFF}

{$B+},{$B-};

{$BOOLEVAL ON},

{$BOOLEVAL OFF}

Local    
{$C+}

{$ASSERTIONS ON}

{$C+},{$C-};

{$ASSERTIONS ON},

{$ASSERTIONS OFF}

Local    
{$D+}

{$DEBUGINFO ON}

{$D+},{$D-}

{$DEBUGINFO ON},

{$DEBUGINFO OFF}

Global    
{$DENYPACKAGEUNIT OFF} {$DENYPACKAGEUNIT ON}, Local    
{$DESCRIPTION 'text'}   Global    
{$DESIGNONLY OFF} {$DESIGNONLY ON},

{$DESIGNONLY OFF}

Local    
{$E-} {$E+},{$E-}      
{$E extension}

{$EXTENSION extension}
 

       
{$EXTERNALSYM identifier}        
{$F-}
 
{$F+},{$F-}      
{$FINITEFLOAT ON} {$FINITEFLOAT ON},

{$FINITEFLOAT OFF}

Global    
{$G+}

{$IMPORTEDDATA ON}

{$G+},{$G-};

{$IMPORTEDDATA ON},

{$IMPORTEDDATA OFF}

Local    
{$H+}

{$LONGSTRINGS ON}

{$H+},{$H-}

{$LONGSTRINGS ON},

{$LONGSTRINGS OFF}
 

Local    
{$HINTS ON} {$HINTS ON},

{$HINTS OFF}

Local    
{$HPPEMIT 'string'}        
{$I filename}

{$INCLUDE filename}

 
 
Local    
{$I+}

{$IOCHECKS ON}

{$I+},{$I-};

{$IOCHECKS ON},

{$IOCHECKS OFF}

Local    
{$IMAGEBASE $00400000} {$IMAGEBASE number} Global    
{$IMPLICITBUILD ON},{$IMPLICITBUILD OFF} {$IMPLICITBUILD ON} Global    
{$J-}

{$WRITEABLECONST OFF}
 

{$J+},{$J-}

{$WRITEABLECONST ON},

{$WRITEABLECONST OFF}

Local    
{$K-} {$K+},{$K-}      
{$L+}

{$LOCALSYMBOLS ON}

{$L+},{$L-}

{$LOCALSYMBOLS ON},

{$LOCALSYMBOLS OFF}

Global    
{$L filename}

{$LINK filename}

  Local    
$LIBPREFIX 'lib' or $SOPREFIX 'bpl' 

$LIBSUFFIX ' '

$LIBVERSION ' '

$LIBPREFIX 'string'

$LIBSUFFIX 'string'

$LIBVERSION 'string'
 

Global    
{$M-}

{$TYPEINFO OFF}

{$M+},{$M-}

{$TYPEINFO ON},

{$TYPEINFO OFF}

Local    
{$M 16384,1048576} {$M minstacksize,maxstacksize};

{$MINSTACKSIZE number}

{$MAXSTACKSIZE number}
 

     
{$M 1048576} {$M reservedbytes}

{$RESOURCERESERVE reservedbytes}

Global Linux  
{$MESSAGE HINT|WARN|ERROR|FATAL 'text string'}   Local    
{$METHODINFO OFF} {$METHODINFO ON},

{$METHODINFO OFF}

     
{$N+}
 
{$N+},{$N-}      
{$NODEFINE identifier}        
{$NOINCLUDE filename}        
{$O+}

{$OPTIMIZATION ON}
 

{$O+},{$O-};

{$OPTIMIZATION ON},

{$OPTIMIZATION OFF}

Local    
{$ObjExportAll Off} {$ObjExportAll On},

{$ObjExportAll Off}

Global    
{$P+}

{$OPENSTRINGS ON}

{$P+},{$P-}

{$OPENSTRINGS ON},

{$OPENSTRINGS OFF}

Local    
{$POINTERMATH OFF} {$POINTERMATH ON},

{$POINTERMATH OFF}
 

Local    
{$Q-}

{$OVERFLOWCHECKS OFF}

{$Q+},{$Q-}

{$OVERFLOWCHECKS ON},

{$OVERFLOWCHECKS OFF}

Local    
{$R filename}

{$RESOURCE filename}

{$R *.xxx}

{$R filename.res filename.rc}

       
{$R-}

{$RANGECHECKS OFF}

{$R+},{$R-}

{$RANGECHECKS ON},

{$RANGECHECKS OFF}

Local    
{$REALCOMPATIBILITY OFF} {$REALCOMPATIBILITY ON},

{$REALCOMPATIBILITY OFF}
 

Local    
{$RUNONLY OFF} {$RUNONLY ON},

{$RUNONLY OFF}

Local    
{$S-} {$S+},{$S-}      
{$SetPEFlags <integer expression>}

{$SetPEOptFlags <integer expression>}
 

  Local    
{$T-}

{$TYPEDADDRESS OFF}

{$T+},{$T-}

{$TYPEDADDRESS ON},

{$TYPEDADDRESS OFF}

Global    
{$U-}

{$SAFEDIVIDE OFF}

{$U+},{$U-}

{$SAFEDIVIDE ON},

{$SAFEDIVIDE OFF}

Local    
{$V+}

{$VARSTRINGCHECKS ON}
 

{$V+},{$V-}

{$VARSTRINGCHECKS ON},

{$VARSTRINGCHECKS OFF}

Local    
{$W-}

{$STACKFRAMES OFF}

{$W+},{$W-}

{$STACKFRAMES ON},

{$STACKFRAMES OFF}

Local    
{$WARN ON} {$WARN identifier ON},

{$WARN identifier OFF}

Local    
{$WARNINGS ON} {$WARNINGS ON},

{$WARNINGS OFF}

Local    
{$WEAKPACKAGEUNIT OFF} {$WEAKPACKAGEUNIT ON},

{$WEAKPACKAGEUNIT OFF}

Local    
{$X+}

{$EXTENDEDSYNTAX ON}

{$X+},{$X-};

{$EXTENDEDSYNTAX ON},

{$EXTENDEDSYNTAX OFF}

Global    
{$YD}

{$DEFINITIONINFO ON} 
 

{$Y+},{$Y-},{$YD};

{$REFERENCEINFO ON},

{$REFERENCEINFO OFF};

{DEFINITIONINFO ON},

{DEFINITIONINFO OFF}

Global    
{$Z1}

{$MINENUMSIZE 1}

{$Z1},{$Z2},{$Z4};

{$MINENUMSIZE 1},

{$MINENUMSIZE 2},

{$MINENUMSIZE 4}
 

Local    
         
$DEFINE

$UNDEF

$IFDEF

$ELSE

$ENDIF

{$IF DEFINED(...)}

{$IFEND}

{$IF NOT DEFINED(...)}

{$IFEND}

{$IF DEFINED(...) OR DEFINED(...)}

{$IFEND}

{$IF DEFINED(...) AND DEFINED(...)}

{$IFEND}

{$IF System.Const >= Number}

{$IFEND}

{$IFOPT ...}

{$ELSE}

{$ENDIF}

       
         
{$region 'text'} ... {$endregion}      
同步内容