Meson 常見問題

另請參閱 如何在 Meson 中執行 X

為什麼它叫做 Meson?

當最初選擇這個名稱時,有兩個主要的限制:給定的名稱不得存在 Debian 套件或 Sourceforge 專案。這排除了數十個潛在的專案名稱。在某個時候,考慮使用 Gluon 這個名稱。膠子是將質子和中子結合在一起的基本粒子,很像建置系統的工作是將程式碼片段和編譯器綁定成一個完整的整體。

不幸的是,這個名稱也被使用了。然後檢查了其餘的次原子粒子,發現 Meson 可以使用。

使用執行緒(例如 pthreads)的正確方法是什麼?

thread_dep = dependency('threads')

這會為您設定所有項目。來自 Autotools 或 CMake 的人員希望透過手動尋找 libpthread.so 來執行此操作。不要這樣做,它有棘手的邊角案例,尤其是在交叉編譯時。

如何在系統套件中無法使用 Meson 的主機上使用 Meson?

從 0.29.0 版開始,Meson 可以從 Python 套件索引取得,因此安裝它只是執行此命令的問題

$ pip3 install <your options here> meson

如果您無法存取 PyPI,這也不是問題。 Meson 的設計可以輕鬆地從解壓縮的原始碼 tarball 甚至 git 簽出中執行。首先,您需要下載 Meson。然後使用此命令來設定您的建置,而不是使用簡單的 meson

$ /path/to/meson.py <options>

之後,您不必再擔心呼叫 Meson。它會記住最初從哪裡呼叫的,並會適當地呼叫自身。作為使用者,您唯一需要做的就是 cd 進入您的建置目錄並呼叫 meson compile

為什麼我不能使用萬用字元指定目標檔案?

人們似乎想要這樣做,而不是明確指定檔案

executable('myprog', sources : '*.cpp') # This does NOT work!

Meson 不支援此語法,原因很簡單。這無法兼顧可靠性和速度。可靠是指如果使用者在子目錄中新增了一個新的原始碼檔案,Meson 應該偵測到這一點並自動將其作為建置的一部分。

Meson 的主要要求之一是它必須快速。這表示在一個有 10,000 個原始碼檔案的樹狀結構中進行空操作的建置所花費的時間不得超過一秒的一小部分。這只有在 Meson 知道要檢查的確切檔案清單時才有可能。如果任何目標被指定為萬用字元 glob,這就不再可能了。 Meson 將需要每次重新評估 glob 並將產生的檔案清單與先前的清單進行比較。這表示要檢查整個原始碼樹狀結構(因為 glob 模式可能是 src/\*/\*/\*/\*.cpp 或類似的模式)。這是不可能有效執行的。

Meson 的主要後端是 Ninja,它也不支援萬用字元比對,原因相同。

因此,所有原始碼檔案都必須明確指定。

但我真的很想使用萬用字元!

如果對您來說,可靠性和便利性之間的權衡是可以接受的,那麼 Meson 會為您提供執行萬用字元 globbing 所需的所有工具。您可以在組態期間執行任意命令。首先,您需要編寫一個腳本來尋找要編譯的檔案。這是一個簡單的 shell 腳本,它會將目前目錄中的所有 .c 檔案寫入,每行一個。

#!/bin/sh

for i in *.c; do
  echo $i
done

然後,您需要在您的 Meson 檔案中執行此腳本,將輸出轉換為字串陣列,並在目標中使用結果。

c = run_command('grabber.sh', check: true)
sources = c.stdout().strip().split('\n')
e = executable('prog', sources)

該腳本可以是任何可執行檔,因此可以用 shell、Python、Lua、Perl 或您想要的任何語言編寫。

如上所述,權衡之處在於,僅將新檔案新增到原始碼目錄不會自動將它們新增到建置中。要新增它們,您需要告訴 Meson 重新初始化自身。最簡單的方法是觸碰原始碼根目錄中的 meson.build 檔案。然後,Meson 將在下次執行建置命令時重新設定自身。進階使用者甚至可以編寫一個小型背景腳本,利用檔案系統事件佇列(例如 inotify)來自動執行此操作。

我應該使用 subdir 還是 subproject

答案幾乎總是 subdir。子專案的存在是為了非常特定的使用案例:將外部相依性嵌入到您的建置流程中。例如,假設我們正在編寫一個遊戲,並希望使用 SDL。讓我們進一步假設 SDL 附帶 Meson 建置定義。讓我們進一步假設我們不想使用預先建置的二進位檔,而是想自己編譯 SDL。

