From 6e3f48daeb96c3f582d057a7095c5b938cdef122 Mon Sep 17 00:00:00 2001 From: PJ Reiniger Date: Wed, 14 May 2025 01:01:47 -0400 Subject: [PATCH] [bazel] Add scripts to validate pregeneration tools (#7690) --- BUILD.bazel | 49 +++++ README-Bazel.md | 6 + WORKSPACE | 84 ++++++++- hal/BUILD.bazel | 54 ++++++ hal/generate.bzl | 47 +++++ ntcore/BUILD.bazel | 39 ++++ ntcore/generate_ntcore.bzl | 31 +++ requirements.txt | 3 + requirements_lock.txt | 208 +++++++++++++++++++++ shared/bazel/compiler_flags/linux_flags.rc | 7 + wpilibNewCommands/BUILD.bazel | 38 ++++ wpilibNewCommands/generate.bzl | 32 ++++ wpilibc/BUILD.bazel | 59 ++++++ wpilibc/generate.bzl | 33 ++++ wpilibc/generate_wpilibc.py | 42 +++++ wpilibcExamples/BUILD.bazel | 50 +++++ wpilibcExamples/build_cpp_examples.bzl | 79 ++++++++ wpilibcExamples/example_projects.bzl | 87 +++++++++ wpilibcExamples/generate_bazel_files.py | 58 ++++++ wpilibj/BUILD.bazel | 60 +++++- wpilibj/generate.bzl | 32 ++++ wpilibj/generate_wpilibj.py | 32 ++++ wpilibjExamples/BUILD.bazel | 46 +++++ wpilibjExamples/build_java_examples.bzl | 71 +++++++ wpilibjExamples/example_projects.bzl | 93 +++++++++ wpilibjExamples/generate_bazel_files.py | 68 +++++++ wpimath/BUILD.bazel | 80 ++++++++ wpimath/generate.bzl | 54 ++++++ wpimath/generate_wpimath.py | 65 +++++++ wpiunits/BUILD.bazel | 27 +++ wpiunits/generate_wpiunits.bzl | 27 +++ wpiutil/BUILD.bazel | 52 ++++++ wpiutil/generate.bzl | 39 ++++ 33 files changed, 1750 insertions(+), 2 deletions(-) create mode 100644 BUILD.bazel create mode 100644 hal/generate.bzl create mode 100644 ntcore/generate_ntcore.bzl create mode 100644 requirements.txt create mode 100644 requirements_lock.txt create mode 100644 wpilibNewCommands/generate.bzl create mode 100644 wpilibc/generate.bzl create mode 100644 wpilibc/generate_wpilibc.py create mode 100644 wpilibcExamples/BUILD.bazel create mode 100644 wpilibcExamples/build_cpp_examples.bzl create mode 100644 wpilibcExamples/example_projects.bzl create mode 100644 wpilibcExamples/generate_bazel_files.py create mode 100644 wpilibj/generate.bzl create mode 100644 wpilibj/generate_wpilibj.py create mode 100644 wpilibjExamples/BUILD.bazel create mode 100644 wpilibjExamples/build_java_examples.bzl create mode 100644 wpilibjExamples/example_projects.bzl create mode 100644 wpilibjExamples/generate_bazel_files.py create mode 100644 wpimath/generate.bzl create mode 100644 wpimath/generate_wpimath.py create mode 100644 wpiunits/generate_wpiunits.bzl create mode 100644 wpiutil/generate.bzl diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 0000000000..3c3b5bde20 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,49 @@ +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") +load("@rules_python//python:pip.bzl", "compile_pip_requirements") + +filegroup( + name = "license", + srcs = [ + "LICENSE.md", + "ThirdPartyNotices.txt", + ], + visibility = ["//visibility:public"], +) + +# bazel build //:requirements.lock +compile_pip_requirements( + name = "requirements", + extra_args = ["--allow-unsafe"], + requirements_in = "requirements.txt", + requirements_txt = "requirements_lock.txt", + tags = ["no-roborio"], +) + +alias( + name = "quickbuf_protoc", + actual = select({ + "@bazel_tools//src/conditions:darwin": "@quickbuffer_protoc_osx//file", + "@bazel_tools//src/conditions:windows": "@quickbuffer_protoc_windows//file", + "@rules_bzlmodrio_toolchains//constraints/combined:is_linux": "@quickbuffer_protoc_linux//file", + }), + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + +# This is a helper to run all of the pregeneration scripts at once. +write_source_files( + name = "write_all", + additional_update_targets = [ + "//hal:write_hal", + "//ntcore:write_ntcore", + "//wpilibc:write_wpilibc", + "//wpilibcExamples:write_example_project_list", + "//wpilibj:write_wpilibj", + "//wpilibjExamples:write_example_project_list", + "//wpilibNewCommands:write_wpilib_new_commands", + "//wpimath:write_wpimath", + "//wpiunits:write_wpiunits", + "//wpiutil:write_wpiutil", + ], + tags = ["pregeneration"], +) diff --git a/README-Bazel.md b/README-Bazel.md index 2a3bb45b75..fc4ddf0b30 100644 --- a/README-Bazel.md +++ b/README-Bazel.md @@ -23,3 +23,9 @@ Examples: build --local_ram_resources=HOST_RAM*.5 # Don't use more than half my RAM when building build --local_cpu_resources=HOST_CPUS-1 # Leave one core alone ``` + +## Pregenerating Files +allwpilib uses extensive use of pre-generating files that are later used to build C++ / Java libraries that are tracked by version control. Quite often, +these pre-generation scripts use some configuration file to create multipile files inside of an output directory. While this process could be accomplished +with a `genrule` that would require an explicit listing of every output file, which would be tedious to maintain as well as potentially confusing to people +adding new features those libraries. Therefor, we use `@aspect_bazel_lib` and their `write_source_files` feature to generate these directories. In the event that the generation process creates more than a small handful of predictable files, a custom rule is written to generate the directory. diff --git a/WORKSPACE b/WORKSPACE index 7362421731..b8848cde8f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,34 @@ -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file") + +# Rules Python +http_archive( + name = "rules_python", + sha256 = "c68bdc4fbec25de5b5493b8819cfc877c4ea299c0dcb15c244c5a00208cde311", + strip_prefix = "rules_python-0.31.0", + url = "https://github.com/bazelbuild/rules_python/releases/download/0.31.0/rules_python-0.31.0.tar.gz", +) + +load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains") + +py_repositories() + +python_register_toolchains( + name = "python_3_10", + ignore_root_user_error = True, + python_version = "3.10", +) + +load("@rules_python//python:pip.bzl", "pip_parse") + +pip_parse( + name = "allwpilib_pip_deps", + python_interpreter_target = "@python_3_10_host//:python", + requirements_lock = "//:requirements_lock.txt", +) + +load("@allwpilib_pip_deps//:requirements.bzl", "install_deps") + +install_deps() # Download Extra java rules http_archive( @@ -99,6 +129,18 @@ maven_install( ], ) +# Setup aspect lib +http_archive( + name = "aspect_bazel_lib", + sha256 = "a8a92645e7298bbf538aa880131c6adb4cf6239bbd27230f077a00414d58e4ce", + strip_prefix = "bazel-lib-2.7.2", + url = "https://github.com/aspect-build/bazel-lib/releases/download/v2.7.2/bazel-lib-v2.7.2.tar.gz", +) + +load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies") + +aspect_bazel_lib_dependencies() + # Download toolchains http_archive( name = "rules_bzlmodrio_toolchains", @@ -190,3 +232,43 @@ load( ) apple_support_dependencies() + +# Setup quickbuf compiler +QUICKBUF_VERSION = "1.3.2" + +http_file( + name = "quickbuffer_protoc_linux", + executable = True, + sha256 = "f9a041bccaa7040db523666ef1b5fe9f6f94e70a82c88951f18f58aadd9c50b5", + url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-linux-x86_64.exe", +) + +http_file( + name = "quickbuffer_protoc_osx", + executable = True, + sha256 = "ea307c2b69664ae7e7c69db4cddf5803187e5a34bceffd09a21652f0f16044f7", + url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-osx-x86_64.exe ", +) + +http_file( + name = "quickbuffer_protoc_windows", + executable = True, + sha256 = "27dc1f29764a62b5e6a813a4bcd63e81bbdc3394da760a44acae1025b4a89f1d", + url = "https://repo1.maven.org/maven2/us/hebi/quickbuf/protoc-gen-quickbuf/" + QUICKBUF_VERSION + "/protoc-gen-quickbuf-" + QUICKBUF_VERSION + "-windows-x86_64.exe ", +) + +# Setup rules_proto +http_archive( + name = "rules_proto", + sha256 = "0e5c64a2599a6e26c6a03d6162242d231ecc0de219534c38cb4402171def21e8", + strip_prefix = "rules_proto-7.0.2", + url = "https://github.com/bazelbuild/rules_proto/releases/download/7.0.2/rules_proto-7.0.2.tar.gz", +) + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies") + +rules_proto_dependencies() + +load("@rules_proto//proto:setup.bzl", "rules_proto_setup") + +rules_proto_setup() diff --git a/hal/BUILD.bazel b/hal/BUILD.bazel index ce7368560d..b846ddd730 100644 --- a/hal/BUILD.bazel +++ b/hal/BUILD.bazel @@ -1,8 +1,55 @@ +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary") +load("@rules_python//python:defs.bzl", "py_binary") +load("//hal:generate.bzl", "generate_hal") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library") +filegroup( + name = "templates", + srcs = glob(["src/generate/*"]), +) + +filegroup( + name = "proto_files", + srcs = glob(["src/mrc/proto/**/*.proto"]), +) + +py_binary( + name = "generate_nanopb", + srcs = ["generate_nanopb.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +generate_hal( + name = "generate_hal_files", + proto_files = ":proto_files", +) + +write_source_files( + name = "write_hal", + files = { + "src/generated": ":generate_hal_files", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + +cc_library( + name = "generated_cc_headers", + hdrs = glob(["src/generated/main/native/include/**"]), + includes = ["src/generated/main/native/include"], + strip_include_prefix = "src/generated/main/native/include", + visibility = ["//hal:__subpackages__"], +) + cc_library( name = "mrc_cc_headers", hdrs = glob(["src/mrc/include/**"]), @@ -19,6 +66,12 @@ cc_library( visibility = ["//hal:__subpackages__"], ) +filegroup( + name = "generated_java", + srcs = glob(["src/generated/main/java/**/*.java"]), + visibility = ["//hal:__subpackages__"], +) + SYSTEMCORE_SRCS = glob(["src/main/native/systemcore/**"]) SIM_SRCS = glob(["src/main/native/sim/**"]) @@ -45,6 +98,7 @@ cc_library( strip_include_prefix = "src/main/native/include", visibility = ["//visibility:public"], deps = [ + ":generated_cc_headers", ":generated_mrc_cc_headers", ":mrc_cc_headers", "//ntcore:ntcore.static", diff --git a/hal/generate.bzl b/hal/generate.bzl new file mode 100644 index 0000000000..29bdd38b39 --- /dev/null +++ b/hal/generate.bzl @@ -0,0 +1,47 @@ +def __generate_hal_impl(ctx): + """ + Custom rule used to create the hal pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path + "/main/native/cpp/mrc/protobuf") + args.add("--nanopb", ctx.executable._nanopb_generator) + + ctx.actions.run( + inputs = ctx.attr._templates.files.to_list() + ctx.attr.proto_files.files.to_list(), + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + tools = [ctx.executable._protoc, ctx.executable._nanopb_generator], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_hal = rule( + implementation = __generate_hal_impl, + attrs = { + "proto_files": attr.label( + allow_files = True, + mandatory = True, + ), + "_nanopb_generator": attr.label( + default = Label("//wpiutil:nanopb_generator"), + cfg = "exec", + executable = True, + ), + "_protoc": attr.label( + default = Label("@com_google_protobuf//:protoc"), + cfg = "exec", + executable = True, + ), + "_templates": attr.label( + default = Label("//hal:templates"), + ), + "_tool": attr.label( + default = Label("//hal:generate_nanopb"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/ntcore/BUILD.bazel b/ntcore/BUILD.bazel index 4147b8ef81..fedf16b531 100644 --- a/ntcore/BUILD.bazel +++ b/ntcore/BUILD.bazel @@ -1,8 +1,47 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary") +load("@rules_python//python:defs.bzl", "py_binary") +load("//ntcore:generate_ntcore.bzl", "generate_ntcore") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library") +generate_ntcore( + name = "generate_ntcore", +) + +filegroup( + name = "templates", + srcs = glob([ + "src/generate/**/*.jinja", + "src/generate/*.json", + ]), +) + +py_binary( + name = "generate_topics", + srcs = ["generate_topics.py"], + data = [":templates"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +write_source_files( + name = "write_ntcore", + files = { + "src/generated": ":generate_ntcore", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + cc_library( name = "generated_cc_headers", hdrs = glob(["src/generated/main/native/include/**"]), diff --git a/ntcore/generate_ntcore.bzl b/ntcore/generate_ntcore.bzl new file mode 100644 index 0000000000..cec26e8f54 --- /dev/null +++ b/ntcore/generate_ntcore.bzl @@ -0,0 +1,31 @@ +def __generate_ntcore_impl(ctx): + """ + Custom rule used to create the ntcore pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + + ctx.actions.run( + inputs = ctx.attr._templates.files, + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_ntcore = rule( + implementation = __generate_ntcore_impl, + attrs = { + "_templates": attr.label( + default = Label("//ntcore:templates"), + ), + "_tool": attr.label( + default = Label("//ntcore:generate_topics"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..3220185bfd --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +jinja2==3.0.0a1 +protobuf==5.28.3 +grpcio-tools==1.68.0 diff --git a/requirements_lock.txt b/requirements_lock.txt new file mode 100644 index 0000000000..332688e377 --- /dev/null +++ b/requirements_lock.txt @@ -0,0 +1,208 @@ +# +# This file is autogenerated by pip-compile with Python 3.10 +# by the following command: +# +# bazel run //:requirements.update +# +grpcio==1.68.0 \ + --hash=sha256:0d230852ba97654453d290e98d6aa61cb48fa5fafb474fb4c4298d8721809354 \ + --hash=sha256:0efbbd849867e0e569af09e165363ade75cf84f5229b2698d53cf22c7a4f9e21 \ + --hash=sha256:14331e5c27ed3545360464a139ed279aa09db088f6e9502e95ad4bfa852bb116 \ + --hash=sha256:15327ab81131ef9b94cb9f45b5bd98803a179c7c61205c8c0ac9aff9d6c4e82a \ + --hash=sha256:15377bce516b1c861c35e18eaa1c280692bf563264836cece693c0f169b48829 \ + --hash=sha256:15fa1fe25d365a13bc6d52fcac0e3ee1f9baebdde2c9b3b2425f8a4979fccea1 \ + --hash=sha256:18668e36e7f4045820f069997834e94e8275910b1f03e078a6020bd464cb2363 \ + --hash=sha256:2af76ab7c427aaa26aa9187c3e3c42f38d3771f91a20f99657d992afada2294a \ + --hash=sha256:2bddd04a790b69f7a7385f6a112f46ea0b34c4746f361ebafe9ca0be567c78e9 \ + --hash=sha256:32a9cb4686eb2e89d97022ecb9e1606d132f85c444354c17a7dbde4a455e4a3b \ + --hash=sha256:3ac7f10850fd0487fcce169c3c55509101c3bde2a3b454869639df2176b60a03 \ + --hash=sha256:3b2b559beb2d433129441783e5f42e3be40a9e1a89ec906efabf26591c5cd415 \ + --hash=sha256:4028b8e9a3bff6f377698587d642e24bd221810c06579a18420a17688e421af7 \ + --hash=sha256:44bcbebb24363d587472089b89e2ea0ab2e2b4df0e4856ba4c0b087c82412121 \ + --hash=sha256:46a2d74d4dd8993151c6cd585594c082abe74112c8e4175ddda4106f2ceb022f \ + --hash=sha256:4df81d78fd1646bf94ced4fb4cd0a7fe2e91608089c522ef17bc7db26e64effd \ + --hash=sha256:4e300e6978df0b65cc2d100c54e097c10dfc7018b9bd890bbbf08022d47f766d \ + --hash=sha256:4f1931c7aa85be0fa6cea6af388e576f3bf6baee9e5d481c586980c774debcb4 \ + --hash=sha256:50992f214264e207e07222703c17d9cfdcc2c46ed5a1ea86843d440148ebbe10 \ + --hash=sha256:55d3b52fd41ec5772a953612db4e70ae741a6d6ed640c4c89a64f017a1ac02b5 \ + --hash=sha256:5a180328e92b9a0050958ced34dddcb86fec5a8b332f5a229e353dafc16cd332 \ + --hash=sha256:619b5d0f29f4f5351440e9343224c3e19912c21aeda44e0c49d0d147a8d01544 \ + --hash=sha256:6b2f98165ea2790ea159393a2246b56f580d24d7da0d0342c18a085299c40a75 \ + --hash=sha256:6f9c7ad1a23e1047f827385f4713b5b8c6c7d325705be1dd3e31fb00dcb2f665 \ + --hash=sha256:79f81b7fbfb136247b70465bd836fa1733043fdee539cd6031cb499e9608a110 \ + --hash=sha256:7e0a3e72c0e9a1acab77bef14a73a416630b7fd2cbd893c0a873edc47c42c8cd \ + --hash=sha256:7e7483d39b4a4fddb9906671e9ea21aaad4f031cdfc349fec76bdfa1e404543a \ + --hash=sha256:88fb2925789cfe6daa20900260ef0a1d0a61283dfb2d2fffe6194396a354c618 \ + --hash=sha256:8af6137cc4ae8e421690d276e7627cfc726d4293f6607acf9ea7260bd8fc3d7d \ + --hash=sha256:8b0ff09c81e3aded7a183bc6473639b46b6caa9c1901d6f5e2cba24b95e59e30 \ + --hash=sha256:8c73f9fbbaee1a132487e31585aa83987ddf626426d703ebcb9a528cf231c9b1 \ + --hash=sha256:99f06232b5c9138593ae6f2e355054318717d32a9c09cdc5a2885540835067a1 \ + --hash=sha256:9fe1b141cda52f2ca73e17d2d3c6a9f3f3a0c255c216b50ce616e9dca7e3441d \ + --hash=sha256:a17278d977746472698460c63abf333e1d806bd41f2224f90dbe9460101c9796 \ + --hash=sha256:a59f5822f9459bed098ffbceb2713abbf7c6fd13f2b9243461da5c338d0cd6c3 \ + --hash=sha256:a6213d2f7a22c3c30a479fb5e249b6b7e648e17f364598ff64d08a5136fe488b \ + --hash=sha256:a831dcc343440969aaa812004685ed322cdb526cd197112d0db303b0da1e8659 \ + --hash=sha256:afbf45a62ba85a720491bfe9b2642f8761ff348006f5ef67e4622621f116b04a \ + --hash=sha256:b0cf343c6f4f6aa44863e13ec9ddfe299e0be68f87d68e777328bff785897b05 \ + --hash=sha256:c03d89df516128febc5a7e760d675b478ba25802447624edf7aa13b1e7b11e2a \ + --hash=sha256:c1245651f3c9ea92a2db4f95d37b7597db6b246d5892bca6ee8c0e90d76fb73c \ + --hash=sha256:cc5f0a4f5904b8c25729a0498886b797feb817d1fd3812554ffa39551112c161 \ + --hash=sha256:dba037ff8d284c8e7ea9a510c8ae0f5b016004f13c3648f72411c464b67ff2fb \ + --hash=sha256:def1a60a111d24376e4b753db39705adbe9483ef4ca4761f825639d884d5da78 \ + --hash=sha256:e0d2f68eaa0a755edd9a47d40e50dba6df2bceda66960dee1218da81a2834d27 \ + --hash=sha256:e0d30f3fee9372796f54d3100b31ee70972eaadcc87314be369360248a3dcffe \ + --hash=sha256:e18589e747c1e70b60fab6767ff99b2d0c359ea1db8a2cb524477f93cdbedf5b \ + --hash=sha256:e1e7ed311afb351ff0d0e583a66fcb39675be112d61e7cfd6c8269884a98afbc \ + --hash=sha256:e46541de8425a4d6829ac6c5d9b16c03c292105fe9ebf78cb1c31e8d242f9155 \ + --hash=sha256:e694b5928b7b33ca2d3b4d5f9bf8b5888906f181daff6b406f4938f3a997a490 \ + --hash=sha256:f60fa2adf281fd73ae3a50677572521edca34ba373a45b457b5ebe87c2d01e1d \ + --hash=sha256:f84890b205692ea813653ece4ac9afa2139eae136e419231b0eec7c39fdbe4c2 \ + --hash=sha256:f8f695d9576ce836eab27ba7401c60acaf9ef6cf2f70dfe5462055ba3df02cc3 \ + --hash=sha256:fc05759ffbd7875e0ff2bd877be1438dfe97c9312bbc558c8284a9afa1d0f40e \ + --hash=sha256:fd2c2d47969daa0e27eadaf15c13b5e92605c5e5953d23c06d0b5239a2f176d3 + # via grpcio-tools +grpcio-tools==1.68.0 \ + --hash=sha256:01ace351a51d7ee120963a4612b1f00e964462ec548db20d17f8902e238592c8 \ + --hash=sha256:061345c0079b9471f32230186ab01acb908ea0e577bc1699a8cf47acef8be4af \ + --hash=sha256:0f77957e3a0916a0dd18d57ce6b49d95fc9a5cfed92310f226339c0fda5394f6 \ + --hash=sha256:10d03e3ad4af6284fd27cb14f5a3d52045913c1253e3e24a384ed91bc8adbfcd \ + --hash=sha256:1117a81592542f0c36575082daa6413c57ca39188b18a4c50ec7332616f4b97e \ + --hash=sha256:1769d7f529de1cc102f7fb900611e3c0b69bdb244fca1075b24d6e5b49024586 \ + --hash=sha256:17d0c9004ea82b4213955a585401e80c30d4b37a1d4ace32ccdea8db4d3b7d43 \ + --hash=sha256:196cd8a3a5963a4c9e424314df9eb573b305e6f958fe6508d26580ce01e7aa56 \ + --hash=sha256:19bafb80948eda979b1b3a63c1567162d06249f43068a0e46a028a448e6f72d4 \ + --hash=sha256:261d98fd635595de42aadee848f9af46da6654d63791c888891e94f66c5d0682 \ + --hash=sha256:26335eea976dfc1ff5d90b19c309a9425bd53868112a0507ad20f297f2c21d3e \ + --hash=sha256:28ebdbad2ef16699d07400b65260240851049a75502eff69a59b127d3ab960f1 \ + --hash=sha256:2919faae04fe47bad57fc9b578aeaab527da260e851f321a253b6b11862254a8 \ + --hash=sha256:2ec3a2e0afa4866ccc5ba33c071aebaa619245dfdd840cbb74f2b0591868d085 \ + --hash=sha256:3aa40958355920ae2846c6fb5cadac4f2c8e33234a2982fef8101da0990e3968 \ + --hash=sha256:453ee3193d59c974c678d91f08786f43c25ef753651b0825dc3d008c31baf68d \ + --hash=sha256:46b537480b8fd2195d988120a28467601a2a3de2e504043b89fb90318e1eb754 \ + --hash=sha256:4fe611d89a1836df8936f066d39c7eb03d4241806449ec45d4b8e1c843ae8011 \ + --hash=sha256:511224a99726eb84db9ddb84dc8a75377c3eae797d835f99e80128ec618376d5 \ + --hash=sha256:51e5a090849b30c99a2396d42140b8a3e558eff6cdfa12603f9582e2cd07724e \ + --hash=sha256:533ce6791a5ba21e35d74c6c25caf4776f5692785a170c01ea1153783ad5af31 \ + --hash=sha256:56842a0ce74b4b92eb62cd5ee00181b2d3acc58ba0c4fd20d15a5db51f891ba6 \ + --hash=sha256:57e29e78c33fb1b1d557fbe7650d722d1f2b0a9f53ea73beb8ea47e627b6000b \ + --hash=sha256:59a885091bf29700ba0e14a954d156a18714caaa2006a7f328b18e1ac4b1e721 \ + --hash=sha256:5afd2f3f7257b52228a7808a2b4a765893d4d802d7a2377d9284853e67d045c6 \ + --hash=sha256:5d3150d784d8050b10dcf5eb06e04fb90747a1547fed3a062a608d940fe57066 \ + --hash=sha256:66b70b37184d40806844f51c2757c6b852511d4ea46a3bf2c7e931a47b455bc6 \ + --hash=sha256:6950725bf7a496f81d3ec3324334ffc9dbec743b510dd0e897f51f8627eeb6ac \ + --hash=sha256:6dd69c9f3ff85eee8d1f71adf7023c638ca8d465633244ac1b7f19bc3668612d \ + --hash=sha256:700f171cd3293ee8d50cd43171562ff07b14fa8e49ee471cd91c6924c7da8644 \ + --hash=sha256:737804ec2225dd4cc27e633b4ca0e963b0795161bf678285fab6586e917fd867 \ + --hash=sha256:766c2cd2e365e0fc0e559af56f2c2d144d95fd7cb8668a34d533e66d6435eb34 \ + --hash=sha256:795f2cd76f68a12b0b5541b98187ba367dd69b49d359cf98b781ead742961370 \ + --hash=sha256:7dc5195dc02057668cc22da1ff1aea1811f6fa0deb801b3194dec1fe0bab1cf0 \ + --hash=sha256:80b733014eb40d920d836d782e5cdea0dcc90d251a2ffb35ab378ef4f8a42c14 \ + --hash=sha256:849b12bec2320e49e988df104c92217d533e01febac172a4495caab36d9f0edc \ + --hash=sha256:88640d95ee41921ac7352fa5fadca52a06d7e21fbe53e6a706a9a494f756be7d \ + --hash=sha256:8fefc6d000e169a97336feded23ce614df3fb9926fc48c7a9ff8ea459d93b5b0 \ + --hash=sha256:92a09afe64fe26696595de2036e10967876d26b12c894cc9160f00152cacebe7 \ + --hash=sha256:9509a5c3ed3d54fa7ac20748d501cb86668f764605a0a68f275339ee0f1dc1a6 \ + --hash=sha256:ab93fab49fa1e699e577ff5fbb99aba660164d710d4c33cfe0aa9d06f585539f \ + --hash=sha256:b094b22919b786ad73c20372ef5e546330e7cd2c6dc12293b7ed586975f35d38 \ + --hash=sha256:b47ae076ffb29a68e517bc03552bef0d9c973f8e18adadff180b123e973a26ea \ + --hash=sha256:b4ca81770cd729a9ea536d871aacedbde2b732bb9bb83c9d993d63f58502153d \ + --hash=sha256:c10f3faa0cc4d89eb546f53b623837af23e86dc495d3b89510bcc0e0a6c0b8b2 \ + --hash=sha256:c77ecc5164bb413a613bdac9091dcc29d26834a2ac42fcd1afdfcda9e3003e68 \ + --hash=sha256:cad40c3164ee9cef62524dea509449ea581b17ea493178beef051bf79b5103ca \ + --hash=sha256:d0470ffc6a93c86cdda48edd428d22e2fef17d854788d60d0d5f291038873157 \ + --hash=sha256:d3e678162e1d7a8720dc05fdd537fc8df082a50831791f7bb1c6f90095f8368b \ + --hash=sha256:dd9a654af8536b3de8525bff72a245fef62d572eabf96ac946fe850e707cb27d \ + --hash=sha256:e31be6dc61496a59c1079b0a669f93dfcc2cdc4b1dbdc4374247cd09cee1329b \ + --hash=sha256:e903d07bc65232aa9e7704c829aec263e1e139442608e473d7912417a9908e29 \ + --hash=sha256:ee86157ef899f58ba2fe1055cce0d33bd703e99aa6d5a0895581ac3969f06bfa \ + --hash=sha256:f65942fab440e99113ce14436deace7554d5aa554ea18358e3a5f3fc47efe322 \ + --hash=sha256:f95103e3e4e7fee7c6123bc9e4e925e07ad24d8d09d7c1c916fb6c8d1cb9e726 + # via -r requirements.txt +jinja2==3.0.0a1 \ + --hash=sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484 \ + --hash=sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668 + # via -r requirements.txt +markupsafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144 \ + --hash=sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29 \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a \ + --hash=sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178 \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 + # via jinja2 +protobuf==5.28.3 \ + --hash=sha256:0c4eec6f987338617072592b97943fdbe30d019c56126493111cf24344c1cc24 \ + --hash=sha256:135658402f71bbd49500322c0f736145731b16fc79dc8f367ab544a17eab4535 \ + --hash=sha256:27b246b3723692bf1068d5734ddaf2fccc2cdd6e0c9b47fe099244d80200593b \ + --hash=sha256:3e6101d095dfd119513cde7259aa703d16c6bbdfae2554dfe5cfdbe94e32d548 \ + --hash=sha256:3fa2de6b8b29d12c61911505d893afe7320ce7ccba4df913e2971461fa36d584 \ + --hash=sha256:64badbc49180a5e401f373f9ce7ab1d18b63f7dd4a9cdc43c92b9f0b481cef7b \ + --hash=sha256:70585a70fc2dd4818c51287ceef5bdba6387f88a578c86d47bb34669b5552c36 \ + --hash=sha256:712319fbdddb46f21abb66cd33cb9e491a5763b2febd8f228251add221981135 \ + --hash=sha256:91fba8f445723fcf400fdbe9ca796b19d3b1242cd873907979b9ed71e4afe868 \ + --hash=sha256:a3f6857551e53ce35e60b403b8a27b0295f7d6eb63d10484f12bc6879c715687 \ + --hash=sha256:cee1757663fa32a1ee673434fcf3bf24dd54763c79690201208bafec62f19eed + # via + # -r requirements.txt + # grpcio-tools + +# The following packages are considered to be unsafe in a requirements file: +setuptools==75.6.0 \ + --hash=sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6 \ + --hash=sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d + # via grpcio-tools diff --git a/shared/bazel/compiler_flags/linux_flags.rc b/shared/bazel/compiler_flags/linux_flags.rc index 0a19c1d73d..a15a5f7d8c 100644 --- a/shared/bazel/compiler_flags/linux_flags.rc +++ b/shared/bazel/compiler_flags/linux_flags.rc @@ -12,3 +12,10 @@ build:linux --copt=-Werror # Not in nativetools build:linux --cxxopt=-Wno-deprecated-enum-enum-conversion + +# Cleanup build output for tools +build:linux --host_cxxopt=-Wno-missing-field-initializers +build:linux --host_cxxopt=-Wno-deprecated-enum-enum-conversion +build:linux --host_cxxopt=-Wno-sign-compare +build:linux --host_cxxopt=-Wno-unknown-pragmas +build:linux --host_cxxopt=-Wno-attributes diff --git a/wpilibNewCommands/BUILD.bazel b/wpilibNewCommands/BUILD.bazel index 37b063dd5b..5011bba0c5 100644 --- a/wpilibNewCommands/BUILD.bazel +++ b/wpilibNewCommands/BUILD.bazel @@ -1,6 +1,44 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary", "java_library") +load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") +load("//wpilibNewCommands:generate.bzl", "generate_wpilib_new_commands") + +py_binary( + name = "generate_hids", + srcs = ["generate_hids.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +filegroup( + name = "templates", + srcs = glob(["src/generate/main/**"]) + [ + "//wpilibj:hid_schema", + ], + visibility = ["//wpilibNewCommands:__subpackages__"], +) + +generate_wpilib_new_commands( + name = "generate_wpilib_new_commands", +) + +write_source_files( + name = "write_wpilib_new_commands", + files = { + "src/generated": ":generate_wpilib_new_commands", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) cc_library( name = "generated_cc_headers", diff --git a/wpilibNewCommands/generate.bzl b/wpilibNewCommands/generate.bzl new file mode 100644 index 0000000000..ab3598c13c --- /dev/null +++ b/wpilibNewCommands/generate.bzl @@ -0,0 +1,32 @@ +def __generate_wpilib_new_commands_impl(ctx): + """ + Custom rule used to create the wpilibNewCommands pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + args.add("--template_root", "wpilibNewCommands/src/generate") + + ctx.actions.run( + inputs = ctx.attr._templates.files, + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpilib_new_commands = rule( + implementation = __generate_wpilib_new_commands_impl, + attrs = { + "_templates": attr.label( + default = Label("//wpilibNewCommands:templates"), + ), + "_tool": attr.label( + default = Label("//wpilibNewCommands:generate_hids"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/wpilibc/BUILD.bazel b/wpilibc/BUILD.bazel index 62e871af19..e7c8fe9538 100644 --- a/wpilibc/BUILD.bazel +++ b/wpilibc/BUILD.bazel @@ -1,5 +1,54 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") +load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules/gen:gen-version-file.bzl", "generate_version_file") +load("//wpilibc:generate.bzl", "generate_wpilibc") + +py_binary( + name = "generate_hids", + srcs = ["generate_hids.py"], + tags = ["manual"], + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +py_binary( + name = "generate_pwm_motor_controllers", + srcs = ["generate_pwm_motor_controllers.py"], + tags = ["manual"], + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +py_binary( + name = "generate_wpilibc_py", + srcs = ["generate_wpilibc.py"], + main = "generate_wpilibc.py", + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + ":generate_hids", + ":generate_pwm_motor_controllers", + ], +) + +filegroup( + name = "templates", + srcs = glob(["src/generate/main/native/**"]) + [ + "//wpilibj:hid_schema", + "//wpilibj:pwm_schema", + ], + visibility = ["//wpilibc:__subpackages__"], +) + +generate_wpilibc( + name = "generate_wpilibc", +) generate_version_file( name = "generate-version", @@ -8,6 +57,16 @@ generate_version_file( visibility = ["//wpilibc:__subpackages__"], ) +write_source_files( + name = "write_wpilibc", + files = { + "src/generated": ":generate_wpilibc", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + cc_library( name = "generated_cc_headers", hdrs = glob(["src/generated/main/native/include/**"]), diff --git a/wpilibc/generate.bzl b/wpilibc/generate.bzl new file mode 100644 index 0000000000..cc4249ce08 --- /dev/null +++ b/wpilibc/generate.bzl @@ -0,0 +1,33 @@ +def __generate_wpilibc_impl(ctx): + """ + Custom rule used to create the wpilibc pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + args.add("--schema_root", "wpilibj/src/generate") + args.add("--template_root", "wpilibc/src/generate") + + ctx.actions.run( + inputs = ctx.attr._templates.files, + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpilibc = rule( + implementation = __generate_wpilibc_impl, + attrs = { + "_templates": attr.label( + default = Label("//wpilibc:templates"), + ), + "_tool": attr.label( + default = Label("//wpilibc:generate_wpilibc_py"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/wpilibc/generate_wpilibc.py b/wpilibc/generate_wpilibc.py new file mode 100644 index 0000000000..d46c48afed --- /dev/null +++ b/wpilibc/generate_wpilibc.py @@ -0,0 +1,42 @@ +import argparse +import os +from pathlib import Path + +from wpilibc.generate_hids import generate_hids +from wpilibc.generate_pwm_motor_controllers import generate_pwm_motor_controllers + + +def main(): + dirname, _ = os.path.split(os.path.abspath(__file__)) + + parser = argparse.ArgumentParser() + parser.add_argument( + "--output_directory", + help="Optional. If set, will output the generated files to this directory, otherwise it will use a path relative to the script", + default=os.path.join(dirname, "src/generated"), + type=Path, + ) + parser.add_argument( + "--schema_root", + help="Optional. If set, will use this directory as the root for discovering the pwm controller schema", + default=os.path.join(dirname, "../wpilibj/src/generate"), + type=Path, + ) + parser.add_argument( + "--template_root", + help="Optional. If set, will use this directory as the root for the jinja templates", + default=os.path.join(dirname, "src/generate"), + type=Path, + ) + args = parser.parse_args() + + generate_hids( + args.output_directory, args.template_root, args.schema_root / "hids.json" + ) + generate_pwm_motor_controllers( + args.output_directory, args.template_root, args.schema_root + ) + + +if __name__ == "__main__": + main() diff --git a/wpilibcExamples/BUILD.bazel b/wpilibcExamples/BUILD.bazel new file mode 100644 index 0000000000..511b0f6971 --- /dev/null +++ b/wpilibcExamples/BUILD.bazel @@ -0,0 +1,50 @@ +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_file") +load("@rules_python//python:defs.bzl", "py_binary") +load("//wpilibcExamples:build_cpp_examples.bzl", "build_commands", "build_examples", "build_snippets", "build_templates", "build_tests") + +py_binary( + name = "generate_bazel_files", + srcs = ["generate_bazel_files.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), +) + +cmd = "$(locations :generate_bazel_files) $(OUTS)" + +genrule( + name = "generate_bazel_files_rule", + srcs = [ + "src/main/cpp/commands/commands.json", + "src/main/cpp/examples/examples.json", + "src/main/cpp/snippets/snippets.json", + "src/main/cpp/templates/templates.json", + ], + outs = ["gen/example_projects.bzl"], + cmd = cmd, + tools = [":generate_bazel_files"], +) + +write_source_file( + name = "write_example_project_list", + in_file = ":generate_bazel_files_rule", + out_file = "example_projects.bzl", + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + +halsim_deps = [ +] + +build_commands() + +build_examples(halsim_deps = halsim_deps) + +build_snippets() + +build_templates() + +build_tests() diff --git a/wpilibcExamples/build_cpp_examples.bzl b/wpilibcExamples/build_cpp_examples.bzl new file mode 100644 index 0000000000..1929d48ac3 --- /dev/null +++ b/wpilibcExamples/build_cpp_examples.bzl @@ -0,0 +1,79 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") +load("//wpilibcExamples:example_projects.bzl", "COMMANDS_V2_FOLDERS", "EXAMPLE_FOLDERS", "SNIPPETS_FOLDERS", "TEMPLATES_FOLDERS", "TESTS_FOLDERS") + +def build_examples(halsim_deps = []): + for folder in EXAMPLE_FOLDERS: + cc_library( + name = folder + "-examples-headers", + hdrs = native.glob(["src/main/cpp/examples/" + folder + "/include/**/*.h"]), + strip_include_prefix = "src/main/cpp/examples/" + folder + "/include", + tags = ["wpi-example"], + ) + cc_binary( + name = folder + "-example", + srcs = native.glob(["src/main/cpp/examples/" + folder + "/cpp/**/*.cpp", "src/main/cpp/examples/" + folder + "/c/**/*.c"]), + deps = [ + "//wpilibNewCommands:wpilibNewCommands.static", + "//apriltag:apriltag.static", + "//romiVendordep:romi-cpp.static", + "//xrpVendordep:xrp-cpp", + ":{}-examples-headers".format(folder), + ], + tags = ["wpi-example"], + ) + +def build_commands(): + for folder in COMMANDS_V2_FOLDERS: + cc_library( + name = folder + "-command", + srcs = native.glob(["src/main/cpp/commands/" + folder + "/**/*.cpp"]), + hdrs = native.glob(["src/main/cpp/commands/" + folder + "/**/*.h"]), + deps = [ + "//wpilibNewCommands:wpilibNewCommands.static", + ], + strip_include_prefix = "src/main/cpp/commands/" + folder, + tags = ["wpi-example"], + ) + +def build_snippets(): + for folder in SNIPPETS_FOLDERS: + cc_library( + name = folder + "-template", + srcs = native.glob(["src/main/cpp/snippets/" + folder + "/**/*.cpp"]), + hdrs = native.glob(["src/main/cpp/snippets/" + folder + "/**/*.h"]), + deps = [ + "//wpilibNewCommands:wpilibNewCommands.static", + ], + strip_include_prefix = "src/main/cpp/snippets/" + folder + "/include", + tags = ["wpi-example"], + ) + +def build_templates(): + for folder in TEMPLATES_FOLDERS: + cc_library( + name = folder + "-template", + srcs = native.glob(["src/main/cpp/templates/" + folder + "/**/*.cpp"]), + hdrs = native.glob(["src/main/cpp/templates/" + folder + "/**/*.h"]), + deps = [ + "//wpilibNewCommands:wpilibNewCommands.static", + ], + strip_include_prefix = "src/main/cpp/templates/" + folder + "/include", + tags = ["wpi-example"], + ) + +def build_tests(): + for folder in TESTS_FOLDERS: + example_src_folder = "src/main/cpp/examples/" + folder + example_test_folder = "src/test/cpp/examples/" + folder + cc_test( + name = folder + "-test", + size = "small", + srcs = native.glob([example_test_folder + "/**/*.cpp", example_src_folder + "/cpp/**/*.cpp", example_src_folder + "/c/**/*.c"]), + deps = [ + "//wpilibNewCommands:wpilibNewCommands.static", + ":{}-examples-headers".format(folder), + "//thirdparty/googletest:googletest.static", + ], + defines = ["RUNNING_FRC_TESTS=1"], + tags = ["wpi-example", "no-tsan", "no-asan", "no-ubsan", "exclusive"], + ) diff --git a/wpilibcExamples/example_projects.bzl b/wpilibcExamples/example_projects.bzl new file mode 100644 index 0000000000..2899928743 --- /dev/null +++ b/wpilibcExamples/example_projects.bzl @@ -0,0 +1,87 @@ +EXAMPLE_FOLDERS = [ + "AddressableLED", + "AprilTagsVision", + "ArcadeDrive", + "ArcadeDriveXboxController", + "ArmSimulation", + "CANPDP", + "DifferentialDriveBot", + "DifferentialDrivePoseEstimator", + "DigitalCommunication", + "DriveDistanceOffboard", + "DutyCycleEncoder", + "DutyCycleInput", + "ElevatorExponentialProfile", + "ElevatorExponentialSimulation", + "ElevatorProfiledPID", + "ElevatorSimulation", + "ElevatorTrapezoidProfile", + "Encoder", + "EventLoop", + "FlywheelBangBangController", + "GettingStarted", + "Gyro", + "GyroMecanum", + "HAL", + "HatchbotInlined", + "HatchbotTraditional", + "HidRumble", + "HttpCamera", + "I2CCommunication", + "IntermediateVision", + "MecanumBot", + "MecanumControllerCommand", + "MecanumDrive", + "MecanumDrivePoseEstimator", + "Mechanism2d", + "MotorControl", + "PotentiometerPID", + "QuickVision", + "RapidReactCommandBot", + "RomiReference", + "SelectCommand", + "SimpleDifferentialDriveSimulation", + "Solenoid", + "StateSpaceArm", + "StateSpaceElevator", + "StateSpaceFlywheel", + "StateSpaceFlywheelSysId", + "SwerveBot", + "SwerveControllerCommand", + "SwerveDrivePoseEstimator", + "SysIdRoutine", + "TankDrive", + "TankDriveXboxController", + "UnitTest", + "XRPReference", +] + +COMMANDS_V2_FOLDERS = [ + "command2", + "emptyclass", + "instantcommand", + "parallelcommandgroup", + "paralleldeadlinegroup", + "parallelracegroup", + "sequentialcommandgroup", + "subsystem2", +] + +SNIPPETS_FOLDERS = [ + "DutyCycleEncoder", + "Encoder", +] + +TEMPLATES_FOLDERS = [ + "commandbased", + "commandbasedskeleton", + "robotbaseskeleton", + "timed", + "timedskeleton", + "timeslice", + "timesliceskeleton", +] + +TESTS_FOLDERS = [ + "UnitTest", +] diff --git a/wpilibcExamples/generate_bazel_files.py b/wpilibcExamples/generate_bazel_files.py new file mode 100644 index 0000000000..3cbc983ccd --- /dev/null +++ b/wpilibcExamples/generate_bazel_files.py @@ -0,0 +1,58 @@ +import json +import sys + + +def load_foldernames(filename): + output = [] + + with open(filename, "r") as f: + data = json.load(f) + + for test_data in data: + output.append(test_data["foldername"]) + + return sorted(set(output)) + + +def load_tests(filename): + output = [] + + with open(filename, "r") as f: + data = json.load(f) + + for test_data in data: + if test_data.get("hasunittests", False): + output.append(test_data["foldername"]) + + return sorted(set(output)) + + +def main(): + examples = load_foldernames("wpilibcExamples/src/main/cpp/examples/examples.json") + commands = load_foldernames("wpilibcExamples/src/main/cpp/commands/commands.json") + templates = load_foldernames( + "wpilibcExamples/src/main/cpp/templates/templates.json" + ) + snippets = load_foldernames("wpilibcExamples/src/main/cpp/snippets/snippets.json") + tests = load_tests("wpilibcExamples/src/main/cpp/examples/examples.json") + + output_file = "wpilibcExamples/example_projects.bzl" + if len(sys.argv) == 2: + output_file = sys.argv[1] + + with open(output_file, "w") as f: + f.write('EXAMPLE_FOLDERS = [\n "' + '",\n "'.join(examples) + '",\n]\n\n') + f.write( + 'COMMANDS_V2_FOLDERS = [\n "' + '",\n "'.join(commands) + '",\n]\n\n' + ) + f.write( + 'SNIPPETS_FOLDERS = [\n "' + '",\n "'.join(snippets) + '",\n]\n\n' + ) + f.write( + 'TEMPLATES_FOLDERS = [\n "' + '",\n "'.join(templates) + '",\n]\n\n' + ) + f.write('TESTS_FOLDERS = [\n "' + '",\n "'.join(tests) + '",\n]\n') + + +if __name__ == "__main__": + main() diff --git a/wpilibj/BUILD.bazel b/wpilibj/BUILD.bazel index b5f193f2c4..9af93f7454 100644 --- a/wpilibj/BUILD.bazel +++ b/wpilibj/BUILD.bazel @@ -1,7 +1,65 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary") load("@rules_java//java:defs.bzl", "java_binary", "java_library") +load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules/gen:gen-version-file.bzl", "generate_version_file") +load("//wpilibj:generate.bzl", "generate_wpilibj") + +py_binary( + name = "generate_hids", + srcs = ["generate_hids.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +py_binary( + name = "generate_pwm_motor_controllers", + srcs = ["generate_pwm_motor_controllers.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +py_binary( + name = "generate_wpilibj_py", + srcs = ["generate_wpilibj.py"], + main = "generate_wpilibj.py", + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + ":generate_hids", + ":generate_pwm_motor_controllers", + ], +) + +generate_wpilibj( + name = "generate_wpilibj", +) + +write_source_files( + name = "write_wpilibj", + files = { + "src/generated": ":generate_wpilibj", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) generate_version_file( name = "generate-version", @@ -91,7 +149,7 @@ filegroup( filegroup( name = "templates", - srcs = glob(["src/generate/*.jinja"]) + [ + srcs = glob(["src/generate/**/*.jinja"]) + [ ":hid_schema", ":pwm_schema", ], diff --git a/wpilibj/generate.bzl b/wpilibj/generate.bzl new file mode 100644 index 0000000000..9fd6aaf2cd --- /dev/null +++ b/wpilibj/generate.bzl @@ -0,0 +1,32 @@ +def __generate_wpilibj_impl(ctx): + """ + Custom rule used to create the wpilibj pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + args.add("--template_root", "wpilibj/src/generate") + + ctx.actions.run( + inputs = ctx.attr._templates.files, + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpilibj = rule( + implementation = __generate_wpilibj_impl, + attrs = { + "_templates": attr.label( + default = Label("//wpilibj:templates"), + ), + "_tool": attr.label( + default = Label("//wpilibj:generate_wpilibj_py"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/wpilibj/generate_wpilibj.py b/wpilibj/generate_wpilibj.py new file mode 100644 index 0000000000..1118714599 --- /dev/null +++ b/wpilibj/generate_wpilibj.py @@ -0,0 +1,32 @@ +import argparse +import os +from pathlib import Path + +from wpilibj.generate_hids import generate_hids +from wpilibj.generate_pwm_motor_controllers import generate_pwm_motor_controllers + + +def main(): + dirname, _ = os.path.split(os.path.abspath(__file__)) + + parser = argparse.ArgumentParser() + parser.add_argument( + "--output_directory", + help="Optional. If set, will output the generated files to this directory, otherwise it will use a path relative to the script", + default=os.path.join(dirname, "src/generated"), + type=Path, + ) + parser.add_argument( + "--template_root", + help="Optional. If set, will use this directory as the root for the jinja templates", + default=os.path.join(dirname, "src/generate"), + type=Path, + ) + args = parser.parse_args() + + generate_hids(args.output_directory, args.template_root) + generate_pwm_motor_controllers(args.output_directory, args.template_root) + + +if __name__ == "__main__": + main() diff --git a/wpilibjExamples/BUILD.bazel b/wpilibjExamples/BUILD.bazel new file mode 100644 index 0000000000..4161746bab --- /dev/null +++ b/wpilibjExamples/BUILD.bazel @@ -0,0 +1,46 @@ +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_file") +load("@rules_python//python:defs.bzl", "py_binary") +load("//wpilibjExamples:build_java_examples.bzl", "build_commands", "build_examples", "build_snippets", "build_templates") + +py_binary( + name = "generate_bazel_files", + srcs = ["generate_bazel_files.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), +) + +genrule( + name = "generate_bazel_files_rule", + srcs = [ + "src/main/java/edu/wpi/first/wpilibj/commands/commands.json", + "src/main/java/edu/wpi/first/wpilibj/examples/examples.json", + "src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json", + "src/main/java/edu/wpi/first/wpilibj/templates/templates.json", + ], + outs = ["gen/example_projects.bzl"], + cmd = "$(locations :generate_bazel_files) $(OUTS)", + tools = [":generate_bazel_files"], +) + +write_source_file( + name = "write_example_project_list", + in_file = ":generate_bazel_files_rule", + out_file = "example_projects.bzl", + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) + +halsim_deps = [ +] + +build_commands() + +build_examples(halsim_deps = halsim_deps) + +build_snippets() + +build_templates() diff --git a/wpilibjExamples/build_java_examples.bzl b/wpilibjExamples/build_java_examples.bzl new file mode 100644 index 0000000000..bc2712c510 --- /dev/null +++ b/wpilibjExamples/build_java_examples.bzl @@ -0,0 +1,71 @@ +load("@rules_java//java:defs.bzl", "java_binary", "java_library") +load("//wpilibjExamples:example_projects.bzl", "COMMANDS_V2_FOLDERS", "EXAMPLES_FOLDERS", "SNIPPETS_FOLDERS", "TEMPLATES_FOLDERS") + +def build_examples(halsim_deps): + for folder in EXAMPLES_FOLDERS: + java_binary( + name = folder + "-example", + srcs = native.glob(["src/main/java/edu/wpi/first/wpilibj/examples/" + folder + "/**/*.java"]), + main_class = "edu/wpi/first/wpilibj/examples/" + folder + "/Main", + plugins = [ + "//epilogue-processor:plugin", + ], + deps = [ + "//apriltag:apriltag-java", + "//cameraserver:cameraserver-java", + "//cscore:cscore-java", + "//hal:hal-java", + "//ntcore:networktables-java", + "//wpimath:wpimath-java", + "//wpilibj:wpilibj", + "//wpilibNewCommands:wpilibNewCommands-java", + "//wpiutil:wpiutil-java", + "//romiVendordep:romi-java", + "//xrpVendordep:xrp-java", + "//wpiunits", + "//epilogue-runtime:epilogue", + "@bzlmodrio-opencv//libraries/java/opencv", + ], + tags = ["wpi-example"], + ) + +def build_commands(): + for folder in COMMANDS_V2_FOLDERS: + java_library( + name = folder + "-command", + srcs = native.glob(["src/main/java/edu/wpi/first/wpilibj/commands/" + folder + "/**/*.java"]), + deps = [ + "//hal:hal-java", + "//wpilibj:wpilibj", + "//wpilibNewCommands:wpilibNewCommands-java", + "//wpimath:wpimath-java", + ], + tags = ["wpi-example"], + ) + +def build_snippets(): + for folder in SNIPPETS_FOLDERS: + java_library( + name = folder + "-snippet", + srcs = native.glob(["src/main/java/edu/wpi/first/wpilibj/snippets/" + folder + "/**/*.java"]), + deps = [ + "//wpilibj:wpilibj", + ], + tags = ["wpi-example"], + ) + +def build_templates(): + for folder in TEMPLATES_FOLDERS: + java_library( + name = folder + "-template", + srcs = native.glob(["src/main/java/edu/wpi/first/wpilibj/templates/" + folder + "/**/*.java"]), + deps = [ + "//hal:hal-java", + "//wpilibj:wpilibj", + "//wpilibNewCommands:wpilibNewCommands-java", + "//wpimath:wpimath-java", + "//wpiutil:wpiutil-java", + "//xrpVendordep:xrp-java", + ], + tags = ["wpi-example"], + ) diff --git a/wpilibjExamples/example_projects.bzl b/wpilibjExamples/example_projects.bzl new file mode 100644 index 0000000000..a1c75816bb --- /dev/null +++ b/wpilibjExamples/example_projects.bzl @@ -0,0 +1,93 @@ +EXAMPLES_FOLDERS = [ + "addressableled", + "apriltagsvision", + "arcadedrive", + "arcadedrivexboxcontroller", + "armsimulation", + "canpdp", + "differentialdrivebot", + "differentialdriveposeestimator", + "digitalcommunication", + "drivedistanceoffboard", + "dutycycleencoder", + "dutycycleinput", + "elevatorexponentialprofile", + "elevatorexponentialsimulation", + "elevatorprofiledpid", + "elevatorsimulation", + "elevatortrapezoidprofile", + "encoder", + "eventloop", + "flywheelbangbangcontroller", + "gettingstarted", + "gyro", + "gyromecanum", + "hatchbotinlined", + "hatchbottraditional", + "hidrumble", + "httpcamera", + "i2ccommunication", + "intermediatevision", + "mecanumbot", + "mecanumcontrollercommand", + "mecanumdrive", + "mecanumdriveposeestimator", + "mechanism2d", + "motorcontrol", + "potentiometerpid", + "quickvision", + "rapidreactcommandbot", + "romireference", + "selectcommand", + "simpledifferentialdrivesimulation", + "solenoid", + "statespacearm", + "statespaceelevator", + "statespaceflywheel", + "statespaceflywheelsysid", + "swervebot", + "swervecontrollercommand", + "swervedriveposeestimator", + "sysidroutine", + "tankdrive", + "tankdrivexboxcontroller", + "unittest", + "xrpreference", +] + +COMMANDS_V2_FOLDERS = [ + "command2", + "emptyclass", + "instantcommand", + "parallelcommandgroup", + "paralleldeadlinegroup", + "parallelracegroup", + "sequentialcommandgroup", + "subsystem2", +] + +SNIPPETS_FOLDERS = [ + "dutycycleencoder", + "encoder", +] + +TEMPLATES_FOLDERS = [ + "commandbased", + "commandbasedskeleton", + "educational", + "robotbaseskeleton", + "romicommandbased", + "romieducational", + "romitimed", + "timed", + "timedskeleton", + "timeslice", + "timesliceskeleton", + "xrpcommandbased", + "xrpeducational", + "xrptimed", +] + +TEST_FOLDERS = [ + "unittest", +] diff --git a/wpilibjExamples/generate_bazel_files.py b/wpilibjExamples/generate_bazel_files.py new file mode 100644 index 0000000000..6254311cb9 --- /dev/null +++ b/wpilibjExamples/generate_bazel_files.py @@ -0,0 +1,68 @@ +import json +import sys + + +def load_foldernames(filename): + output = [] + + with open(filename, "r") as f: + data = json.load(f) + + for test_data in data: + output.append(test_data["foldername"]) + + return sorted(set(output)) + + +def load_tests(filename): + output = [] + + with open(filename, "r") as f: + data = json.load(f) + + for test_data in data: + if test_data.get("hasunittests", False): + output.append(test_data["foldername"]) + + return sorted(set(output)) + + +def main(): + examples = load_foldernames( + "wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json" + ) + commands = load_foldernames( + "wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/commands/commands.json" + ) + templates = load_foldernames( + "wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/templates/templates.json" + ) + snippets = load_foldernames( + "wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/snippets/snippets.json" + ) + tests = load_tests( + "wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/examples.json" + ) + + output_file = "wpilibjExamples/example_projects.bzl" + if len(sys.argv) == 2: + output_file = sys.argv[1] + + with open(output_file, "w") as f: + f.write( + 'EXAMPLES_FOLDERS = [\n "' + '",\n "'.join(examples) + '",\n]\n\n' + ) + f.write( + 'COMMANDS_V2_FOLDERS = [\n "' + '",\n "'.join(commands) + '",\n]\n\n' + ) + f.write( + 'SNIPPETS_FOLDERS = [\n "' + '",\n "'.join(snippets) + '",\n]\n\n' + ) + f.write( + 'TEMPLATES_FOLDERS = [\n "' + '",\n "'.join(templates) + '",\n]\n\n' + ) + f.write('TEST_FOLDERS = [\n "' + '",\n "'.join(tests) + '",\n]\n') + + +if __name__ == "__main__": + main() diff --git a/wpimath/BUILD.bazel b/wpimath/BUILD.bazel index d6763b68de..85e143ff9d 100644 --- a/wpimath/BUILD.bazel +++ b/wpimath/BUILD.bazel @@ -1,8 +1,88 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary") load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library") +load("//wpimath:generate.bzl", "generate_wpimath") + +filegroup( + name = "templates", + srcs = glob(["src/generate/main/java/*.jinja"]), +) + +filegroup( + name = "proto_files", + srcs = glob(["src/main/proto/**/*.proto"]), +) + +py_binary( + name = "generate_nanopb", + srcs = ["generate_nanopb.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +py_binary( + name = "generate_numbers", + srcs = ["generate_numbers.py"], + data = [":templates"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +py_binary( + name = "generate_quickbuf", + srcs = ["generate_quickbuf.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +py_binary( + name = "generate_wpimath_py", + srcs = ["generate_wpimath.py"], + main = "generate_wpimath.py", + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + ":generate_nanopb", + ":generate_numbers", + ":generate_quickbuf", + ], +) + +generate_wpimath( + name = "generate_wpimath", + tags = ["pregeneration"], +) + +write_source_files( + name = "write_wpimath", + files = { + "src/generated": ":generate_wpimath", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) filegroup( name = "generated_java", diff --git a/wpimath/generate.bzl b/wpimath/generate.bzl new file mode 100644 index 0000000000..aed7a26bba --- /dev/null +++ b/wpimath/generate.bzl @@ -0,0 +1,54 @@ +def __generate_wpimath_impl(ctx): + """ + Custom rule used to create the wpimath pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + args.add("--protoc", ctx.executable._protoc) + args.add("--quickbuf_plugin", ctx.executable._quickbuf) + args.add("--nanopb_generator", ctx.executable._nanopb_generator) + + ctx.actions.run( + inputs = ctx.attr._templates.files.to_list() + ctx.attr.proto_files.files.to_list(), + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + tools = [ctx.executable._protoc, ctx.executable._nanopb_generator, ctx.executable._quickbuf], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpimath = rule( + implementation = __generate_wpimath_impl, + attrs = { + "proto_files": attr.label( + allow_files = True, + default = Label("//wpimath:proto_files"), + ), + "_nanopb_generator": attr.label( + default = Label("//wpiutil:nanopb_generator"), + cfg = "exec", + executable = True, + ), + "_protoc": attr.label( + default = Label("@com_google_protobuf//:protoc"), + cfg = "exec", + executable = True, + ), + "_quickbuf": attr.label( + default = Label("//:quickbuf_protoc"), + cfg = "exec", + executable = True, + ), + "_templates": attr.label( + default = Label("//wpimath:templates"), + ), + "_tool": attr.label( + default = Label("//wpimath:generate_wpimath_py"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/wpimath/generate_wpimath.py b/wpimath/generate_wpimath.py new file mode 100644 index 0000000000..2b430eb052 --- /dev/null +++ b/wpimath/generate_wpimath.py @@ -0,0 +1,65 @@ +import argparse +import sys +from pathlib import Path + +from wpimath.generate_nanopb import generate_nanopb +from wpimath.generate_numbers import generate_numbers +from wpimath.generate_quickbuf import generate_quickbuf + + +def main(argv): + script_path = Path(__file__).resolve() + dirname = script_path.parent + + parser = argparse.ArgumentParser() + parser.add_argument( + "--output_directory", + help="Optional. If set, will output the generated files to this directory, otherwise it will use a path relative to the script", + default=dirname / "src/generated", + type=Path, + ) + parser.add_argument( + "--template_root", + help="Optional. If set, will use this directory as the root for the jinja templates", + default=dirname / "src/generate", + type=Path, + ) + parser.add_argument( + "--proto_directory", + help="Optional. If set, will use this directory to glob for protobuf files", + default=dirname / "src/main/proto", + type=Path, + ) + parser.add_argument( + "--protoc", + help="Protoc executable command", + default="protoc", + ) + parser.add_argument( + "--nanopb_generator", + help="Path to the quickbuf protoc plugin", + required=True, + ) + parser.add_argument( + "--quickbuf_plugin", + help="Path to the quickbuf protoc plugin", + required=True, + ) + args = parser.parse_args(argv) + + generate_numbers(args.output_directory, args.template_root) + generate_nanopb( + args.nanopb_generator, + args.output_directory / "main/native/cpp/wpimath/protobuf", + args.proto_directory, + ) + generate_quickbuf( + args.protoc, + args.quickbuf_plugin, + args.output_directory / "main/java", + args.proto_directory, + ) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/wpiunits/BUILD.bazel b/wpiunits/BUILD.bazel index d6609a4f00..d6c360fc83 100644 --- a/wpiunits/BUILD.bazel +++ b/wpiunits/BUILD.bazel @@ -1,5 +1,32 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_java//java:defs.bzl", "java_binary", "java_library") +load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") +load("//wpiunits:generate_wpiunits.bzl", "generate_wpiunits") + +py_binary( + name = "generate_units", + srcs = ["generate_units.py"], + data = glob(["src/generate/main/java/**"]), + tags = ["manual"], + visibility = ["//visibility:public"], + deps = [requirement("jinja2")], +) + +generate_wpiunits( + name = "gen_units", +) + +write_source_files( + name = "write_wpiunits", + files = { + "src/generated": ":gen_units", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) java_library( name = "wpiunits", diff --git a/wpiunits/generate_wpiunits.bzl b/wpiunits/generate_wpiunits.bzl new file mode 100644 index 0000000000..72fdce5218 --- /dev/null +++ b/wpiunits/generate_wpiunits.bzl @@ -0,0 +1,27 @@ +def __generate_wpiunits_impl(ctx): + """ + Custom rule used to create the wpiunits pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + + ctx.actions.run( + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpiunits = rule( + implementation = __generate_wpiunits_impl, + attrs = { + "_tool": attr.label( + default = Label("//wpiunits:generate_units"), + cfg = "exec", + executable = True, + ), + }, +) diff --git a/wpiutil/BUILD.bazel b/wpiutil/BUILD.bazel index 3fcfaecc2b..190d69cb12 100644 --- a/wpiutil/BUILD.bazel +++ b/wpiutil/BUILD.bazel @@ -1,8 +1,60 @@ +load("@allwpilib_pip_deps//:requirements.bzl", "requirement") +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") load("@rules_java//java:defs.bzl", "java_binary") +load("@rules_python//python:defs.bzl", "py_binary") load("//shared/bazel/rules:java_rules.bzl", "wpilib_java_junit5_test") load("//shared/bazel/rules:jni_rules.bzl", "wpilib_jni_cc_library", "wpilib_jni_java_library") load("//shared/bazel/rules/gen:gen-resources.bzl", "generate_resources") +load("//wpiutil:generate.bzl", "generate_wpiutil") + +py_binary( + name = "nanopb_generator", + srcs = glob(["src/main/native/thirdparty/nanopb/generator/**/*.py"]), + data = ["src/main/native/thirdparty/nanopb/generator/proto/nanopb.proto"], + imports = ["."], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + requirement("protobuf"), + requirement("grpcio-tools"), + ], +) + +py_binary( + name = "generate_nanopb", + srcs = ["generate_nanopb.py"], + target_compatible_with = select({ + "@rules_bzlmodrio_toolchains//constraints/is_roborio:roborio": ["@platforms//:incompatible"], + "@rules_bzlmodrio_toolchains//constraints/is_systemcore:systemcore": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], +) + +filegroup( + name = "proto_files", + srcs = glob(["src/test/proto/*.proto"]), +) + +generate_wpiutil( + name = "generate_wpiutil", + proto_files = ":proto_files", +) + +write_source_files( + name = "write_wpiutil", + files = { + "src/generated/test/native/cpp": ":generate_wpiutil", + }, + suggested_update_target = "//:write_all", + tags = ["pregeneration"], + visibility = ["//visibility:public"], +) cc_library( name = "argparse-headers", diff --git a/wpiutil/generate.bzl b/wpiutil/generate.bzl new file mode 100644 index 0000000000..97a1bf0c95 --- /dev/null +++ b/wpiutil/generate.bzl @@ -0,0 +1,39 @@ +def __generate_wpiutil_impl(ctx): + """ + Custom rule used to create the wpiutil pre-generated files. See `./README-Bazel.md` for the reasoning. + """ + output_dir = ctx.actions.declare_directory("_gendir") + + args = ctx.actions.args() + args.add("--output_directory", output_dir.path) + args.add("--nanopb", ctx.executable._nanopb_generator) + + ctx.actions.run( + inputs = ctx.attr.proto_files.files, + outputs = [output_dir], + executable = ctx.executable._tool, + arguments = [args], + tools = [ctx.executable._nanopb_generator], + ) + + return [DefaultInfo(files = depset([output_dir]))] + +generate_wpiutil = rule( + implementation = __generate_wpiutil_impl, + attrs = { + "proto_files": attr.label( + allow_files = True, + mandatory = True, + ), + "_nanopb_generator": attr.label( + default = Label("//wpiutil:nanopb_generator"), + cfg = "exec", + executable = True, + ), + "_tool": attr.label( + default = Label("//wpiutil:generate_nanopb"), + cfg = "exec", + executable = True, + ), + }, +)