Tạo biến

Báo cáo vấn đề Xem nguồn

Biến "Tạo" là một lớp đặc biệt gồm 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à "Chủ đề thay thế "Tạo biến".

Ví dụ: bạn có thể sử dụng các tuỳ chọn 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 được xác định trước (có sẵn cho mọi mục tiêu) và biến tuỳ chỉnh (được xác định trong các mục tiêu phần phụ thuộc và chỉ dành cho những mục tiêu phụ thuộc vào chúng).

Thuật ngữ "Make" xuất hiện mang tính lịch sử: ban đầu, cú pháp và ngữ nghĩa của các biến này dự kiến khớp với GNU Make.

Sử dụng

Các thuộc tính được đánh dấu là "Có chủ đề thay thế "Tạo biến" có thể tham chiếu đến biến "Tạo" FOO như sau:

my_attr = "prefix $(FOO) suffix"

Nói cách khác, bất kỳ chuỗi con nào khớp với $(FOO) sẽ được mở rộng thành giá trị của FOO. Nếu giá trị đó là "bar", 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 đã biết với mục tiêu đang sử dụng, thì Bazel sẽ gặp lỗi.

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

my_attr = "prefix $@ suffix"

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

Biến được xác định trước

Biến "Tạo" đã xác định trước có thể được tham chiếu bằng bất kỳ thuộc tính nào được đánh dấu là "Có chủ đề thay thế "Tạo biến" trên bất kỳ mục tiêu nào.

Để xem danh sách các biến này và giá trị của chúng cho một tập hợp các tuỳ chọn bản dựng nhất định, hãy chạy

bazel info --show_make_env [build options]

và xem các dòng đầu ra trên cùng có chứa chữ cái viết hoa.

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

Biến tuỳ chọn trong chuỗi công cụ

Biến đường dẫn

  • BINDIR: Cơ sở của cây nhị phân đã tạo cho cấu trúc mục tiêu.

    Xin lưu ý rằng bạn có thể sử dụng một cây khác cho các chương trình chạy trong quá trình tạo bản dựng trên kiến trúc máy chủ lưu trữ để hỗ trợ biên dịch chéo.

    Nếu muốn chạy một công cụ từ trong genrule, bạn nên lấy đường dẫn của công cụ đó là $(execpath toolname), trong đó toolname phải được liệt kê trong thuộc tính tools của genrule.

  • GENDIR: Cơ sở của cây mã đã tạo cho cấu trúc mục tiêu.

Biến cấu trúc máy

  • TARGET_CPU: CPU của kiến trúc mục tiêu, ví dụ: k8.

Biến tạo quy tắc được xác định trước

Các thuộc tính sau dành riêng cho thuộc tính cmd của genrule và thường đóng vai trò quan trọng để giúp thuộc tính đó hoạt động.

Xem ví dụ về các biến quy tắc gen được xác định trước.

  • OUTS: Danh sách outs của genrule. Nếu chỉ có một tệp đầu ra, bạn cũng có thể sử dụng $@.
  • SRCS: Danh sách srcs của genrule (hay chính xác hơn: tên đường dẫn của các tệp tương ứng với các nhãn trong danh sách srcs). Nếu chỉ có một tệp nguồn, bạn cũng có thể sử dụng $<.
  • <: SRCS nếu là một tệp đơn. Trường hợp khác sẽ kích hoạt lỗi bản dựng.
  • @: OUTS nếu là một tệp đơn. Trường hợp khác sẽ kích hoạt lỗi bản dựng.
  • RULEDIR: Thư mục đầu ra của mục tiêu, tức là thư mục tương ứng với tên của gói chứa mục tiêu trong cây genfiles hoặc bin. Đối với //my/pkg:my_genrule, thuộc tính này luôn kết thúc bằng my/pkg, ngay cả khi dữ liệu đầu ra của //my/pkg:my_genrule nằm trong thư mục con.

  • @D: Thư mục đầu ra. Nếu phần out có một mục nhập, thì mục này sẽ mở rộng thành thư mục chứa tệp đó. Nếu tệp này có nhiều mục nhập, thì thao tác này sẽ mở rộng đến thư mục gốc của gói trong cây genfiles, ngay cả khi tất cả các tệp đầu ra đều nằm trong cùng một thư mục con!

    Lưu ý: Hãy sử dụng RULEDIR thay vì @DRULEDIR có ngữ nghĩa đơn giản hơn và hoạt động theo cùng một cách bất kể số lượng tệp đầu ra.

    Nếu quy tắc gen cần tạo các tệp trung gian tạm thời (có thể do sử dụng một số công cụ khác như trình biên dịch), thì quy tắc đó sẽ cố gắng ghi các tệp này vào @D (mặc dù /tmp cũng sẽ có thể ghi) và xoá các tệp này trước khi hoàn tất.

    Đặc biệt, tránh ghi vào các thư mục chứa dữ liệu đầu vào. Các ứng dụng này có thể nằm trên các hệ thống tệp chỉ có thể đọc. Ngay cả khi không, việc này sẽ khiến cây nguồn bị chuyển vào thùng rác.

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

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