在這種情況下,您會使用 subproject。方法是獲取 SDL 的原始碼並將其放置在您自己的原始碼樹狀結構中。然後您會執行 sdl = subproject('sdl'),這會導致 Meson 將 SDL 作為您的建置的一部分進行建置,然後允許您與其連結或執行您可能偏好的任何其他操作。

對於其他所有使用情況,您都會使用 subdir。例如,如果您想在一個目錄中建置一個共享程式庫,並在另一個目錄中針對它連結測試,您可以執行類似這樣的操作

project('simple', 'c')
subdir('src')   # library is built here
subdir('tests') # test binaries would link against the library here

為什麼沒有 Make 後端?

因為 Make 很慢。這不是實作問題,Make 就是無法加速。如需更多資訊,我們建議您閱讀 Ninja 的作者 Evan Martin 的這篇文章。Makefile 的語法也很難編寫,這使得它們成為很大的維護負擔。

人們使用 Make 而不是 Ninja 的唯一原因是使用沒有 Ninja 移植的平台。即使在這種情況下,移植 Ninja 所需的工作量也比為 Meson 編寫 Make 後端少一個數量級。

只需使用 Ninja,您會因此感到更快樂。我保證。

為什麼 Meson 不只是 Python 模組,這樣我就可以在 Python 中編寫我的建置設定?

與此相關的一個問題是為什麼 Meson 的設定語言不是圖靈完備的?

有很多很好的理由,其中大多數都在這個網頁上總結:反對在設定檔中使用程式語言

除了這些原因之外,不公開 Python 或任何其他「真正的」程式語言使得將 Meson 的實作移植到不同的語言成為可能。如果例如 Python 被證明是效能瓶頸,這可能會變得有必要。這是一個實際問題,它已為 GNU Autotools 和 SCons 造成了複雜化。

如何執行與 Libtools export-symbol 和 export-regex 等效的操作?

使用 GCC 符號可見性或編寫連結器腳本。這帶來的好處是您的符號定義位於獨立檔案中,而不是埋在您的建置定義中。可以在這裡找到一個範例。

使用 GCC 時,除非您另行指定,否則共享程式庫上的所有符號都會自動匯出。使用 MSVC 時,預設不會匯出任何符號。如果您的共享程式庫不匯出任何符號,MSVC 會靜默地不產生匯入程式庫檔案,導致失敗。解決方案是新增 GCC wiki 中指定的符號可見性定義。

我新增了一些編譯器標誌,現在建置失敗,並出現奇怪的錯誤。發生什麼事?

您可能執行了類似於以下的操作

executable('foobar', ...
           c_args : '-some_arg -other_arg')

Meson 是明確的。在這種特殊情況下,它不會自動在空白字元處分割您的字串,而是會按原樣接受它,並額外努力將其原封不動地傳遞給編譯器,包括在 shell 呼叫中正確地引用它。這是讓例如其中有空格的檔案能夠完美運作所必需的。要傳遞多個命令列引數,您需要將它們明確放入一個類似這樣的陣列中

executable('foobar', ...
           c_args : ['-some_arg', '-other_arg'])

為什麼會忽略對預設專案選項的變更?

您可能有一個看起來像這樣的專案

project('foobar', 'cpp')

這在 GCC 編譯器上預設為 c++11。假設您想改用 c++14,因此您將定義變更為以下內容

project('foobar', 'cpp', default_options : ['cpp_std=c++14'])

但是當您重新編譯時,它仍然使用 c++11。原因在於,只有在您第一次設定建置目錄時才會查看預設選項。之後,該設定會被認為具有一個值,因此會忽略預設值。要將現有的建置目錄變更為 c++14,可以使用 meson configure 重新設定您的建置目錄,或刪除建置目錄並從頭開始重新建立。

當預設值變更時,我們不會自動變更選項值的原因在於,不可能可靠地知道該怎麼做。我們需要解決的實際問題是「如果選項的值是 foo,預設值是 bar,我們是否應該將選項值也變更為 bar」。有很多選擇

  • 如果使用者自己將值從預設值變更,那麼我們絕不能將其變更回來

  • 如果使用者沒有變更該值,但變更了預設值,那麼本節的前提似乎表明應該變更該值

  • 假設使用者將值從預設值變更為 foo,然後變更回 bar,然後將預設值變更為 bar,則要採取的正確步驟本身是模棱兩可的

