花褪残红青杏小。燕子飞时,绿水人家绕。

Delphi的编译指令

菜鸟编程 十五楼的鸟儿 29458浏览 0评论
一个程序从无到有的过程是这样的: 编辑代码 -> 预处理 -> 编译(成dcu等) -> 链接(为exe等).

一、什么是预处理?
譬如 VCL 中有很多代码是兼容 Linux 的, 在 WINDOWS 下就需要在编译之前预处理掉那些 for Linux 的代码.
1、判断操作系统: 其中的 "MSWINDOWS" 和 "LINUX" 就是 Delphi 预定义的 "条件标识符".
[code=delphi]
begin
{$IFDEF MSWINDOWS}
ShowMessage('Windows');
{$ENDIF}

{$IFDEF LINUX}
ShowMessage('Linux');
{$ENDIF}
end;[/code]


2、自定义条件标识符(DEFINE): 下面例子中自定义了条件标识符: Nobird; 标识符和定义它的指令都不区分大小写, 但大家一般惯用大写.
[code=delphi]
begin
{$DEFINE Nobird}
{$IFDEF Nobird}
ShowMessage('标识符 Nobird 已定义');
{$ELSE}
ShowMessage('标识符 Nobird 未定义');
{$ENDIF}
end;
[/code]

3、取消条件标识符的定义(UNDEF):
[code=delphi]
begin
{$DEFINE Nobird}
{$IFDEF Nobird}
ShowMessage('确认标识符 Nobird 是否定义');
{$ENDIF}

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

4、取消定义的简单办法: 在 {$...} 的 $ 前面随便加点什么, 让它变成 "注释", 譬如: {.$}
[code=delphi]
begin
{.$DEFINE Nobird}
{$IFDEF Nobird}
ShowMessage('确认标识符 Nobird 是否定义');
{$ENDIF}

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


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.
[code=delphi]
begin
{$IFDEF DEBUG}
ShowMessage('调试模式');
{$ENDIF}

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


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

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

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

它甚至可以嵌入到代码行当中, 譬如 ActnColorMaps 单元就有这么一句:
[code=delphi]
begin
SystemParametersInfo(SPI_GETFLATMENU, 0, {$IFNDEF CLR}@{$ENDIF}FlatMenus, 0);
end;[/code]


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

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

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

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

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

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

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

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

下面列出了这些默认设置:
[code=delphi]
{$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}[/code]

二、条件语句的更多用法

1. $IFDEF 等同于 $IF DEFINED(...) : 它们的结束分别是: $ENDIF、$IFEND; 例子中的 VER200 是 Delphi 2009 的标识.
[code=delphi]
begin
{$IFDEF VER200}
ShowMessage('这是 Delphi 2009');
{$ENDIF}

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


2. $IFNDEF 等同于 $IF NOT DEFINED(...) : 它们的结束分别是: $ENDIF、$IFEND; 例子中的 VER150 是 Delphi 7 的标识.
[code=delphi]
begin
{$IFNDEF VER150}
ShowMessage('这不是 Delphi 7');

{$ENDIF}

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

3. 可以使用 or 和 and:
[code=delphi]
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;[/code]


4. 可以使用 System 单元里的常量: 我测试了 System 单元里的很多常量都没问题.
[code=delphi]
begin
ShowMessage(FloatToStr(CompilerVersion)); {在 Delphi 2009 中, CompilerVersion = 20.0}

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

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

{$B+}
{$IFOPT B+}
ShowMessage('Ok!');
{$ENDIF}
end;[/code]




















指令及默认值可选值范围注释举例
{$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}
GlobalLinux 
{$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-}
r/>
{$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}

转载请注明:鸟儿博客 » Delphi的编译指令

游客
发表我的评论 换个身份
取消评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址