Tạo biến

Báo cáo vấn đề Xem nguồn Hằng đêm · 7,4 của Google. 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ả các 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ỉ có sẵn cho các mục tiêu phụ thuộc vào các biến đó).

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 đã biết với phương thức tiêu thụ target, Bazel gặp lỗi.

"Nhãn hiệu" các biến có tên không phải là ký hiệu 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"

Để viết $ 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 viết $$.

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

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

Để xem danh sách các biến này và giá trị của các biến đó cho một nhóm 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ề biến được xác định trước.

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

Biến đường dẫn

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

    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 thời gian dựa trên kiến trúc máy chủ lưu trữ để hỗ trợ biên dịch chéo.

    Nếu bạn muốn chạy một công cụ từ bên trong genrule, thì cách nên dùng để 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ã được tạo cho cấu trúc mục tiêu.

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

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

Các biến genrule được xác định trước

Sau đây là các thuộc tính đặc biệt dành cho thuộc tính cmd của genrule và thường rất quan trọng để làm cho thuộc tính đó hoạt động.

Xem ví dụ về các biến genrule đượ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 (hoặc chính xác hơn: tên đường dẫn của các tệp tương ứng với 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. Else sẽ kích hoạt lỗi bản dựng.
  • @: OUTS nếu là một tệp đơn. Nếu không, 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 thư mục tương ứng với tên của gói chứa đích dưới cây genfiles hoặc bin. Cho //my/pkg:my_genrule, bộ sưu tập 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 các thư mục con.

  • @D: Thư mục đầu ra. Nếu out có một mục nhập thao tác này sẽ mở rộng thành thư mục chứa tệp đó. Nếu có nhiều mục nhập này, thao tác này sẽ mở rộng đến thư mục gốc của gói trong phần tử Cây genfiles, ngay cả khi tất cả các tệp đầu ra đều giống nhau 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ách tương tự bất kể số lượng tệp đầu ra.

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

    Đặc biệt, hãy tránh ghi vào các thư mục chứa dữ liệu đầu vào. Các tệp này có thể nằm trên 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 đầ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 lấy các tham số 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 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ề các biến đường dẫn được xác định trước.

  • execpath: Biểu thị đường dẫn bên dưới execroot nơi Bazel chạy các thao tác xây 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 theo đườ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. Chiến lược phát hành đĩa đơn 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 công ty (mà là đường dẫn con ở dưới thư mục gốc) là testapp/empty.source. Chiến dịch này là đường dẫn mà thao tác 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. Cho các nhãn đại diện cho tệp nguồn, thì điều này sẽ tự động xảy ra. Đố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 đúng, 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. Sử dụng rlocationpath cho hỗ trợ 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ý liên quan đến 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ữ.

    Kết quả này có cùng "một đầu ra" các yêu cầu của 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 phần phụ thuộc tại thời gian chạy, trong thư mục runfile (nếu có) hoặc sử dụng tệp kê khai của runfile.

    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ữ.

    Chuyển đường dẫn này đến tệp nhị phân và phân giải thành đường dẫn hệ thống tệp bằng cách sử dụng thì thư viện runfile là phương pháp được ưu tiên để tìm các phần phụ thuộc tại thời gian chạy. So với rootpath, ứng dụng 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 thư mục runfile thì không sẵn có.

    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, rlocationpathslocation . Các hàm này hỗ trợ các nhãn tạo ra nhiều đầu ra, trong đó mỗi đầu ra được liệt kê và phân tách bằng một 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 chính tắc: foo, :foo//somepkg:foo đều ổn.

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 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++

Các nội dung sau đượ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:current_cc_toolchain"] Một số quy tắc, chẳng hạn như java_binary, ngầm ẩn đưa chuỗi công cụ C++ vào định nghĩa quy tắc của chúng. Các lớp này 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 cách "chạy trình biên dịch trên nó". Để hỗ trợ nhiều chế độ biên dịch như *SAN, ThinLTO, có/không có mô-đun và tệp nhị phân được tối ưu hoá cẩn thận cùng lúc 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 rất hữu ích để đảm bảo đặt chính xác đầu vào, đầu ra và cờ dòng lệnh trên từng hành động trong số nhiều 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. 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 genrules. Cụ thể, lệnh này chứa cờ để chọn đúng cấu trúc nếu CC hỗ trợ nhiều các kiến trúc khác nhau.
  • NM: "nm" từ crosstool.
  • OBJCOPY: Lệnh objcopy từ cùng một bộ với C/C++ trình biên dịch.
  • 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 chỉ số 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ử dụng các phương pháp tinh vi 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 chúng, trước tiên hãy liên hệ với các nhà phát triển Bazel.

  • JAVA: API "java" Command (một Java ảo máy). 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 bạn phải thay đổi trước khi gọi java, bạn cần thu thập thư mục đang làm việc 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. Nó sẽ có một "thùng" thư mục con.

Biến do Starlark xác định

Người viết quy tắc và chuỗi công cụ có thể xác định hoàn toàn tuỳ chỉnh bằng cách trả về một TemplateVariableInfo Google Cloud. Bất kỳ quy tắc nào dựa trên điều này thông qua Sau đó, thuộc tính toolchains có thể đọc giá trị của các thuộc tính đó:

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