為了回答後面的問題,我們不僅需要記住目前值和舊值,還需要記住使用者變更該值的所有時間,以及從哪個值變更為哪個其他值。由於人們不記得自己那麼久以前的行為,因此根據長期的歷史在各個狀態之間切換會讓人感到困惑。

因此,我們執行簡單且易於理解的操作:預設值只是預設值,一旦設定,絕不會影響選項的值。

Wrap 會在背後下載來源嗎?

不會。為了讓 Meson 在建置時從網路上下載任何內容,必須滿足兩個條件。

首先,在 subprojects 目錄中必須有一個帶有下載 URL 的 .wrap 檔案。如果不存在,Meson 將不會下載任何內容。

第二個要求是,您的 meson.build 檔案中必須有明確的子專案呼叫。subproject('foobar')dependency('foobar', fallback : ['foobar', 'foo_dep'])。如果這些宣告不在任何建置檔案中,或者它們沒有被呼叫(例如,由於 if/else),則不會下載任何內容。

如果這對您來說還不夠,從 0.40.0 版開始,Meson 有一個名為 wrap-mode 的選項,可用於使用 --wrap-mode=nodownload 完全停用 wrap 下載。您也可以使用 --wrap-mode=nofallback 完全停用相依性回退,這也表示 nodownload 選項。

另一方面,如果您希望 Meson 始終使用相依性的回退,即使存在外部相依性並且可以滿足版本要求,例如為了確保您的專案在使用回退時可以建置,您可以使用 0.46.0 版本以來的 --wrap-mode=forcefallback

為什麼 Meson 是用 Python 而不是 [程式語言 X] 實作的?

因為建置系統在某些方面與普通應用程式不同。

或許最大的限制是,由於 Meson 被用於在作業系統最底層建構軟體,它是新系統核心啟動的一部分。每當新增對新的 CPU 架構的支援時,Meson 必須在系統上執行,然後才能在本機編譯使用它的軟體。這個要求增加了兩個硬性限制。

第一個限制是 Meson 必須擁有最少的相依性,因為它們都必須在啟動期間建置才能使 Meson 運作。

第二個限制是 Meson 必須支援所有 CPU 架構,包括現有的和未來的架構。例如,許多新的程式設計語言只有基於 LLVM 的編譯器可用。與 GCC 相比,LLVM 的 CPU 支援有限,因此在這些平台上啟動 Meson 首先需要向 LLVM 新增新的處理器支援。在大多數情況下,這是不可行的。

另一個限制是我們希望盡可能多的平台上開發人員使用他們作業系統提供的預設工具來提交 Meson 開發。實際上,這意味著 Windows 開發人員應該能夠僅使用 Visual Studio 進行貢獻。

在撰寫本文時(2018 年 4 月),只有三種語言可以滿足這些要求

  • C
  • C++
  • Python

在這些之中,我們選擇了 Python,因為它最適合我們的需求。

但我真的很想要一個不使用 Python 的 Meson 版本!

生態系統多樣性是好事。我們鼓勵有興趣的使用者自行編寫這個競爭性的 Meson 實作。截至 2021 年 9 月,有 3 個專案嘗試這樣做

我有不與 Meson 協同運作的專有編譯器工具鏈 X,我該如何使其運作?

Meson 需要知道每個編譯器的幾個細節,才能使用它來編譯程式碼。這些細節包括每個選項要使用的編譯器標誌,以及如何從其輸出中偵測編譯器。此資訊不能透過組態檔輸入,而是需要更改 Meson 的原始程式碼,這些變更需要提交給 Meson 主儲存庫。理論上,您可以執行帶有自訂修補程式的您自己的分支版本,但這不是善用您的時間。請將程式碼向上游提交,以便所有人都可以使用該工具鏈。

為現有語言新增新編譯器的步驟大致如下。為了簡單起見,我們假設使用 C 編譯器。

  • mesonbuild/compilers/c.py 中建立一個具有適當名稱的新類別。查看同一語言的其他編譯器具有的方法,並複製它們所執行的操作。

  • 如果編譯器只能用於交叉編譯,請務必將其標記為這樣(請參閱現有編譯器類別的範例)。

  • 將偵測邏輯新增到 mesonbuild/environment.py,尋找名為 detect_c_compiler 的方法。

  • 執行測試套件並修復問題,直到測試通過。

  • 提交提取請求,將測試套件的結果新增到您的 MR(連結現有頁面即可)。

  • 如果編譯器是免費提供的,請考慮將其新增到 CI 系統。

