Delphi的編譯指令
阿新 • • 發佈:2019-02-14
一個程式從無到有的過程是這樣的: 編輯程式碼 -> 預處理 -> 編譯(成dcu等) -> 連結(為exe等).
一、什麼是預處理?
譬如 VCL 中有很多程式碼是相容 Linux 的, 在 Windows 下就需要在編譯之前預處理掉那些 for Linux 的程式碼.
1、判斷作業系統: 其中的 "MSWINDOWS" 和 "LINUX" 就是 Delphi 預定義的 "條件識別符號".
2、自定義條件識別符號(DEFINE): 下面例子中自定義了條件識別符號: Nobird; 識別符號和定義它的指令都不區分大小寫, 但大家一般慣用大寫.
3、取消條件識別符號的定義(UNDEF):
4、取消定義的簡單辦法: 在 {$...} 的 $ 前面隨便加點什麼, 讓它變成 "註釋", 譬如: {.$}
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.
7、編譯指令寫在哪?: 編譯指令可以寫在內碼表的任何地方, 不過在程式碼的不同區域有時也會不同;
譬如: {$APPTYPE GUI} 和 {$APPTYPE CONSOLE} 就只能寫在工程檔案裡才有效.
{$APPTYPE GUI} 和 {$APPTYPE CONSOLE} 分別表示視窗工程和控制檯工程.
其中 {$APPTYPE GUI} 是預設的, 所以很少見到它.
它甚至可以嵌入到程式碼行當中, 譬如 ActnColorMaps 單元就有這麼一句:
8、條件識別符號的有效範圍: Delphi 預定義的條件識別符號都是全域性的, 我們用 {$DEFINE ...} 自定義的識別符號都是區域性的.
如何自定義全域性的識別符號呢?
Project -> Options... -> 選定 Delphi Compiler -> 點選 Conditional defines 右邊小按鈕 -> 新增.
不過這和系統預定義的還是有區別, 咱們自定義的只能用於當前檔案.
如何定義每個檔案都可以使用的識別符號呢?
從 Project -> Options... 定義後, 馬上選擇左下角的 Default.
這和系統預定義的還是有區別, 因為這隻能左右以後的檔案, 管不著以前存在的檔案.
如何...沒辦法了.
其他編譯指令, 譬如在 Debug 或 Release 中的設定也都是這樣; 也就是說: 每個檔案都有相對獨立的編譯設定.
看到 Project -> Options... 馬上明白了編譯指令的設定方法有兩種:
1、使用 {$...} 在程式碼中嵌入;
2、從 Project -> Options... 設定.
但在程式碼中嵌入有時是不可替代的, 譬如現在討論的條件編譯.
9、編譯指令有多少?: 現在談到的還只是條件編譯, 實際應用最多的是開關編譯; 在任一內碼表執行快捷鍵 Ctrl+O+O , 然後看看最上面...
下面列出了這些預設設定:
二、條件語句的更多用法
1. $IFDEF 等同於 $IF DEFINED(...) : 它們的結束分別是: $ENDIF、$IFEND; 例子中的 VER200 是 Delphi 2009 的標識.
2. $IFNDEF 等同於 $IF NOT DEFINED(...) : 它們的結束分別是: $ENDIF、$IFEND; 例子中的 VER150 是 Delphi 7 的標識.
3. 可以使用 or 和 and:
4. 可以使用 System 單元裡的常量: 我測試了 System 單元裡的很多常量都沒問題.
5. 使用 $IFOPT 判斷編譯開關: Delphi 挺好玩, 26個字母分別安排成不同的開關指令(用 Ctrl+o+o 檢視, 當然開關指令不止這些);
$IFOPT 可以判斷這些指令是否開啟.
這個指令不是很常用, 我看了一下 2009 的 VCL 原始碼, 總共才用了 6 次.
一、什麼是預處理?
譬如 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} |