diff --git a/environment_setup/setup_software.sh b/environment_setup/setup_software.sh index fd94cce9a5..8172472d66 100755 --- a/environment_setup/setup_software.sh +++ b/environment_setup/setup_software.sh @@ -75,7 +75,7 @@ host_software_packages=( libffi-dev # needed to use _ctypes in Python3 libssl-dev # needed to build Python 3 with ssl support openssl # possibly also necessary for ssl in Python 3 - sshpass #used to remotely ssh into robots via Ansible + sshpass # used to remotely ssh into robots via Ansible unzip # installing tigers autoref xvfb # used for CI to run GUI applications ) diff --git a/environment_setup/setup_software_mac.sh b/environment_setup/setup_software_mac.sh index 5a759fa89f..23658ddbfa 100755 --- a/environment_setup/setup_software_mac.sh +++ b/environment_setup/setup_software_mac.sh @@ -32,6 +32,8 @@ host_software_packages=( node@20 go@1.24 clang-format@20 + sshpass # used to remotely ssh into robots via Ansible + messense/macos-cross-toolchains/aarch64-unknown-linux-gnu # raspberry pi cross compiler ) for pkg in "${host_software_packages[@]}"; do @@ -72,9 +74,13 @@ print_status_msg "Install clang-format" install_clang_format $sys print_status_msg "Done installing clang-format" -print_status_msg "Setting up cross compiler for robot software" -install_cross_compiler $sys -print_status_msg "Done setting up cross compiler for robot software" +print_status_msg "Setting Up PlatformIO" +sudo ln -s /opt/tbotspython/bin/platformio /usr/local/bin/platformio +print_status_msg "Done PlatformIO Setup" + +print_status_msg "Setting up STM32 cross-compiler for motor board firmware" +install_stm32_cross_compiler $sys +print_status_msg "Done setting up STM32 cross-compiler" print_status_msg "Setting Up Python Development Headers" install_python_toolchain_headers diff --git a/environment_setup/util.sh b/environment_setup/util.sh index 75359ea10f..8a006f6891 100755 --- a/environment_setup/util.sh +++ b/environment_setup/util.sh @@ -38,23 +38,14 @@ install_clang_format() { install_cross_compiler() { file_name=aarch64-tbots-linux-gnu-for-aarch64 - if is_darwin $1; then - full_file_name=$file_name.tar.xz - curl -L "https://raw.githubusercontent.com/UBC-Thunderbots/Software-External-Dependencies/refs/heads/main/toolchain/$full_file_name" \ - -o /tmp/tbots_download_cache/$full_file_name - tar -xf /tmp/tbots_download_cache/$full_file_name -C /tmp/tbots_download_cache/ - sudo mv /tmp/tbots_download_cache/aarch64-tbots-linux-gnu /opt/tbotspython - rm /tmp/tbots_download_cache/$full_file_name - else - if is_x86 $1; then - file_name=aarch64-tbots-linux-gnu-for-x86 - fi - full_file_name=$file_name.tar.xz - wget https://raw.githubusercontent.com/UBC-Thunderbots/Software-External-Dependencies/refs/heads/main/toolchain/$full_file_name -O /tmp/tbots_download_cache/$full_file_name - tar -xf /tmp/tbots_download_cache/$full_file_name -C /tmp/tbots_download_cache/ - sudo mv /tmp/tbots_download_cache/aarch64-tbots-linux-gnu /opt/tbotspython - rm /tmp/tbots_download_cache/$full_file_name + if is_x86 $1; then + file_name=aarch64-tbots-linux-gnu-for-x86 fi + full_file_name=$file_name.tar.xz + wget https://raw.githubusercontent.com/UBC-Thunderbots/Software-External-Dependencies/refs/heads/main/toolchain/$full_file_name -O /tmp/tbots_download_cache/$full_file_name + tar -xf /tmp/tbots_download_cache/$full_file_name -C /tmp/tbots_download_cache/ + sudo mv /tmp/tbots_download_cache/aarch64-tbots-linux-gnu /opt/tbotspython + rm /tmp/tbots_download_cache/$full_file_name } install_gamecontroller () { @@ -127,14 +118,17 @@ install_python_dev_cross_compile_headers() { install_stm32_cross_compiler() { arch="aarch64" - if is_x86 $1; then + if is_darwin $1; then + arch="darwin-arm64" + elif is_x86 $1; then arch="x86_64" fi - download_link=https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-${arch}-arm-none-eabi.tar.xz + toolchain_name=arm-gnu-toolchain-14.3.rel1-${arch}-arm-none-eabi + download_link=https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/${toolchain_name}.tar.xz wget -N $download_link -O /tmp/tbots_download_cache/arm-gnu-toolchain.tar.xz tar -xf /tmp/tbots_download_cache/arm-gnu-toolchain.tar.xz -C /tmp/tbots_download_cache/ - sudo mv /tmp/tbots_download_cache/arm-gnu-toolchain-14.3.rel1-${arch}-arm-none-eabi /opt/tbotspython/arm-none-eabi-gcc + sudo mv /tmp/tbots_download_cache/${toolchain_name} /opt/tbotspython/arm-none-eabi-gcc rm /tmp/tbots_download_cache/arm-gnu-toolchain.tar.xz } diff --git a/src/MODULE.bazel b/src/MODULE.bazel index 34c2500d42..cf90fb580a 100644 --- a/src/MODULE.bazel +++ b/src/MODULE.bazel @@ -250,6 +250,7 @@ register_toolchains( ) register_toolchains( + "//toolchains/cc:cc_toolchain_for_macos_robot", "//toolchains/cc:cc_toolchain_for_k8_aarch64_linux", "//toolchains/cc:cc_toolchain_for_k8", "//toolchains/cc:cc_toolchain_for_aarch64", @@ -286,6 +287,12 @@ new_local_repository( path = "/opt/tbotspython/aarch64-tbots-linux-gnu/", ) +new_local_repository( + name = "macos_robot_gcc", + build_file = "@//extlibs:macos_robot_gcc.BUILD", + path = "/opt/homebrew/opt/aarch64-unknown-linux-gnu/toolchain/", +) + new_local_repository( name = "motor_board_gcc", build_file = "@//extlibs:motor_board_gcc.BUILD", diff --git a/src/extlibs/macos_robot_gcc.BUILD b/src/extlibs/macos_robot_gcc.BUILD new file mode 100644 index 0000000000..3d70d0b5ea --- /dev/null +++ b/src/extlibs/macos_robot_gcc.BUILD @@ -0,0 +1,6 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "everything", + srcs = glob(["**"]), +) diff --git a/src/software/embedded/BUILD b/src/software/embedded/BUILD index e26612ecd8..fc516010c8 100644 --- a/src/software/embedded/BUILD +++ b/src/software/embedded/BUILD @@ -72,6 +72,8 @@ cc_library( name = "spi_utils", srcs = ["spi_utils.cpp"], hdrs = ["spi_utils.h"], + # Uses Linux kernel headers (linux/spi/spidev.h); robot-only. + target_compatible_with = ["@platforms//os:linux"], deps = [ "//software/logger", ], diff --git a/src/software/embedded/gpio/BUILD b/src/software/embedded/gpio/BUILD index a09031ccf2..b3e02951b0 100644 --- a/src/software/embedded/gpio/BUILD +++ b/src/software/embedded/gpio/BUILD @@ -10,6 +10,8 @@ cc_library( "gpio.h", "gpio_char_dev.h", ], + # Uses Linux kernel headers (linux/gpio.h); robot-only. + target_compatible_with = ["@platforms//os:linux"], deps = [ "//software/logger", "//software/logger:network_logger", diff --git a/src/software/embedded/motor_controller/BUILD b/src/software/embedded/motor_controller/BUILD index 26518edbfd..16c3f1b0ca 100644 --- a/src/software/embedded/motor_controller/BUILD +++ b/src/software/embedded/motor_controller/BUILD @@ -27,6 +27,8 @@ cc_library( "stspin_motor_controller.h", "tmc_motor_controller.h", ], + # Uses Linux kernel headers (linux/spi/spidev.h); robot-only. + target_compatible_with = ["@platforms//os:linux"], deps = [ ":motor_board", ":motor_fault_indicator", diff --git a/src/software/embedded/services/BUILD b/src/software/embedded/services/BUILD index fa9571a16c..ced15431fd 100644 --- a/src/software/embedded/services/BUILD +++ b/src/software/embedded/services/BUILD @@ -42,6 +42,8 @@ cc_library( name = "imu", srcs = ["imu.cpp"], hdrs = ["imu.h"], + # Uses Linux kernel headers (linux/i2c-dev.h); robot-only. + target_compatible_with = ["@platforms//os:linux"], deps = [ "//proto:tbots_cc_proto", "//shared:constants", diff --git a/src/tbots.py b/src/tbots.py index bcebce7ab1..b745d76482 100755 --- a/src/tbots.py +++ b/src/tbots.py @@ -194,7 +194,7 @@ def create_command(config: BuildConfig, extra_args: list[str]) -> list[str]: if config.test_suite and config.action == ActionArgument.test: target = """-- //... \\ -//software/gameplay_tests/... \\ - -//toolchains/cc/... \\ + -//toolchains/... \\ -//software:unix_full_system_tar_gen""" else: target = fuzzy_find_target( @@ -221,6 +221,9 @@ def create_command(config: BuildConfig, extra_args: list[str]) -> list[str]: if condition: command += list(flag.value) + if config.test_suite and config.action == ActionArgument.test: + command += ["--build_tests_only"] + if config.jobs_option: command += [f"--jobs={config.jobs_option}"] diff --git a/src/toolchains/cc/BUILD b/src/toolchains/cc/BUILD index a560ba1276..a71dc2651e 100644 --- a/src/toolchains/cc/BUILD +++ b/src/toolchains/cc/BUILD @@ -269,6 +269,9 @@ cc_toolchain_config_k8_aarch64_linux( toolchain( name = "cc_toolchain_for_k8_aarch64_linux", + exec_compatible_with = [ + "@platforms//os:linux", + ], target_compatible_with = [ "@platforms//cpu:aarch64", "@platforms//os:linux", @@ -278,6 +281,69 @@ toolchain( toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) +MACOS_ROBOT_TC = "/opt/homebrew/opt/aarch64-unknown-linux-gnu/toolchain" + +cc_toolchain_config_k8_aarch64_linux( + name = "gcc_macos_robot", + builtin_include_directories = [ + "/opt/homebrew/opt/aarch64-unknown-linux-gnu", # symlink-reported (libstdc++ headers) + "/opt/homebrew/Cellar/aarch64-unknown-linux-gnu", # realpath-reported (sysroot headers) + ] + make_builtin_include_directories(), + tool_paths = { + "ar": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-ar", + "cpp": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-cpp", + # messense ships no dwp; point at gcc (unused without fission). + "dwp": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-gcc", + "gcc": "wrapper/macos_robot_gcc", + "gcov": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-gcov", + "ld": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-ld", + "nm": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-nm", + "objcopy": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-objcopy", + "objdump": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-objdump", + "strip": MACOS_ROBOT_TC + "/bin/aarch64-unknown-linux-gnu-strip", + }, + toolchain_identifier = "gcc-macos-robot", +) + +filegroup( + name = "macos_robot_everything", + srcs = [ + "wrapper/macos_robot_gcc", + "@macos_robot_gcc//:everything", + ], +) + +cc_toolchain( + name = "cc_toolchain_macos_robot", + all_files = ":macos_robot_everything", + ar_files = ":macos_robot_everything", + as_files = ":macos_robot_everything", + compiler_files = ":macos_robot_everything", + dwp_files = ":macos_robot_everything", + linker_files = ":macos_robot_everything", + objcopy_files = ":macos_robot_everything", + strip_files = ":macos_robot_everything", + supports_param_files = 0, + tags = ["no-ide"], + toolchain_config = ":gcc_macos_robot", + toolchain_identifier = "gcc-macos-robot", +) + +toolchain( + name = "cc_toolchain_for_macos_robot", + exec_compatible_with = [ + "@platforms//os:osx", + "@platforms//cpu:aarch64", + ], + target_compatible_with = [ + "@platforms//cpu:aarch64", + "@platforms//os:linux", + ":glibc_2_27", + ], + toolchain = ":cc_toolchain_macos_robot", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + toolchain( name = "cc_toolchain_for_k8", exec_compatible_with = [ diff --git a/src/toolchains/cc/wrapper/macos_robot_gcc b/src/toolchains/cc/wrapper/macos_robot_gcc new file mode 100755 index 0000000000..b030f6d7ab --- /dev/null +++ b/src/toolchains/cc/wrapper/macos_robot_gcc @@ -0,0 +1,28 @@ +#!/bin/bash --norc + +# Wrapper around the prebuilt messense aarch64-unknown-linux-gnu GCC 15.x, +# applying two robot-deployment fix-ups (both no-ops for compile-only calls): +# +# * Static C++ runtime: this toolchain is GCC 15, newer than the robot's system +# libstdc++, so a dynamic libstdc++ dependency requires GLIBCXX/CXXABI symbol +# versions the robot doesn't have. Bazel passes an explicit `-lstdc++`, which +# `-static-libstdc++` does NOT intercept, so rewrite it to the static archive +# (`-l:libstdc++.a`). `-static-libgcc` covers libgcc. +# +# * `-fuse-ld=bfd`: messense ships only the BFD linker (no ld.gold), but the +# shared cc_toolchain config adds `-fuse-ld=gold`; appending bfd wins. + +# Homebrew's version-independent symlink (kept in sync with MACOS_ROBOT_TC in +# //toolchains/cc:BUILD), so this survives `brew upgrade` of the toolchain. +TC=/opt/homebrew/opt/aarch64-unknown-linux-gnu/toolchain + +args=() +for a in "$@"; do + if [ "$a" = "-lstdc++" ]; then + args+=("-l:libstdc++.a") + else + args+=("$a") + fi +done + +exec "$TC/bin/aarch64-unknown-linux-gnu-gcc" "${args[@]}" -fuse-ld=bfd -static-libgcc