為什麼使用 MSVC 建置我的專案會輸出名為 libfoo.a 的靜態程式庫?

Windows 上靜態程式庫的命名慣例通常是 foo.lib。不幸的是,匯入程式庫也稱為 foo.lib

這會在使用我們建置共用和靜態程式庫的預設程式庫類型時,造成檔案名稱衝突,也會在安裝期間造成衝突,因為所有程式庫預設都安裝到同一個目錄中。

為了解決這個問題,我們決定在使用 MSVC 建置時,預設建立格式為 libfoo.a 的靜態程式庫。這有以下優點

  1. 完全避免檔案名稱衝突。
  2. MSVC 靜態程式庫的格式為 ar,與 GNU 靜態程式庫格式相同,因此使用此副檔名在語義上是正確的。
  3. 現在,所有平台和所有工具鏈的靜態程式庫檔案名稱格式都相同。
  4. 當將程式庫指定為 -lfoo 時,Clang 和 GNU 編譯器都可以搜尋 libfoo.a。這不適用於靜態程式庫的其他命名方案,例如 libfoo.lib
  5. 由於 -lfoo 可以直接使用,pkgconfig 檔案對於在 Windows 上使用 MSVC、GCC 和 Clang 建置的專案都可以正常運作。
  6. MSVC 沒有搜尋程式庫檔案名稱的引數,而且 它不在意副檔名是什麼,因此指定 libfoo.a 而不是 foo.lib 不會改變工作流程,而且它更不模糊,因此是一種改進。
  7. 只要使用相同的 CRT(例如,使用 MSYS2 的 UCRT),使用 MinGW 編譯器建置的專案就完全與 MSVC 相容。這些專案也將其靜態程式庫命名為 libfoo.a

如果由於某些原因,您真的需要您的專案在使用 MSVC 建置時輸出格式為 foo.lib 的靜態程式庫,您可以將 name_prefix: kwarg 設定為 '',並將 name_suffix: kwarg 設定為 'lib'。要取得每個的預設行為,您可以不指定 kwarg,或將 [](空陣列)傳遞給它。

我需要像在 Autotools 中那樣,將我的標頭新增到來源清單中嗎?

Autotools 要求您將私有和公開標頭新增到來源清單,以便它知道要在 make dist 產生的 tarball 中包含哪些檔案。Meson 的 dist 命令只會收集您提交到 git/hg 儲存庫的所有內容,並將其新增到 tarball 中,因此將標頭新增到來源清單中是沒有意義的。

Meson 使用 Ninja,後者使用編譯器相依性資訊來自動判斷 C 來源和標頭之間的相依性,因此當標頭變更時,它會正確地重建內容。

唯一的例外是產生的標頭,您必須正確宣告相依性

如果由於任何原因,您確實將非產生的標頭新增到目標的來源清單中,Meson 將直接忽略它們。

我該如何告訴 Meson 我的來源使用產生的標頭?

假設您使用 custom_target() 來產生標頭,然後在您的 C 程式碼中 #include 它們。以下是如何確保 Meson 在嘗試編譯建置目標中的任何來源之前產生標頭

libfoo_gen_headers = custom_target('gen-headers', ..., output: 'foo-gen.h')
libfoo_sources = files('foo-utils.c', 'foo-lib.c')
# Add generated headers to the list of sources for the build target
libfoo = library('foo', sources: [libfoo_sources + libfoo_gen_headers])

現在假設您有一個連結到 libfoo 的新目標

libbar_sources = files('bar-lib.c')
libbar = library('bar', sources: libbar_sources, link_with: libfoo)

這會在兩個目標之間新增連結時相依性,但請注意,目標的來源沒有編譯時相依性,並且可以以任何順序建置;這可以提高平行性並加快建置速度。

如果 libbar 中的來源也使用 foo-gen.h,那就是編譯時相依性,您也必須將 libfoo_gen_headers 新增到 libbarsources:

libbar_sources = files('bar-lib.c')
libbar = library('bar', sources: libbar_sources + libfoo_gen_headers, link_with: libfoo)

