Tạo biến

Báo cáo vấn đề Xem nguồn Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Biến "Make" (Tạo) là một lớp đặc biệt của các biến chuỗi có thể mở rộng dành cho các thuộc tính được đánh dấu là "Có thể thay thế bằng "biến Make".

Ví dụ: bạn có thể sử dụng các tham số này để chèn các đường dẫn chuỗi công cụ cụ thể vào các thao tác bản dựng do người dùng tạo.

Bazel cung cấp cả biến đã xác định trước (có sẵn cho tất cả mục tiêu) và biến tuỳ chỉnh (được xác định trong mục tiêu phần phụ thuộc và chỉ có sẵn cho các mục tiêu phụ thuộc vào chúng).

Lý do sử dụng thuật ngữ "Tạo" là do lịch sử: cú pháp và ngữ nghĩa của các biến này ban đầu được dùng để khớp với GNU Make.

Sử dụng

Các thuộc tính được đánh dấu là "Có thể thay thế bằng "biến Make"" có thể tham chiếu đến biến "Make" FOO như sau:

my_attr = "prefix $(FOO) suffix"

Nói cách khác, mọi chuỗi con khớp với $(FOO) sẽ được mở rộng thành giá trị của FOO. Nếu giá trị đó là "bar", thì chuỗi cuối cùng sẽ trở thành:

my_attr = "prefix bar suffix"

Nếu FOO không tương ứng với một biến mà mục tiêu sử dụng biết, thì Bazel sẽ không thành công và báo lỗi.

Bạn cũng có thể tham chiếu các biến "Make" có tên là các ký hiệu không phải chữ cái, chẳng hạn như @, chỉ bằng cách sử dụng dấu đô la mà không cần dấu ngoặc đơn. Ví dụ:

my_attr = "prefix $@ suffix"

Để ghi $ dưới dạng chuỗi cố định (tức là để ngăn việc mở rộng biến), hãy ghi $$.

Predefined variables

Predefined "Make" variables can be referenced by any attribute marked as "Subject to 'Make variable' substitution" on any target.

To see the list of these variables and their values for a given set of build options, run

bazel info --show_make_env [build options]

and look at the top output lines with capital letters.

See an example of predefined variables.

Toolchain option variables

Path variables

  • BINDIR: The base of the generated binary tree for the target architecture.

    Note that a different tree may be used for programs that run during the build on the host architecture, to support cross-compiling.

    If you want to run a tool from within a genrule, the recommended way to get its path is $(execpath toolname), where toolname must be listed in the genrule's tools attribute.

  • GENDIR: The base of the generated code tree for the target architecture.

Machine architecture variables

  • TARGET_CPU: The target architecture's CPU, e.g. k8.

Predefined genrule variables

The following are specially available to genrule's cmd attribute and are generally important for making that attribute work.

See an example of predefined genrule variables.

  • OUTS: The genrule's outs list. If you have only one output file, you can also use $@.
  • SRCS: The genrule's srcs list (or more precisely: the path names of the files corresponding to labels in the srcs list). If you have only one source file, you can also use $<.
  • <: SRCS, if it is a single file. Else triggers a build error.
  • @: OUTS, if it is a single file. Else triggers a build error.
  • RULEDIR: The output directory of the target, that is, the directory corresponding to the name of the package containing the target under the genfiles or bin tree. For //my/pkg:my_genrule this always ends in my/pkg, even if //my/pkg:my_genrule's outputs are in subdirectories.

  • @D: The output directory. If outs has one entry, this expands to the directory containing that file. If it has multiple entries, this expands to the package's root directory in the genfiles tree, even if all output files are in the same subdirectory!

    Note: Use RULEDIR over @D because RULEDIR has simpler semantics and behaves the same way regardless of the number of output files.

    If the genrule needs to generate temporary intermediate files (perhaps as a result of using some other tool like a compiler), it should attempt to write them to @D (although /tmp will also be writable) and remove them before finishing.

    Especially avoid writing to directories containing inputs. They may be on read-only filesystems. Even if not, doing so would trash the source tree.

