Bazel hỗ trợ phức tạp cho việc mô hình hoá nền tảng và chuỗi công cụ. Để tích hợp tính năng này với các dự án thực, bạn cần có sự hợp tác cẩn thận giữa chủ sở hữu mã, người duy trì quy tắc và nhà phát triển Bazel cốt lõi.
Trang này tóm tắt mục đích của nền tảng và cho biết cách tạo bằng nền tảng.
tl;dr: API nền tảng và chuỗi công cụ của Bazel đã có sẵn nhưng sẽ không hoạt động ở mọi nơi cho đến khi tất cả quy tắc ngôn ngữ, select() và các tài liệu tham khảo cũ khác được cập nhật. Công việc này đang được tiến hành. Cuối cùng, tất cả các bản dựng sẽ dựa trên nền tảng.
Hãy đọc bên dưới để xem các bản dựng của bạn phù hợp với nền tảng nào.
Để biết tài liệu chính thức hơn, hãy xem:
Thông tin khái quát
Nền tảng và chuỗi công cụ được ra mắt để chuẩn hoá cách các dự án phần mềm nhắm đến các máy khác nhau và tạo bằng các công cụ ngôn ngữ phù hợp.
Đây là một bổ sung tương đối gần đây cho Bazel. Tính năng này được lấy cảm hứng từ việc quan sát thấy rằng người duy trì ngôn ngữ đã thực hiện việc này theo cách đặc biệt và không tương thích. Ví dụ: các quy tắc C++ sử dụng --cpu và --crosstool_top để đặt CPU mục tiêu và chuỗi công cụ C++ của bản dựng. Không có quy tắc nào trong số này mô hình hoá chính xác một "nền tảng". Các nỗ lực trước đây để thực hiện việc này đã tạo ra các bản dựng không chính xác và khó sử dụng.
Các cờ này cũng không kiểm soát quá trình biên dịch Java. Quá trình này đã phát triển giao diện độc lập riêng với --java_toolchain.
Bazel dành cho các dự án lớn, đa ngôn ngữ và đa nền tảng. Điều này đòi hỏi sự hỗ trợ có nguyên tắc hơn cho các khái niệm này, bao gồm cả các API rõ ràng khuyến khích khả năng tương tác giữa ngôn ngữ và dự án. Đây là mục đích của các API mới này.
Di chuyển
API nền tảng và chuỗi công cụ chỉ hoạt động khi các dự án thực sự sử dụng chúng. Điều này không đơn giản vì logic quy tắc, chuỗi công cụ, phần phụ thuộc và select() của dự án phải hỗ trợ chúng. Điều này đòi hỏi một trình tự di chuyển cẩn thận để tất cả các dự án và phần phụ thuộc của chúng hoạt động chính xác.
Ví dụ: Quy tắc C++ của Bazel hỗ trợ các nền tảng. Nhưng Quy tắc Apple thì không. Dự án C++ của bạn có thể không quan tâm đến Apple. Nhưng những người khác có thể quan tâm. Vì vậy, bạn chưa thể bật các nền tảng trên toàn cầu cho tất cả các bản dựng C++.
Phần còn lại của trang này mô tả trình tự di chuyển này cũng như cách và thời điểm các dự án của bạn có thể phù hợp.
Mục tiêu
Quá trình di chuyển nền tảng của Bazel hoàn tất khi tất cả các dự án tạo bằng biểu mẫu:
bazel build //:myproject --platforms=//:myplatformĐiều này ngụ ý:
- Các quy tắc mà dự án của bạn sử dụng có thể suy ra các chuỗi công cụ chính xác từ
//:myplatform. - Các quy tắc mà phần phụ thuộc của dự án bạn sử dụng có thể suy ra các chuỗi công cụ chính xác từ
//:myplatform. - Hoặc các dự án phụ thuộc vào dự án của bạn hỗ trợ
//:myplatformhoặc dự án của bạn hỗ trợ các API cũ (như--crosstool_top). //:myplatformtham chiếu đến [các khai báo chung][Common Platform Declaration]{: .external} củaCPU,OSvà các khái niệm chung khác hỗ trợ khả năng tương thích tự động giữa các dự án.- Tất cả các dự án có liên quan'
select()s đều hiểu các thuộc tính của máy được ngụ ý bởi//:myplatform. //:myplatformđược xác định ở một vị trí rõ ràng và có thể sử dụng lại: trong kho lưu trữ của dự án nếu nền tảng này là duy nhất cho dự án của bạn, nếu không thì ở nơi mà tất cả các dự án có thể sử dụng nền tảng này đều có thể tìm thấy.
Các API cũ sẽ bị xoá ngay khi đạt được mục tiêu này. Sau đó, đây sẽ là cách tiêu chuẩn để các dự án chọn nền tảng và chuỗi công cụ.
Tôi có nên sử dụng nền tảng không?
Nếu chỉ muốn tạo hoặc biên dịch chéo một dự án, bạn nên làm theo tài liệu chính thức của dự án.
Nếu là người duy trì dự án, ngôn ngữ hoặc chuỗi công cụ, thì cuối cùng bạn sẽ muốn hỗ trợ các API mới. Việc bạn chờ cho đến khi quá trình di chuyển toàn cầu hoàn tất hay chọn tham gia sớm phụ thuộc vào nhu cầu cụ thể về giá trị / chi phí:
Giá trị
- Bạn có thể
select()hoặc chọn chuỗi công cụ dựa trên các thuộc tính chính xác mà bạn quan tâm thay vì các cờ được mã hoá cứng như--cpu. Ví dụ: nhiều CPU có thể hỗ trợ cùng một tập lệnh. - Các bản dựng chính xác hơn. Nếu bạn
select()với--cputrong ví dụ trên, sau đó thêm một CPU mới hỗ trợ cùng một tập lệnh, thìselect()sẽ không nhận ra CPU mới. Nhưngselect()trên các nền tảng vẫn chính xác. - Trải nghiệm người dùng đơn giản hơn. Tất cả các dự án đều hiểu:
--platforms=//:myplatform. Không cần nhiều cờ dành riêng cho ngôn ngữ trên dòng lệnh. - Thiết kế ngôn ngữ đơn giản hơn. Tất cả các ngôn ngữ đều dùng chung một API để xác định chuỗi công cụ, sử dụng chuỗi công cụ và chọn chuỗi công cụ phù hợp cho một nền tảng.
- Bạn có thể bỏ qua các mục tiêu trong giai đoạn tạo và kiểm thử nếu chúng không tương thích với nền tảng mục tiêu.
Chi phí
- Các dự án phụ thuộc chưa hỗ trợ nền tảng có thể không tự động hoạt động với dự án của bạn.
- Để các dự án này hoạt động, bạn có thể cần bảo trì tạm thời bổ sung.
- Việc cùng tồn tại của các API mới và cũ đòi hỏi hướng dẫn cẩn thận hơn cho người dùng để tránh nhầm lẫn.
- Các định nghĩa chính tắc cho các thuộc tính chung như
OSvàCPUvẫn đang phát triển và có thể yêu cầu đóng góp ban đầu bổ sung. - Các định nghĩa chính tắc cho chuỗi công cụ dành riêng cho ngôn ngữ vẫn đang phát triển và có thể yêu cầu đóng góp ban đầu bổ sung.
Xem xét API
Một platform là một tập hợp các mục tiêu
constraint_value:
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
A constraint_value là một thuộc tính của máy. Các giá trị của cùng một "loại" được nhóm trong một
constraint_setting chung:
constraint_setting(name = "os")
constraint_value(
name = "linux",
constraint_setting = ":os",
)
constraint_value(
name = "mac",
constraint_setting = ":os",
)
A toolchain là một quy tắc Starlark. Các
thuộc tính của nó khai báo các công cụ của ngôn ngữ (như compiler =
"//mytoolchain:custom_gcc"). Các nhà cung cấp của nó chuyển
thông tin này đến các quy tắc cần tạo bằng các công cụ này.
Chuỗi công cụ khai báo constraint_value của các máy mà chúng có thể
nhắm đến
(target_compatible_with = ["@platforms//os:linux"]) và các máy mà công cụ của chúng có thể
chạy
(exec_compatible_with = ["@platforms//os:mac"]).
Khi tạo $ bazel build //:myproject --platforms=//:myplatform, Bazel
sẽ tự động chọn một chuỗi công cụ có thể chạy trên máy tạo và
tạo tệp nhị phân cho //:myplatform. Đây được gọi là phân giải chuỗi công cụ.
Bạn có thể đăng ký tập hợp các chuỗi công cụ có sẵn trong WORKSPACE bằng
register_toolchains hoặc trên
dòng lệnh bằng --extra_toolchains.
Hãy xem tại đây để tìm hiểu sâu hơn.
Trạng thái
Hỗ trợ nền tảng hiện tại khác nhau giữa các ngôn ngữ. Tất cả các quy tắc chính của Bazel đều đang chuyển sang các nền tảng. Nhưng quá trình này sẽ mất thời gian. Điều này là do 3 lý do chính:
Logic quy tắc phải được cập nhật để lấy thông tin công cụ từ API chuỗi công cụ mới (
ctx.toolchains) và ngừng đọc các chế độ cài đặt cũ như--cpuvà--crosstool_top. Điều này tương đối đơn giản.Người duy trì chuỗi công cụ phải xác định chuỗi công cụ và giúp người dùng truy cập được (trong kho lưu trữ GitHub và các mục
WORKSPACE). Điều này về mặt kỹ thuật là đơn giản nhưng phải được sắp xếp một cách thông minh để duy trì trải nghiệm người dùng dễ dàng.Bạn cũng cần có định nghĩa nền tảng (trừ phi bạn tạo cho cùng một máy mà Bazel chạy). Nói chung, các dự án nên xác định nền tảng riêng.
Các dự án hiện có phải được di chuyển.
select()và quá trình chuyển đổi cũng phải được di chuyển. Đây là thách thức lớn nhất. Thách thức này đặc biệt khó khăn đối với các dự án đa ngôn ngữ (có thể không thành công nếu tất cả các ngôn ngữ không thể đọc--platforms).
Nếu đang thiết kế một bộ quy tắc mới, bạn phải hỗ trợ các nền tảng ngay từ đầu. Điều này tự động giúp các quy tắc của bạn tương thích với các quy tắc và dự án khác, đồng thời tăng giá trị khi API nền tảng trở nên phổ biến hơn.
Thuộc tính nền tảng chung
Các thuộc tính nền tảng như OS và CPU thường gặp trên các dự án phải được khai báo ở một vị trí tiêu chuẩn và tập trung. Điều này khuyến khích khả năng tương thích giữa các dự án và giữa các ngôn ngữ.
Ví dụ: nếu MyApp có select() trên constraint_value
@myapp//cpus:arm và SomeCommonLib có select() trên @commonlib//constraints:arm, thì các quy tắc này sẽ kích hoạt chế độ "arm" với các tiêu chí không tương thích.
Các thuộc tính chung trên toàn cầu được khai báo trong kho lưu trữ
@platforms
(vì vậy, nhãn chính tắc cho ví dụ trên là @platforms//cpu:arm).
Các thuộc tính chung của ngôn ngữ phải được khai báo trong kho lưu trữ của các ngôn ngữ tương ứng.
Nền tảng mặc định
Nói chung, chủ sở hữu dự án nên xác định các
nền tảng rõ ràng để mô tả các
loại máy mà họ muốn tạo. Sau đó, các nền tảng này sẽ được kích hoạt bằng --platforms.
Khi --platforms không được thiết lập, Bazel sẽ mặc định là platform đại diện cho máy tạo cục bộ. Nền tảng này được tạo tự động tại @local_config_platform//:host nên bạn không cần xác định rõ ràng. Nền tảng này liên kết OS
và CPU của máy cục bộ với constraint_value được khai báo trong
@platforms.
C++
Các quy tắc C++ của Bazel sử dụng các nền tảng để chọn chuỗi công cụ khi bạn thiết lập
--incompatible_enable_cc_toolchain_resolution
(#7260).
Điều này có nghĩa là bạn có thể định cấu hình dự án C++ bằng:
bazel build //:my_cpp_project --platforms=//:myplatformthay vì:
bazel build //:my_cpp_project` --cpu=... --crosstool_top=... --compiler=...Nếu dự án của bạn là C++ thuần tuý và không phụ thuộc vào các dự án không phải C++, thì bạn có thể sử dụng
các nền tảng một cách an toàn miễn là selects và
quá trình chuyển đổi của bạn tương thích. Hãy xem
#7260 và
Định cấu hình chuỗi công cụ C++ để biết thêm hướng dẫn.
Chế độ này không được bật theo mặc định. Điều này là do các dự án Apple
vẫn định cấu hình các phần phụ thuộc C++ bằng --cpu và --crosstool_top
(ví dụ). Vì vậy, điều này phụ thuộc vào việc các quy tắc Apple di chuyển sang các nền tảng.
Java
Các quy tắc Java của Bazel sử dụng các nền tảng.
Điều này thay thế các cờ cũ --java_toolchain, --host_java_toolchain, --javabase và --host_javabase.
Để tìm hiểu cách sử dụng các cờ cấu hình, hãy xem hướng dẫn sử dụng Bazel và Java. Để biết thêm thông tin, hãy xem Tài liệu thiết kế.
Nếu bạn vẫn đang sử dụng các cờ cũ, hãy làm theo quy trình di chuyển trong Vấn đề #7849.
Android
Các quy tắc Android của Bazel sử dụng các nền tảng để chọn chuỗi công cụ khi bạn thiết lập --incompatible_enable_android_toolchain_resolution.
Chế độ này không được bật theo mặc định. Nhưng quá trình di chuyển đang diễn ra tốt đẹp.
Apple
Các quy tắc Apple của Bazel chưa hỗ trợ các nền tảng để chọn chuỗi công cụ Apple.
Các quy tắc này cũng không hỗ trợ các phần phụ thuộc C++ được bật trên nền tảng vì chúng sử dụng --crosstool_top cũ để thiết lập chuỗi công cụ C++. Cho đến khi quá trình này được di chuyển, bạn
có thể kết hợp các dự án Apple với C++ được bật trên nền tảng bằng cách liên kết nền tảng
(ví dụ).
Ngôn ngữ khác
- Các quy tắc Rust của Bazel hỗ trợ đầy đủ các nền tảng.
- Các quy tắc Go của Bazel hỗ trợ đầy đủ các nền tảng (thông tin chi tiết).
Nếu đang thiết kế các quy tắc cho một ngôn ngữ mới, hãy sử dụng các nền tảng để chọn chuỗi công cụ của ngôn ngữ đó. Hãy xem tài liệu về chuỗi công cụ để biết hướng dẫn chi tiết.
select()
Các dự án có thể select() trên
constraint_value các mục tiêu nhưng không hoàn thành
các nền tảng. Đây là ý định để select() hỗ trợ nhiều loại máy nhất có thể. Một thư viện có các nguồn dành riêng cho ARM phải hỗ trợ tất cả các máy chạy ARM trừ phi có lý do cụ thể hơn.
Để chọn một hoặc nhiều constraint_value, hãy sử dụng:
config_setting(
name = "is_arm",
constraint_values = [
"@platforms//cpu:arm",
],
)
Điều này tương đương với việc chọn theo cách truyền thống trên --cpu:
config_setting(
name = "is_arm",
values = {
"cpu": "arm",
},
)
Xem thêm chi tiết tại đây.
select trên --cpu, --crosstool_top, v.v. không hiểu --platforms. Khi
di chuyển dự án sang các nền tảng, bạn phải chuyển đổi chúng thành
constraint_values hoặc sử dụng mối liên kết nền tảng để hỗ trợ
cả hai kiểu trong cửa sổ di chuyển.
Kiểu chuyển cảnh
Quá trình chuyển đổi Starlark thay đổi
các cờ xuống các phần của biểu đồ tạo. Nếu dự án của bạn sử dụng quá trình chuyển đổi thiết lập --cpu, --crossstool_top hoặc các cờ cũ khác, thì các quy tắc đọc --platforms sẽ không thấy những thay đổi này.
Khi di chuyển dự án sang các nền tảng, bạn phải chuyển đổi các thay đổi như
return { "//command_line_option:cpu": "arm" } thành return {
"//command_line_option:platforms": "//:my_arm_platform" } hoặc sử dụng mối liên kết
nền tảng để hỗ trợ cả hai kiểu trong cửa sổ di chuyển.
Cách sử dụng nền tảng ngay hôm nay
Nếu chỉ muốn tạo hoặc biên dịch chéo một dự án, bạn nên làm theo tài liệu chính thức của dự án. Người duy trì ngôn ngữ và dự án sẽ quyết định cách và thời điểm tích hợp với các nền tảng cũng như giá trị mà các nền tảng đó mang lại.
Nếu là người duy trì dự án, ngôn ngữ hoặc chuỗi công cụ và bản dựng của bạn không sử dụng các nền tảng theo mặc định, thì bạn có 3 lựa chọn (ngoài việc chờ quá trình di chuyển toàn cầu):
Bật cờ "sử dụng nền tảng" cho các ngôn ngữ của dự án (nếu có ) và thực hiện mọi hoạt động kiểm thử cần thiết để xem các dự án mà bạn quan tâm có hoạt động hay không.
Nếu các dự án mà bạn quan tâm vẫn phụ thuộc vào các cờ cũ như
--cpuvà--crosstool_top, hãy sử dụng các cờ này cùng với--platforms:bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...Điều này có một số chi phí bảo trì (bạn phải tự đảm bảo các chế độ cài đặt khớp nhau). Nhưng điều này sẽ hoạt động khi không có quá trình chuyển đổi không tuân thủ .
Viết mối liên kết nền tảng để hỗ trợ cả hai kiểu bằng cách liên kết các chế độ cài đặt kiểu
--cpuvới các nền tảng tương ứng và ngược lại.
Mối liên kết nền tảng
Mối liên kết nền tảng là một API tạm thời cho phép logic dựa trên nền tảng và logic dựa trên nền tảng cũ cùng tồn tại trong cùng một bản dựng thông qua cửa sổ ngừng hoạt động của logic dựa trên nền tảng cũ.
Mối liên kết nền tảng là một mối liên kết của platform() với một tập hợp cờ cũ tương ứng hoặc ngược lại. Ví dụ:
platforms:
# Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
//platforms:ios
--cpu=ios_x86_64
--apple_platform_type=ios
flags:
# Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
--cpu=ios_x86_64
--apple_platform_type=ios
//platforms:ios
# Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
--cpu=darwin
--apple_platform_type=macos
//platforms:macos
Bazel sử dụng mối liên kết này để đảm bảo tất cả các chế độ cài đặt (cả dựa trên nền tảng và cũ) đều được áp dụng nhất quán trong suốt quá trình tạo, bao gồm cả quá trình chuyển đổi.
Theo mặc định, Bazel đọc các mối liên kết từ tệp platform_mappings trong thư mục gốc của không gian làm việc. Bạn cũng có thể thiết lập --platform_mappings=//:my_custom_mapping.
Hãy xem tại đây để biết thông tin chi tiết.
Câu hỏi
Để được hỗ trợ chung và có câu hỏi về tiến trình di chuyển, hãy liên hệ với bazel-discuss@googlegroups.com hoặc chủ sở hữu của các quy tắc thích hợp.
Để thảo luận về thiết kế và sự phát triển của các API nền tảng/chuỗi công cụ, hãy liên hệ với bazel-dev@googlegroups.com.