編譯器屬性

並非所有編譯器和平台都相同。因此,Meson 提供了在設定時偵測系統屬性的工具。要取得大多數此資訊,您首先需要從主要的 meson 變數中提取編譯器物件

compiler = meson.get_compiler('c')

這裡我們提取 C 編譯器。我們也可以給定參數 cpp 來取得 C++ 編譯器,objc 來取得 Objective C 編譯器等等。此呼叫對專案宣告中指定的所有語言都有效。嘗試取得其他編譯器將導致無法恢復的錯誤。

系統資訊

這有點複雜,在交叉編譯頁面上有更詳細的說明。但是,如果您只想知道您的程式碼將在哪個作業系統上執行,請發出此命令

host_machine.system()

編譯器 ID

編譯器物件方法 compiler.get_id() 會傳回一個小寫字串,描述編譯器的「系列」。自 0.53.0 版起,compiler.get_linker_id() 會傳回一個小寫字串,其中包含連結器的名稱。由於編譯器通常可以根據作業系統從多個連結器中選擇,因此 get_linker_id 可用於處理或減輕特定連結器的影響。

編譯器物件還有一個方法 compiler.get_argument_syntax(),它會傳回一個小寫字串 gccmsvc 或另一個未定義的字串值;識別編譯器參數是否使用與 gccmsvc 相同的語法,或者其參數與兩者都不相同。這應該僅用於選擇參數的語法,例如使用 compiler.has_argument() 進行測試的參數。

有關支援的編譯器 ID 及其參數類型的列表,請參閱參考表格

程式碼是否可以編譯?

有時測試系統的唯一方法是嘗試編譯一些範例程式碼並查看它是否有效。例如,這可以測試「C++17」編譯器是否實際支援特定的 C++17 功能,而無需求助於維護一個功能列表,該列表會與編譯器供應商、編譯器版本和作業系統進行比較。測試程式碼片段是否執行是一個分為兩個階段的操作。首先,我們使用多行字串運算子定義一些程式碼

code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

然後我們可以執行測試。

result = compiler.compiles(code, name : 'basic check')

變數 *result* 現在將包含 truefalse,具體取決於編譯是否成功。關鍵字參數 name 是可選的。如果指定了,Meson 會將檢查結果寫入其日誌。

有時有必要檢查某個程式碼片段是否不僅可以編譯,而且還可以成功連結,例如,檢查符號是否實際存在於函式庫中。這可以使用 compiler.links() 方法來完成,如下所示

code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''

然後我們可以執行測試。

result = compiler.links(code, args : '-lfoo', name : 'link check')

變數 *result* 現在將包含 truefalse,具體取決於編譯和連結是否成功。關鍵字參數 name 是可選的。如果指定了,Meson 會將檢查結果寫入其日誌。

編譯並執行測試應用程式

以下是如何編譯和執行一個小型測試應用程式。測試程式碼片段是否執行而不是僅僅連結對於某些相依性(例如 MPI)尤其重要。

code = '''#include<stdio.h>
int main(int argc, char **argv) {
  printf("%s\n", "stdout");
  fprintf(stderr, "%s\n", "stderr");
  return 0;
}
'''
result = compiler.run(code, name : 'basic check')

result 變數封裝了測試的狀態,可以使用以下方法提取。name 關鍵字參數的作用與 compiles 相同。

方法 傳回值
compiled 如果編譯成功,則為 True。如果為 false,則所有其他方法都傳回未定義的值。
returncode 應用程式的傳回碼,以整數形式表示
stdout 程式的標準輸出,以文字形式表示。
stderr 程式的標準錯誤,以文字形式表示。

以下是一個使用範例

if result.stdout().strip() == 'some_value'
  # do something
endif

標頭是否存在?

不同平台提供的標頭檔差異很大。Meson 具有偵測系統上是否提供給定標頭檔的功能。透過嘗試編譯一個簡單的測試程式(其中包含指定的標頭)來完成測試。以下程式碼片段描述了如何使用此功能。

if compiler.has_header('sys/fstat.h')
  # header exists, do something
endif

運算式大小

通常,您需要確定特定元素的大小(例如 intwchar_tchar*)。使用上面提到的 compiler 變數,可以這樣完成檢查。

wcharsize = compiler.sizeof('wchar_t', prefix : '#include<wchar.h>')

這會將 wchar_t 的大小(由 sizeof 回報)放入變數 wcharsize 中。關鍵字參數 prefix 是可選的。如果指定,其內容會放在原始檔的頂部。此參數通常用於在設定檔中設定 #include 指示。

在較舊的版本(<= 0.30)中,如果無法確定大小,Meson 會出錯。自 0.31 版起,如果無法確定大小,它會傳回 -1。

函式是否存在?

僅僅有一個標頭並不能說明其內容。有時,您需要明確檢查是否存在某些函式。以下是我們如何檢查函式 open_memstream 是否存在於標頭 stdio.h

if compiler.has_function('open_memstream', prefix : '#include <stdio.h>')
  # function exists, do whatever is required.
endif

請注意,在 macOS 上,程式可以編譯為以比編譯程式的 macOS 版本更舊的 macOS 版本為目標。不能假設編譯時所用的作業系統版本與二進位檔將執行的作業系統版本相符。

因此,當使用 compiler.has_function() 偵測函式可用性時,在 prefix 參數中指定正確的標頭非常重要。

在上面的範例中,偵測到函式 open_memstream,該函式是在 macOS 10.13 中引入的。當使用者在 macOS 10.13 上建置,但以 macOS 10.11 為目標 (-mmacosx-version-min=10.11) 時,這會正確地將該函式報告為遺失。但是,如果沒有標頭,它將缺少必要的可用性資訊,並錯誤地將該函式報告為可用。

結構是否包含成員?

某些平台具有不同的標準結構。以下是如何檢查標頭 myheader.h 中名為 mystruct 的結構是否包含名為 some_member 的成員。

if compiler.has_member('struct mystruct', 'some_member', prefix : '#include<myheader.h>')
  # member exists, do whatever is required
endif

類型對齊

大多數平台都無法在任何位址存取某些資料類型。例如,char 通常可以在任何位址,但 32 位元整數只能在可被四整除的位置。確定資料類型的對齊方式很簡單。

int_alignment = compiler.alignment('int') # Will most likely contain the value 4.

具有參數

此方法測試編譯器是否支援給定的命令列參數。這是透過使用給定參數編譯一個小檔案來實現的。

has_special_flags = compiler.has_argument('-Wspecialthing')

注意:某些編譯器會靜默地吞下它們不理解的命令列參數。因此,此測試無法做到 100% 可靠。

搜尋結果為