Note: If the filenames corresponding to the input labels or the output filenames contain spaces, ', or other special characters (or your genrule is part of a Starlark macro which downstream users may invoke on such files), then $(SRCS) and $(OUTS) are not suitable for interpolation into a command line, as they do not have the semantics that "${@}" would in Bash.

One workaround is to convert to a Bash array, with

mapfile SRCS <<< "$$(sed -e 's/ /\\n/g' <<'genrule_srcs_expansion'
$(SRC)
genrule_srcs_expansion
) rồi sử dụng "$$\{SRCS[@]}" trong các dòng lệnh tiếp theo thay cho $(SRCS). Một lựa chọn hiệu quả hơn là viết quy tắc Starlark.

Biến đường dẫn đầu ra/nguồn được xác định trước

Các biến được xác định trước execpath, execpaths, rootpath, rootpaths, locationlocations nhận tham số nhãn (ví dụ: $(execpath //foo:bar)) và thay thế đường dẫn tệp được biểu thị bằng nhãn đó.

Đối với tệp nguồn, đây là đường dẫn tương ứng với thư mục gốc của không gian làm việc. Đối với các tệp là đầu ra của quy tắc, đây là đường dẫn đầu ra của tệp (xem phần giải thích về tệp đầu ra bên dưới).

Xem ví dụ về biến đường dẫn được xác định trước.

  • execpath: Cho biết đường dẫn bên dưới execroot nơi Bazel chạy các thao tác bản dựng.

    Trong ví dụ trên, Bazel chạy tất cả các thao tác xây dựng trong thư mục được liên kết bằng đường liên kết tượng trưng bazel-myproject trong thư mục gốc của không gian làm việc. Tệp nguồn empty.source được liên kết tại đường dẫn bazel-myproject/testapp/empty.source. Vì vậy, đường dẫn thực thi của tệp này (là đường dẫn con bên dưới thư mục gốc) là testapp/empty.source. Đây là đường dẫn mà các thao tác bản dựng có thể sử dụng để tìm tệp.

    Các tệp đầu ra được phân chia tương tự, nhưng cũng có tiền tố là đường dẫn phụ bazel-out/cpu-compilation_mode/bin (hoặc đối với đầu ra của các công cụ: bazel-out/cpu-opt-exec-hash/bin). Trong ví dụ trên, //testapp:app là một công cụ vì nó xuất hiện trong thuộc tính tools của show_app_output. Vì vậy, tệp đầu ra app của lớp này được ghi vào bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. Do đó, đường dẫn thực thi là bazel-out/cpu-opt-exec-hash/bin/testapp/app. Tiền tố bổ sung này cho phép tạo cùng một mục tiêu cho, giả sử, hai CPU khác nhau trong cùng một bản dựng mà không làm hỏng kết quả của nhau.

    Nhãn được truyền đến biến này phải đại diện cho đúng một tệp. Đối với các nhãn đại diện cho tệp nguồn, giá trị này sẽ tự động là đúng. Đối với nhãn đại diện cho quy tắc, quy tắc phải tạo ra đúng một đầu ra. Nếu giá trị này là sai hoặc nhãn có định dạng không chính xác, thì bản dựng sẽ không thành công và báo lỗi.

  • rootpath: Cho biết đường dẫn mà tệp nhị phân đã tạo có thể sử dụng để tìm phần phụ thuộc trong thời gian chạy so với thư mục con của thư mục tệp chạy tương ứng với kho lưu trữ chính. Lưu ý: Điều này chỉ hoạt động nếu bạn bật --enable_runfiles, điều này không xảy ra trên Windows theo mặc định. Thay vào đó, hãy sử dụng rlocationpath để hỗ trợ trên nhiều nền tảng.

    Cách này tương tự như execpath nhưng xoá các tiền tố cấu hình được mô tả ở trên. Trong ví dụ ở trên, điều này có nghĩa là cả empty.sourceapp đều sử dụng đường dẫn thuần tuý tương ứng với không gian làm việc: testapp/empty.sourcetestapp/app.

    rootpath của một tệp trong kho lưu trữ bên ngoài repo sẽ bắt đầu bằng ../repo/, theo sau là đường dẫn tương ứng với kho lưu trữ.

    Phương thức này có cùng yêu cầu "chỉ một đầu ra" như execpath.

  • rlocationpath: Đường dẫn mà tệp nhị phân đã tạo có thể truyền đến hàm Rlocation của thư viện runfiles để tìm phần phụ thuộc trong thời gian chạy, trong thư mục runfiles (nếu có) hoặc sử dụng tệp kê khai runfiles.

    Tên này tương tự như rootpath ở chỗ không chứa tiền tố cấu hình, nhưng khác ở chỗ luôn bắt đầu bằng tên của kho lưu trữ. Trong ví dụ ở trên, điều này có nghĩa là empty.sourceapp sẽ dẫn đến các đường dẫn sau: myproject/testapp/empty.source myproject/testapp/app.

    rlocationpath của một tệp trong kho lưu trữ bên ngoài repo sẽ bắt đầu bằng repo/, theo sau là đường dẫn tương ứng với kho lưu trữ.

    Việc truyền đường dẫn này đến một tệp nhị phân và phân giải đường dẫn đó thành một đường dẫn hệ thống tệp bằng cách sử dụng thư viện runfiles là phương pháp ưu tiên để tìm các phần phụ thuộc trong thời gian chạy. So với rootpath, phương thức này có ưu điểm là hoạt động trên tất cả các nền tảng và ngay cả khi không có thư mục runfiles.

    Phương thức này có cùng yêu cầu "chỉ một đầu ra" như execpath.

  • location: Từ đồng nghĩa với execpath hoặc rootpath, tuỳ thuộc vào thuộc tính đang được mở rộng. Đây là hành vi cũ trước Starlark và không được khuyến khích sử dụng trừ khi bạn thực sự biết hành vi này làm gì cho một quy tắc cụ thể. Hãy xem #2475 để biết thông tin chi tiết.

execpaths, rootpaths, rlocationpathslocations là các biến thể số nhiều của execpath, rootpath, rlocationpathlocation tương ứng. Các hàm này hỗ trợ các nhãn tạo ra nhiều đầu ra, trong trường hợp đó, mỗi đầu ra được liệt kê và phân tách bằng dấu cách. Quy tắc không có đầu ra và nhãn có định dạng không chính xác sẽ gây ra lỗi bản dựng.

Tất cả nhãn được tham chiếu phải xuất hiện trong srcs, tệp đầu ra hoặc deps của mục tiêu sử dụng. Nếu không, bản dựng sẽ không thành công. Mục tiêu C++ cũng có thể tham chiếu đến các nhãn trong data.

Nhãn không nhất thiết phải ở dạng chuẩn: foo, :foo//somepkg:foo đều được.

Biến tuỳ chỉnh

Bất kỳ thuộc tính nào được đánh dấu là "Có thể thay thế bằng"biến Tạo"" đều có thể tham chiếu đến các biến "Tạo" tuỳ chỉnh, nhưng chỉ trên các mục tiêu phụ thuộc vào các mục tiêu khác xác định các biến này.

Theo phương pháp hay nhất, tất cả các biến phải là tuỳ chỉnh, trừ phi có lý do thực sự tốt để đưa các biến đó vào Bazel cốt lõi. Điều này giúp Bazel không phải tải các phần phụ thuộc có thể tốn kém để cung cấp các biến tiêu thụ mục tiêu có thể không quan tâm.

Biến chuỗi công cụ C++

Sau đây là các quy tắc được xác định trong quy tắc chuỗi công cụ C++ và có sẵn cho mọi quy tắc đặt toolchains = ["@bazel_tools//tools/cpp:toolchain_type"]. Một số quy tắc, chẳng hạn như java_binary, ngầm bao gồm chuỗi công cụ C++ trong định nghĩa quy tắc. Các lớp này sẽ tự động kế thừa các biến này.

Các quy tắc C++ tích hợp sẵn phức tạp hơn nhiều so với việc "chạy trình biên dịch trên đó". Để hỗ trợ nhiều chế độ biên dịch như *SAN, ThinLTO, có/không có mô-đun và các tệp nhị phân được tối ưu hoá cẩn thận cùng với các bài kiểm thử chạy nhanh trên nhiều nền tảng, các quy tắc tích hợp sẵn sẽ nỗ lực hết sức để đảm bảo các đầu vào, đầu ra và cờ dòng lệnh được đặt chính xác trên mỗi hành động có thể được tạo nội bộ.

Các biến này là cơ chế dự phòng để các chuyên gia ngôn ngữ sử dụng trong một số ít trường hợp. Nếu bạn muốn sử dụng các tính năng này, trước tiên, vui lòng liên hệ với các nhà phát triển Bazel.

  • ABI: Phiên bản ABI C++.
  • AR: Lệnh "ar" từ crosstool.
  • C_COMPILER: Giá trị nhận dạng trình biên dịch C/C++, ví dụ: llvm.
  • CC: Lệnh trình biên dịch C và C++.

    Bạn nên luôn sử dụng CC_FLAGS kết hợp với CC. Nếu không làm như vậy, bạn phải tự chịu rủi ro.

  • CC_FLAGS: Một tập hợp cờ tối thiểu để trình biên dịch C/C++ có thể sử dụng genrules. Cụ thể, tệp này chứa các cờ để chọn đúng cấu trúc nếu CC hỗ trợ nhiều cấu trúc.
  • DUMPBIN: Trình kết xuất tệp nhị phân COFF của Microsoft (dumpbin.exe) từ Microsoft Visual Studio.
  • NM: Lệnh "nm" từ crosstool.
  • OBJCOPY: Lệnh objcopy trong cùng một bộ với trình biên dịch C/C++.
  • STRIP: Lệnh strip (loại bỏ) trong cùng một bộ với trình biên dịch C/C++.

Biến chuỗi công cụ Java

Các quy tắc sau được xác định trong quy tắc chuỗi công cụ Java và có sẵn cho mọi quy tắc đặt toolchains = ["@rules_java//toolchains:current_java_runtime"] (hoặc "@rules_java//toolchains:current_host_java_runtime" cho chuỗi công cụ máy chủ tương đương).

Bạn không nên sử dụng trực tiếp hầu hết các công cụ trong JDK. Các quy tắc Java tích hợp sử dụng các phương pháp phức tạp hơn nhiều so với việc biên dịch và đóng gói Java mà các công cụ thượng nguồn có thể thể hiện, chẳng hạn như các tệp Jar giao diện, tệp Jar giao diện tiêu đề và các phương thức triển khai đóng gói và hợp nhất tệp Jar được tối ưu hoá cao.

Các biến này là cơ chế dự phòng để các chuyên gia ngôn ngữ sử dụng trong một số ít trường hợp. Nếu bạn muốn sử dụng các tính năng này, trước tiên, vui lòng liên hệ với các nhà phát triển Bazel.

  • JAVA: Lệnh "java" (máy ảo Java). Hãy tránh điều này và sử dụng quy tắc java_binary nếu có thể. Có thể là đường dẫn tương đối. Nếu phải thay đổi thư mục trước khi gọi java, bạn cần chụp thư mục đang hoạt động trước khi thay đổi thư mục đó.
  • JAVABASE: Thư mục cơ sở chứa các tiện ích Java. Có thể là đường dẫn tương đối. Thư mục này sẽ có một thư mục con "bin".

Biến do Starlark xác định

Trình ghi quy tắc và chuỗi công cụ có thể xác định các biến hoàn toàn tuỳ chỉnh bằng cách trả về trình cung cấp TemplateVariableInfo. Sau đó, mọi quy tắc phụ thuộc vào các giá trị này thông qua thuộc tính toolchains đều có thể đọc giá trị của các giá trị đó:

Xem ví dụ về biến do Starlark xác định.