Đối với các 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à kết quả của quy tắc, đây là đường dẫn đầu ra của tệp (xem nội dung giải thích về tệp đầu ra dưới đây).

Xem ví dụ về các 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 bản dựng trong thư mục do đường liên kết tượng trưng bazel-myproject liên kết 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 thư mục này (là đường dẫn con bên dưới thư mục gốc) là testapp/empty.source. Đây là các thao tác tạo đường dẫn có thể sử dụng để tìm tệp.

    Các tệp đầu ra được sắp xếp tương tự như vậy, nhưng cũng có tiền tố là đường dẫn con bazel-out/cpu-compilation_mode/bin (hoặc cho dữ liệu đầ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ì xuất hiện trong thuộc tính tools của show_app_output. Vì vậy, tệp đầu ra app được ghi vào bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. Do đó, đường dẫn thực thi sẽ là bazel-out/cpu-opt-exec-hash/bin/testapp/app. Tiền tố bổ sung này giúp bạn có thể tạo cùng một mục tiêu cho hai CPU khác nhau trong cùng một bản dựng mà không làm ảnh hưởng đến nhau.

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

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

    Thao tác 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, cả empty.sourceapp đều sử dụng đường dẫn thuần tuý tương đối 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 đối với kho lưu trữ.

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

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

    Thuộc tính này tương tự như rootpath ở chỗ không chứa các tiền tố cấu hình, nhưng có điểm khác ở chỗ nó 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 đối với kho lưu trữ.

    Phương pháp ưu tiên là chuyể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 thư viện runfile để tìm các phần phụ thuộc trong thời gian chạy. So với rootpath, có ưu điểm hơn là hoạt động trên mọi nền tảng và ngay cả khi không có thư mục runfile.

    Hàm 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 được mở rộng. Đây là hành vi cũ của quá trình tạo sao trước Starlark và không được đề xuất trừ phi bạn thực sự hiểu rõ tác dụng của hành vi này đối với một quy tắc cụ thể. Vui lòng xem #2475 để biết thông tin chi tiết.

execpaths, rootpaths, rlocationpathslocations lần lượt là các biến thể số nhiều của execpath, rootpath, rlocationpathslocation. Các API này hỗ trợ các nhãn tạo nhiều dữ liệu đầu ra, trong trường hợp đó, mỗi đầu ra được liệt kê và phân tách bằng một dấu cách. Các quy tắc không có đầu ra và nhãn không đúng định dạng 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 của mục tiêu tiêu thụ, tệp đầu ra hoặc deps. Nếu không, bản dựng sẽ không hoạt độ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 chính tắc: foo, :foo//somepkg:foo đều được.

Biến tuỳ chỉnh

Biến "Tạo" tuỳ chỉnh có thể được tham chiếu bởi bất kỳ thuộc tính nào được đánh dấu là "Tiêu đề thay thế "Tạo biến", 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.

Tốt nhất là tất cả biến đều nên được tuỳ chỉnh, trừ phi có lý do thực sự hợp lý để đư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 dùng taret mà có thể bạn không quan tâm.

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

Các quy tắc sau được xác định trong các 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:current_cc_toolchain"] Một số quy tắc, chẳng hạn như java_binary, ngầm đưa chuỗi công cụ C++ vào định nghĩa quy tắc. Những biến này sẽ tự động kế thừa những 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ợ các chế độ biên dịch đa dạng 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 lúc với các chương trình kiểm thử chạy nhanh trên nhiều nền tảng, các quy tắc tích hợp có độ dài lớn để đảm bảo đầu vào, đầu ra và cờ dòng lệnh chính xác được đặt trên từng thao tác có thể được tạo nội bộ.

Các biến này là một cơ chế dự phòng được 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 chúng, trước tiên hãy 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. Bạn tự chịu rủi ro nếu không làm như vậy.

  • 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 bởi genrules. Cụ thể, thuộc tính này chứa cờ để chọn đúng cấu trúc nếu CC hỗ trợ nhiều cấu trúc.
  • NM: Lệnh "nm" từ crosstool.
  • OBJCOPY: Lệnh objcopy từ cùng một bộ với trình biên dịch C/C++.
  • STRIP: Lệnh xoá từ 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 thuộc tính sau được xác định trong các quy tắc chuỗi công cụ Java và có sẵn cho mọi quy tắc đặt toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"] (hoặc "@bazel_tools//tools/jdk:current_host_java_runtime" cho chuỗi công cụ lưu trữ 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ẵn sử dụng những phương pháp phức tạp hơn nhiều để biên dịch và đóng gói Java so với các công cụ thượng nguồn có thể thể hiện, chẳng hạn như Jars giao diện, Jars giao diện tiêu đề cũng như các quá trình triển khai và hợp nhất và đóng gói Jar được tối ưu hoá cao.

Các biến này là một cơ chế dự phòng được 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 chúng, trước tiên hãy 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à chuyển sang sử dụng quy tắc java_binary nếu có thể. Có thể là một đường dẫn tương đối. Nếu phải thay đổi các thư mục trước khi gọi java, bạn cần ghi lại 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à một đường dẫn tương đối. Tệp này sẽ có một thư mục con là "bin".

Biến do Starlark xác định

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

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