Fuchsia 的建構系統使用工具來追蹤 建構動作,偵測建構動作是否正確且完整狀態 以及相關輸入內容和輸出內容
如果遇到類似下方的錯誤,請繼續閱讀本指南:
Unexpected file accesses building //some/target:label ...
(FileAccessType.READ /path/to/file/not/declared/as/input)
或者,如果您正在查看 action()
或 action_foreach()
目標如下:
action("foo") {
...
hermetic_deps = false
}
建構圖形正確性
建構定義為有向非循環圖,因此動作具有
輸入到機器學習的輸入資料
以及其輸出內容舉例來說
編譯 .cc
檔案至 .o
檔案中的動作,來源檔案會是
做為輸出內容和物件檔案編譯中使用的任何 .h
標頭
都視為相同動作的輸入來源
這個圖表呈現方式可確保建構系統能正確執行 漸進式建構。漸進式建構作業 但後來完成了一些動作輸入內容已變更 要求重新建構應用程式在漸進式建構作業中 盡可能執行最低限度的工作,只重建具有 無論是使用者修改原始碼,還是 因為其他動作的輸出內容有所變更,所以必須重新執行。
對於建構圖表中的任何動作,所有輸入和輸出內容都必須
能讓建構圖正確且指示動作
。不過,基礎建構系統 Ninja 不會對其進行驗證。
建構動作會在使用者的本機環境中執行,並具備
整個檔案系統,包括原始碼樹狀結構和 out/
中的所有檔案
目錄,因此就不會採用沙箱機制,而且可隨處存取。
如未宣告輸入內容,會導致無法重新執行動作 ( 更新文字內容。未宣告輸出內容 形成另一個動作的輸入內容,會產生 動作,在這類動作中,單一建構叫用可能會錯過時間戳記更新。 指出無法在單一叫用中進行彙整 (請參閱 Ninja no-op)。
如果您閱讀這段文字,代表的建構動作可能不是 完整狀態的一或多項輸入內容或輸出內容。
使用自訂動作擴充建構
開發人員可以使用 GN 中繼建構系統,在自家的
BUILD.gn
個檔案。方法是使用 action
和
action_foreach
。自訂動作可讓開發人員叫用
建構時的自訂工具,並將這些工具連結至依附元件圖表,例如:
此工具可在建構期間叫用,並對
漸進式建構作業
動作會使用下列參數來狀態輸入內容:
script
:要執行的工具。這通常是 Python 指令碼,但也可以是 程式語言,以在主機上執行。inputs
:做為工具資料輸入的檔案。舉例來說, 這項工具會壓縮檔案,接著要壓縮的檔案就會列為 輸入內容sources
:這與inputs
相同。只有 因為sources
通常用於 工具的script
,例如依附的 Python 或指令碼程式庫
動作會使用下列參數來狀態輸出內容:
outputs
:每個動作都必須產生至少一個輸出檔案。可執行的操作 舉例來說,如果執行個體動作可以驗證 確保資料正確性,通常會產生「載入檔案」 表示動作已執行,可以空白。
Depfiles
如果在執行動作前無法得知要輸入的部分輸入值,
然後,動作可以指定 depfile
。Depfiles 清單
在執行階段找到的一或多個輸出內容輸入動作的輸入值。
格式為一行或多行,如下所示:
[output_file1] [output_file2...]: [input_file1] [input_file2...]
depfile 中的所有路徑都必須與 root_build_dir
(設為
執行動作的工作目錄)。另請參閱:
偏好來自 rebase_path()
的相對路徑。
編譯器等工具應 (且確實) 支援 該檔案在編譯過程中使用,且格式為 depfile。
用於偵測非密封動作的檔案系統操作追蹤
Fuchsia 建構系統使用檔案系統動作追蹤工具,偵測
動作所讀取或寫入的檔案未列為輸入或輸出,
如上所示,在 BUILD.gn
檔案或 depfile 中明確指定。完成了
以取代執行動作的沙箱,以及作為各種類型的執行階段消毒器。
如果您正在閱讀本頁內容,可能是發生了以下錯誤:
這個系統。錯誤會精確地列出讀取或讀取的檔案
但是並未在 BUILD.gn
或 depfile 中指定為輸入/輸出。
您應該修正這些遺漏的內容,並嘗試重新建構,直到錯誤發生為止
因為
如要在本機建構作業中重現這個錯誤,您需要確保 動作追蹤已啟用:
fx set what --args=build_should_trace_actions=true
執行 fx args
、新增一行 build_should_trace_actions=true
、
儲存並結束。
請注意,如果動作未經過嚴格定義,且尚未修正 在嘗試重建動作時 錯誤。由於這個動作沒有完全定義,因此可能不正確 並從漸進式建構作業中收集 (也就是 嘗試解決的問題)。如要強制執行所有建構動作,請清除 您的建構作業輸出快取
fx clean
根據預設,CQ 會對所有變更執行這些完整性檢查。是
使用上述的 build_should_trace_actions=true
引數,因此
開發人員可在本機重現完全相同的追蹤版本。
抑制隱密動作檢查
為目前不合格的動作設有下列參數:
action("foo") {
...
# TODO(https://fxbug.dev/xxxxx): delete the line below and fix this
hermetic_deps = false
}
這樣會略過上述檢查作業。如果您發現有動作 則應移除抑制,嘗試重現 並修正問題。
如果不想立即修正問題,請回報錯誤,並將錯誤標題 「[Hermetic]」並在回應中納入失敗建構動作的追蹤輸出內容 例如說明如果知道存取權違規問題,請留言說明 以及訓練資料
常見問題及修正方法
缺少輸入/輸出內容
有時在建構期間就知道輸入/輸出內容,但並未指定。 或是您指定的值不正確這些常見問題通常可以輕鬆解決。 例如:
動作執行階段才會知道輸入內容
如前文所述,有時並非所有輸入內容都會在建構時間得知,因此
不能在 BUILD.gn
定義中指定。這就是 depfiles
重點
您可以在下方找到修正建構動作以產生 Depfile 的範例:
- 472565:[建構] 在 generate_fidl_json.py 中產生 depfile
- 472657:[建構] 修正 hotsort_target_internal 的功用
- 473980:[建構] 修正 fidl-c-header 的基數
- 472658:[build] 以傳統手法建構 go_library
- 472637:[建構] 修正扁平緩衝區的特徵
輸入/輸出內容中缺少動作引數
建構動作通常是使用特定檔案路徑做為引數的指令碼。
action("foo") {
script = "concatenate.py"
outputs = [ "$target_out_dir/file1_file2.txt" ]
args = [
"--concat-from",
rebase_path("data/file1.txt", root_build_dir),
rebase_path("data/file2.txt", root_build_dir),
"--output",
] + outputs
}
在上述情況中,你會看到動作追蹤程式錯誤訊息 concatenate.py
讀取自 data/file1.txt
和 data/file2.txt
。這些錯誤很容易察覺
因為您可以看到這些路徑是以引數形式傳遞至指令碼,但
並未列為輸入或輸出內容雖然就技術上來說
不會實際讀取/寫入這些路徑的指令碼
可能性不高。
修正方法如下:
action("foo") {
script = "concatenate.py"
sources = [
"data/file1.txt",
"data/file2.txt",
]
outputs = [ "$target_out_dir/file1_file2.txt" ]
args = [
"--concat-from",
] + rebase_path(sources, root_build_dir) + [
"--output",
] + outputs
}
展開檔案中的引數
在 Python 指令碼中,有一個常見模式會使用這個模式來擴充
做為引數 (也稱為「回應檔案」)。在「BUILD.gn
」中
你會看到:
action("foo") {
script = "myaction.py"
args = [ "@" + rebase_path(args_file, root_build_dir) ]
...
}
接著,您可以在相關聯的 Python 檔案 myaction.py
中找到
使用 fromfile_prefix_chars
的引數剖析器:
def main():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
args = parser.parse_args()
...
上述問題在於 Python 會在執行階段讀取 args_file
指令碼,而且必須指定為輸入內容。修正方法如下:
action("foo") {
script = "myaction.py"
inputs = [ args_file ]
args = [ "@" + rebase_path(args_file, root_build_dir) ]
...
}
如需快速從 GN 的清單填入此類檔案,可以使用
write_file()
:
action("foo") {
args_file = "${target_gen_dir}/${target_name}.args"
write_file(args_file, a_very_long_list_of_args)
args = [ "@" + rebase_path(args_file, root_build_dir) ]
...
}
請注意,GN 提供 response_file_contents
做為
以便使用便捷的替代方法 (而不是 write_file
)。但前提是:
針對源自 Ninja 的錯誤,我們目前不允許
我們建構中的 response_file_contents
。
建立及刪除暫存檔
這是在建構動作中建立暫存檔案的常見模式。 只要執行相同的動作,我們便不允許將暫存檔案列為輸出內容。 建立暫存檔案時,暫存檔案也會在返回前刪除。
暫存檔案應儲存在 target_out_dir
或 target_gen_dir
底下。
使用全域臨時儲存空間 (例如 /tmp
或 $TMPDIR
),或任何讀取和
不建議您寫入結帳或輸出目錄以外的地方,因為
因此更難排解建構失敗的問題,因為系統可能需要大量檔案
以便從檔案系統的其他位置復原
錯誤。
建立及刪除臨時目錄
有時需要在臨時目錄中建立暫存檔案。 同樣地,只要建立暫存目錄的動作 系統也會在傳回之前 以遞迴方式刪除物件
shutil.rmtree
是用於刪除臨時儲存空間的常用函式
目錄然而,由於追蹤器的限制,有時可能會
造成非預期的讀取作業另請參閱:問題 75057:妥善處理
從動作追蹤器的 goil.rmtree 中刪除目錄。
如要突破這項限制,其中一種方法是只建立暫存檔案,而非
暫存目錄暫存檔案應寫入 target_out_dir
底下
或 target_gen_dir
。
有時候無法這麼做,例如當暫存目錄是
您無法修改由外部建構工具所建立。在這種情況下
另一種方法是為臨時目錄取一個特殊名稱
__untraced_foo_tmp_outputs__
,並加入許可清單
「動作追蹤器」。這個檔案的存取權
追蹤程式會忽略這個特殊目錄。因此,
功能不應謹慎使用
舉例來說,假設 bar.py
一律會刪除 --tmp-dir
中的所有檔案
然後重新填入:
action(target_name) {
script = "bar.py"
args = [
"--tmp-dir"
rebase_path("${target_gen_dir}/${target_name}/__untraced_bar_tmp_outputs__", root_build_dir)
]
...
}
然後在動作追蹤器的 ignored_path_parts
中新增項目:
ignored_path_parts = {
# Comment with clear explanation on why this is necessary,
# preferably with a link to an associated bug for more context.
"__untraced_bar_tmp_outputs__",
...
}
CQ 回報的錯誤無法在本機上重現
首先,請確認您使用的是建構引數 build_should_trace_actions=true
,因為
相同。
如果 CQ 回報 action_tracer.py
意外讀取 Python 檔案,但您無法
在本機重現這個問題,原因可能是經過編譯的 Python 檔案
整個樹狀結構的 __pycache__
目錄 (例如 find third_party -type d -name __pycache__
)。
快速的解決方法是刪除這些目錄中的所有 *.pyc
檔案。原因如下:
偽陰性是指檔案系統一律不會開啟原始 .py
檔案,因此
不會回報為觸碰,因此不會觸發失敗的語意檢查。
Python 以外的檔案類型可能會因為類似原因而無法重現。
另請參閱:開啟專案中的裝置化動作