一、什么是预处理?
譬如 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} | 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-} 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的编译指令