或者,如果您有多個具有來源的程式庫,這些來源連結到一個程式庫並也使用其產生的標頭,則此程式碼等效於上述程式碼

# Add generated headers to the list of sources for the build target
libfoo = library('foo', sources: libfoo_sources + libfoo_gen_headers)

# Declare a dependency that will add the generated headers to sources
libfoo_dep = declare_dependency(link_with: libfoo, sources: libfoo_gen_headers)

...

libbar = library('bar', sources: libbar_sources, dependencies: libfoo_dep)

注意:在宣告相依性時,您應該只將標頭新增到 sources:。如果您的自訂目標同時輸出來源和標頭,您可以使用下標表示法來僅取得標頭。

libfoo_gen_sources = custom_target('gen-headers', ..., output: ['foo-gen.h', 'foo-gen.c'])
libfoo_gen_headers = libfoo_gen_sources[0]

# Add static and generated sources to the target
libfoo = library('foo', sources: libfoo_sources + libfoo_gen_sources)

# Declare a dependency that will add the generated *headers* to sources
libfoo_dep = declare_dependency(link_with: libfoo, sources: libfoo_gen_headers)
...
libbar = library('bar', sources: libbar_sources, dependencies: libfoo_dep)

產生同時輸出來源和標頭的一個好例子是 gnome.mkenums()

我該如何在我的 C++ 專案中停用例外和 RTTI?

使用 cpp_ehcpp_rtti 選項。典型的調用看起來像這樣

meson -Dcpp_eh=none -Dcpp_rtti=false <other options>

RTTI 選項僅從 Meson 0.53.0 版本開始提供。

我應該在我的建置檔案中檢查 buildtype 或個別選項(例如 debug)嗎?

這很大程度上取決於您實際需要發生的情況。buildtype 選項旨在描述目前建置的意圖。也就是說,它的用途是什麼。個別選項用於判斷確切的狀態是什麼。透過幾個範例,這會變得更清楚。

假設您有一個來源檔案,已知在使用 -O3 時會誤編譯,並且需要解決方案。那麼您會寫出如下內容

if get_option('optimization') == '3'
    add_project_arguments('-DOPTIMIZATION_WORKAROUND', ...)
endif

另一方面,如果您的專案有您希望在日常開發工作期間(使用 debug 建置類型)啟用的額外記錄和健全性檢查,您將改為執行此操作

if get_option('buildtype') == 'debug'
    add_project_arguments('-DENABLE_EXTRA_CHECKS', ...)
endif

這樣一來,額外的選項會在開發期間自動使用,但不會編譯到發行版本中。請注意,(自 Meson 0.57.0 開始)如果您願意,可以在除錯建置中將最佳化設定為 2。如果您嘗試根據最佳化層級設定此標誌,則在這種情況下會失敗。

我該如何在宣告程式庫之前使用它?

這是有效的(而且很棒)的程式碼

libA = library('libA', 'fileA.cpp', link_with : [])
libB = library('libB', 'fileB.cpp', link_with : [libA])

但是目前沒有辦法讓類似這樣的程式碼運作

libB = library('libB', 'fileB.cpp', link_with : [libA])
libA = library('libA', 'fileA.cpp', link_with : [])

這表示您必須按照相依性流程的順序撰寫 library(...) 呼叫。雖然存在使任意順序成為可能性的想法,但它們被拒絕了,因為重新排序 library(...) 呼叫被認為是「正確」的方式。請參閱 此處 進行討論。

為什麼 Meson 沒有使用者定義的函式/巨集?

對此的簡單答案是,Meson 的設計重點在於解決特定問題,而不是提供通用語言來在建置檔案中編寫複雜的程式碼解決方案。建置系統應該容易編寫且容易理解,函式會混淆這種簡單性。

詳細的答案有兩個

首先,Meson 的目標是提供一組豐富的工具,這些工具可以簡單地解決特定的問題。這類似於 Python 的「包含電池」心態。透過提供工具,以盡可能簡單的方式解決 Meson 的常見問題,我們正在為所有人解決該問題,而不是強迫每個人一遍又一遍地為自己解決該問題,而且往往很糟糕。其中一個例子是 Meson 在各種組態工具可執行檔(sdl-config、llvm-config 等)周圍的相依性包裝器。在其他建置系統中,該相依性的每個使用者都會編寫一個包裝器並處理邊緣案例(或不處理,通常情況下是這樣),在 Meson 中,我們會在內部處理它們,每個人都會獲得修復,並且會為每個人解決邊緣案例。提供使用者定義的函式或巨集直接違反了這個設計目標。

