Biến "Make"

Biến "Make" là một lớp đặc biệt gồm các biến chuỗi có thể mở rộng, được cung cấp cho các thuộc tính được đánh dấu là "Chủ đề để "thay thế biến"".

Ví dụ: bạn có thể sử dụng các hàm này để chèn các đường dẫn chuỗi công cụ cụ thể vào các thao tác xây 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 các biến này).

Lý do cho cụm từ "Make" là do có tính lịch sử: cú pháp và ngữ nghĩa của các biến này ban đầu nhằm khớp với GNU Make.

Sử dụng

Các thuộc tính được đánh dấu là "Chủ đề thay thế để "Tạo biến" có thể tham chiếu đến biến "Make" 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", 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 là mục tiêu sử dụng, thì Bazel sẽ gặp lỗi.

Biến "Make" có tên là các 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ó 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 xác định trước

Biến "Make" xác định trước có thể được tham chiếu bởi bất kỳ thuộc tính nào được đánh dấu là "Chủ đề để "thay thế 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ó viết hoa.

Xem ví dụ về các 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 đã tạo cho cấu trúc mục tiêu.

    Xin lưu ý rằng một cây khác có thể được dùng cho các chương trình chạy trong quá trình tạo trên cấu 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ụ đó $(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.

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

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

Xem ví dụ về biến quy tắc tạo sinh đượ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 đây là một tệp. Trường hợp khác sẽ kích hoạt lỗi bản dựng.
  • @: OUTS, nếu đây là một tệp. 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, giá trị 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 giá trị out có một mục, thì tệp này sẽ mở rộng thành thư mục chứa tệp đó. Nếu có nhiều mục nhập, phương thức này sẽ mở rộng đến thư mục gốc của gói trong cây genfiles, ngay cả khi mọi 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ách giống nhau bất kể số lượng tệp đầu ra.

    Nếu quy tắc tạo (genRules) cần tạo các tệp trung gian tạm thời (có thể là do việc sử dụng một số công cụ khác như trình biên dịch), thì quy tắc tạo 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 hoàn tất.

    Đặc biệt tránh ghi vào các thư mục chứa thông tin đầ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, làm như vậy sẽ chuyển cây nguồ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 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 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 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 hành động tạo bản dựng.

    Trong ví dụ trên, Bazel chạy tất cả hành động tạo bản 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 executor (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 hành động tạo bản dựng có thể sử dụng để tìm tệp.

    Các tệp đầu ra được sắp xếp theo giai đoạn tương tự, nhưng cũng có tiền tố là đường dẫn con bazel-out/cpu-compilation_mode/bin (hoặc đối với kết quả 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. Do đó, tệp đầu ra app được ghi vào bazel-myproject/bazel-out/cpu-opt-exec-hash/bin/testapp/app. Do đó, đường dẫn executor có thể 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, chẳng hạn như hai CPU khác nhau trong cùng một bản dựng mà không bị che khuất lẫ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 đại diện cho tệp nguồn, giá trị này tự động được đặt là true. Đối với các nhãn đại diện cho quy tắc, quy tắc phải tạo đúng một kết quả đầ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 lỗi.

  • rootpath: Mô 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 runfiles 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, chứ không phải trên Windows theo mặc định. Thay vào đó, hãy sử dụng rlocationpath để được hỗ trợ nhiều nền tảng.

    Thuộc tính này tương tự như execpath nhưng sẽ loại bỏ 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 của 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à một tệp nhị phân đã tạo có thể truyền đến hàm Rlocation của thư viện runfiles để tìm một 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.

    Phần tử này tương tự như rootpath ở chỗ không chứa các tiền tố cấu hình, nhưng 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 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 của 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 runfiles để tìm các phần phụ thuộc trong thời gian chạy. So với rootpath, ưu điểm này có một ưu điểm là hoạt động được trên mọi 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 của execpath hoặc rootpath, tuỳ thuộc vào thuộc tính đang được mở rộng. Đây là hành vi tiền Starlark cũ và không nên thực hiện trừ phi bạn thực sự biết hành vi này dành cho một quy tắc cụ thể. Hãy 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 nhãn này hỗ trợ các nhãn tạo ra 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 đầu ra bằng 0 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, tệp đầu ra hoặc deps của mục tiêu tiêu thụ. Nếu không, bản dựng sẽ không hoạt động. Các mục tiêu C++ cũng có thể tham chiếu các nhãn trong data.

Các nhãn không nhất thiết phải ở dạng chính tắc: foo, :foo//somepkg:foo đều được.

Biến tùy chỉnh

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

Phương pháp hay nhất là tất cả biến đều nên tuỳ chỉnh, trừ phi có lý do thực sự hợp lý để đưa chúng 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ó khả năng tốn kém để cung cấp các biến tiêu thụ taret có thể không quan tâm.

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

Nội dung sau đây đượ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"] (hoặc "@bazel_tools//tools/cpp:current_cc_host_toolchain" cho chuỗi công cụ lưu trữ tương đương). Một số quy tắc (chẳng hạn như java_binary) ngầm đưa chuỗi công cụ C++ vào phần định nghĩa quy tắc. Chúng 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ợ 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 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ẽ hoạt động tối đa để đảm bảo các đầu vào, đầu ra và cờ dòng lệnh chính xác được thiết lập trên từng thao tác có thể được tạo nội bộ.

Các biến này là 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 nhà phát triển Bazel.

  • ABI: Phiên bản ABI C++.
  • AR: Lệnh "ar" từ công cụ chéo.
  • C_COMPILER: Giá trị nhận dạng trình biên dịch C/C++, ví dụ: llvm.
  • CC: Lệnh của 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 sẽ 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 được bằng genrules. Cụ thể, lớp này chứa các cờ để chọn cấu trúc chính xác nếu CC hỗ trợ nhiều cấu trúc.
  • NM: Lệnh "nm" qua công cụ chéo.
  • OBJCOPY: Lệnh objcopy từ cùng một bộ với trình biên dịch C/C++.
  • STRIP: Lệnh xoá trong cùng một bộ với trình biên dịch C/C++.

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

Nội dung sau đây đượ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 để biên dịch và đóng gói Java so với các phương pháp mà các công cụ tải lên luồng có thể diễn đạt, chẳng hạn như Jar giao diện, Jar giao diện tiêu đề và các phương pháp đóng gói và hợp nhất Jar được tối ưu hoá cao.

Các biến này là 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 nhà phát triển Bazel.

  • JAVA: Lệnh "java" (máy ảo Java). Hãy tránh trường hợp này và thay vào đó, hãy 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 chụp thư mục đang hoạt động trước khi thay đổi.
  • 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 "bin".

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 các biến tuỳ chỉnh hoàn toàn bằng cách trả về một nhà cung cấp TemplateVariableInfo. Bất kỳ quy tắc nào phụ thuộc vào các yếu tố này thông qua thuộc tính toolchains đều có thể đọc giá trị của chúng:

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