其次,函式和巨集使建置系統更難以理解。當您遇到某些函式呼叫時,您可以參考參考手冊來查看該函式及其簽名。您不需要花費令人沮喪的時間來嘗試解讀一些 m4 位元或追蹤冗長的包含路徑,以找出 function1(呼叫 function2,後者呼叫 function3,以此類推),您就知道建置系統正在做什麼。除非您正在積極開發 Meson 本身,否則它只是一個協調建置您真正關心的東西的工具。我們希望您盡可能少花時間擔心建置系統,以便您可以花更多時間在您的程式碼上。

許多時候,使用者定義的函式是因為缺乏迴圈,或者因為在語言中使用迴圈很繁瑣。Meson 本身具有陣列/清單和雜湊/字典。比較以下虛擬程式碼

func(name, sources, extra_args)
  executable(
    name,
    sources,
    c_args : extra_args
  )
endfunc

func(exe1, ['1.c', 'common.c'], [])
func(exe2, ['2.c', 'common.c'], [])
func(exe2_a, ['2.c', 'common.c'], ['-arg'])
foreach e : [['1', '1.c', []],
             ['2', '2.c', []],
             ['2', '2.c', ['-arg']]]
  executable(
    'exe' + e[0],
    e[1],
    c_args : e[2],
  )
endforeach

與函式版本相比,迴圈程式碼更少,而且更容易理解,尤其是當函式存在於單獨的檔案中時,這在其他流行的建置系統中很常見。

建置系統 DSL 作為通用程式設計語言的設計也往往很糟糕,Meson 嘗試讓使用外部指令碼或程式來處理複雜問題變得容易。雖然不能總是將建置邏輯轉換為指令碼語言(或編譯的語言),但是當可以完成時,這通常是更好的解決方案。外部語言往往是經過深思熟慮和測試的,通常不會倒退,而且使用者更有可能擁有關於它們的領域知識。它們也往往具有更好的工具(例如自動完成、程式碼檢查、測試解決方案),這使得它們隨著時間推移維護負擔更低。

給定如下程式碼

add_project_link_arguments(['-Wl,-foo'], language : ['c'])
executable(
  'main',
  'main.c',
  'helper.cpp',
)

您可能會驚訝地發現,-Wl,-foo不會應用於 main 執行檔的連結。在 Meson 中,這是預期的行為,因為 Meson 會嘗試自動判斷要使用的正確連結器。這樣可以避免像在 autotools 中,必須向某些編譯目標添加虛擬的 C++ 原始碼才能獲得正確的連結的情況。因此,在上述情況中,使用的是 C++ 連結器,而不是 C 連結器,因為 helper.cpp 很可能無法使用 C 連結器進行連結。

通常,解決這個問題的最佳方法是將 cpp 語言添加到 add_project_link_arguments 呼叫中。

add_project_link_arguments(['-Wl,-foo'], language : ['c', 'cpp'])
executable(
  'main',
  'main.c',
  'helper.cpp',
)

要強制使用 C 連結器,可以使用 link_language 關鍵字參數。請注意,如果存在 C 連結器無法解析的符號,這可能會導致編譯失敗。

add_project_link_arguments(['-Wl,-foo'], language : ['c'])
executable(
  'main',
  'main.c',
  'helper.cpp',
  link_language : 'c',
)

如何在我的版本控制系統中忽略建置目錄?

假設您使用 git 或 mercurial,您不需要這樣做! Meson >= 0.57.0 會在每個建置目錄內為您建立 .gitignore.hgignore 檔案。它會使用 glob 忽略 "*",因為所有產生的檔案都不應該被簽入 git。

使用舊版本 Meson 的使用者可能需要自行設定忽略檔案。

如何向目標添加預處理器定義?

只需將 -DFOO 添加到 c_argscpp_args。這適用於所有已知的編譯器。

mylib = library('mylib', 'mysource.c', c_args: ['-DFOO'])

即使 MSVC 文件使用 /D 來表示預處理器定義,其命令列語法 接受 - 而不是 /。在 Meson 中,沒有必要對預處理器定義進行特殊處理 (GH-6269)。

搜尋結果是