diff --git a/BUILD.bazel b/BUILD.bazel index b44a1f8c09..fe34704d13 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -95,6 +95,7 @@ publish_all( "//sysid:sysid_publish.publish", "//thirdparty/googletest:googletest-cpp_publish.publish", "//thirdparty/imgui_suite:imguiSuite-cpp_publish.publish", + "//wpical:wpical_publish.publish", "//wpigui:wpigui-cpp_publish.publish", "//wpilibNewCommands:wpilibNewCommands-cpp_publish.publish", "//wpilibNewCommands:wpilibNewCommands-java_publish.publish", diff --git a/WORKSPACE b/WORKSPACE index 5f03ec6e13..ddcfe20501 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,4 +1,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file") +load("//thirdparty/ceres:repositories.bzl", "ceres_repositories") + +ceres_repositories() http_archive( name = "bazel_features", diff --git a/shared/bazel/rules/cc_rules.bzl b/shared/bazel/rules/cc_rules.bzl index 408d31182a..13feee97a9 100644 --- a/shared/bazel/rules/cc_rules.bzl +++ b/shared/bazel/rules/cc_rules.bzl @@ -189,6 +189,7 @@ def third_party_cc_lib_helper( include_root, src_root = None, src_excludes = [], + defines = [], visibility = None): """ Helper for src / headers pairs that aren't directly compiled, but rather pulled into a bigger library. @@ -212,6 +213,7 @@ def third_party_cc_lib_helper( include_root + "/**", ]), includes = [include_root], + defines = defines, strip_include_prefix = include_root, visibility = visibility, ) @@ -292,6 +294,7 @@ def wpilib_cc_library( srcs = srcs + [lib + "-srcs" for lib in third_party_libraries], deps = deps + [lib + "-headers" for lib in third_party_libraries + third_party_header_only_libraries], strip_include_prefix = strip_include_prefix, + linkopts = linkopts, **kwargs ) diff --git a/shared/bazel/rules/packaging.bzl b/shared/bazel/rules/packaging.bzl index 03ee1ca14d..932d4dfdb1 100644 --- a/shared/bazel/rules/packaging.bzl +++ b/shared/bazel/rules/packaging.bzl @@ -353,6 +353,7 @@ def package_binary_cc_project( name, maven_group_id, maven_artifact_name, + extra_files = [], architectures = None, renames = None): """Packages the C++ binary targets for a project. @@ -374,7 +375,7 @@ def package_binary_cc_project( srcs = [ ":{}-files".format(name), "//:license_pkg_files", - ], + ] + extra_files, architectures = architectures, ) diff --git a/thirdparty/ceres/BUILD.bazel b/thirdparty/ceres/BUILD.bazel new file mode 100644 index 0000000000..69432af420 --- /dev/null +++ b/thirdparty/ceres/BUILD.bazel @@ -0,0 +1,45 @@ +""" +Ceres Solver files +""" + +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_import( + name = "ceres-impl", + static_library = select({ + "@rules_bzlmodrio_toolchains//conditions:linux_x86_64": "@ceres_linuxx86-64static//:lib", + "@rules_bzlmodrio_toolchains//conditions:linux_x86_64_debug": "@ceres_linuxx86-64staticdebug//:lib", + "@rules_bzlmodrio_toolchains//conditions:osx": "@ceres_osxuniversalstatic//:lib", + "@rules_bzlmodrio_toolchains//conditions:osx_debug": "@ceres_osxuniversalstaticdebug//:lib", + "@rules_bzlmodrio_toolchains//conditions:windows_arm64": "@ceres_windowsarm64static//:lib", + "@rules_bzlmodrio_toolchains//conditions:windows_arm64_debug": "@ceres_windowsarm64staticdebug//:lib", + "@rules_bzlmodrio_toolchains//conditions:windows_x86_64": "@ceres_windowsx86-64static//:lib", + "@rules_bzlmodrio_toolchains//conditions:windows_x86_64_debug": "@ceres_windowsx86-64staticdebug//:lib", + "@rules_bzlmodrio_toolchains//constraints/is_bookworm64:bookworm64": "@ceres_linuxarm64static//:lib", + "@rules_bzlmodrio_toolchains//constraints/is_bookworm64:bookworm64_debug": "@ceres_linuxarm64staticdebug//:lib", + "@rules_bzlmodrio_toolchains//constraints/is_raspibookworm32:raspibookworm32": "@ceres_linuxarm32static//:lib", + "@rules_bzlmodrio_toolchains//constraints/is_raspibookworm32:raspibookworm32_debug": "@ceres_linuxarm32staticdebug//:lib", + "//conditions:default": None, + }), +) + +cc_library( + name = "ceres", + defines = [ + "GLOG_NO_GFLAGS", + "GLOG_USE_GLOG_EXPORT", + ] + select({ + "@platforms//os:windows": ["GLOG_DEPRECATED=__declspec(deprecated)"], + "//conditions:default": ["GLOG_DEPRECATED=[[deprecated]]"], + }), + linkopts = select({ + "@platforms//os:windows": ["dbghelp.lib"], + "//conditions:default": [], + }), + deps = [ + ":ceres-impl", + "@ceres_headers//:headers", + ], +) diff --git a/thirdparty/ceres/repositories.bzl b/thirdparty/ceres/repositories.bzl new file mode 100644 index 0000000000..a39df31411 --- /dev/null +++ b/thirdparty/ceres/repositories.bzl @@ -0,0 +1,60 @@ +""" Starlark file for ceres repository definitions """ + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def ceres_repositories(): + """ Fetches the ceres solver libraries """ + year = "frc2026" + version = "2.2-1" + + http_archive( + name = "ceres_headers", + build_file_content = """ +load(\"@rules_cc//cc:defs.bzl\", \"cc_library\") + +cc_library( + name = \"headers\", + hdrs = glob(["ceres/**", "glog/**", "suitesparse/**", "openblas/**"]), + includes = ["."], + deps = ["@//wpimath:eigen-headers"], + visibility = [\"//visibility:public\"], +) +""", + url = "https://frcmaven.wpi.edu/artifactory/development/edu/wpi/first/thirdparty/" + year + "/ceres/ceres-cpp/" + version + "/ceres-cpp-" + version + "-headers.zip", + integrity = "sha256-ITP1hirOrcna3tyOUQyniUGPw5JeeC8Ffm5scno865w=", + ) + + _LIB_ARTIFACTS = { + "linuxarm32static": ("linux", "**/*.a", "sha256-ptlO1AuEWz84nAZn0fdXDf6fRsfj1EQu+/FR7PQO8Pk="), + "linuxarm32staticdebug": ("linux", "**/*.a", "sha256-1n5wFPsML0HYuOodbiDTT4taxo5k/IC7to7YBPQtM1Q="), + "linuxarm64static": ("linux", "**/*.a", "sha256-sBoNq7nTyllKJnOvyNm+IAxnKi8wP3YymaMwK2m8qCw="), + "linuxarm64staticdebug": ("linux", "**/*.a", "sha256-44RmHzCSx8rptaaP3DC2IbTy4p61oAHzfzvomCALk6I="), + "linuxx86-64static": ("linux", "**/*.a", "sha256-ntuu0fS01f/vkL4rMaYEuUaDvuYqQwwqLKcQy6yJwd8="), + "linuxx86-64staticdebug": ("linux", "**/*.a", "sha256-2CmV1Z+gM3AKq/+rC9WSn8Gkx/OXLnVMjHlGT1kmB/c="), + "osxuniversalstatic": ("osx", "**/*.a", "sha256-ExnU2z+kGU0iaYRmOpcPCLWdwIDKhVpQnN2g6iJ/z/U="), + "osxuniversalstaticdebug": ("osx", "**/*.a", "sha256-dnqxm5qgVBKD43ORCIkYH+mXi7oQQKbCTWDY1GdTNfQ="), + "windowsarm64static": ("windows", "**/*.lib", "sha256-obWGoORklu5g//x7CmykDX4S4g7ixy9RECdui5zy28g="), + "windowsarm64staticdebug": ("windows", "**/*.lib", "sha256-iL/rdZ2i+9+48IxQEK3Ty8/zQkp/1h9halDG9YEEXz0="), + "windowsx86-64static": ("windows", "**/*.lib", "sha256-wPhWBdyEC3AK6KgUgbvJsxWODGPSUMbAZmdEE7zSJ9Y="), + "windowsx86-64staticdebug": ("windows", "**/*.lib", "sha256-ibozSdLVUEYAuECwKtTKrqZB5pNFdajktwF2TEw+aDg="), + } + + for artifact, (prefix, glob_pattern, integrity) in _LIB_ARTIFACTS.items(): + repo_name = "ceres_" + artifact + build_file_content = """ +filegroup( + name = \"lib\", + srcs = glob([\"%s\"]), + visibility = [\"//visibility:public\"], +) +""" % glob_pattern + + url_fname = "ceres-cpp-" + version + "-" + artifact + ".zip" + + http_archive( + name = repo_name, + build_file_content = build_file_content, + strip_prefix = prefix, + url = "https://frcmaven.wpi.edu/artifactory/development/edu/wpi/first/thirdparty/" + year + "/ceres/ceres-cpp/" + version + "/" + url_fname, + integrity = integrity, + ) diff --git a/wpical/BUILD.bazel b/wpical/BUILD.bazel new file mode 100644 index 0000000000..753cb4b14e --- /dev/null +++ b/wpical/BUILD.bazel @@ -0,0 +1,247 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_cc//cc:cc_test.bzl", "cc_test") +load("@rules_pkg//:mappings.bzl", "pkg_files") +load("//shared/bazel/rules:cc_rules.bzl", "wpilib_cc_library") +load("//shared/bazel/rules:packaging.bzl", "package_binary_cc_project") +load("//shared/bazel/rules/gen:gen-resources.bzl", "generate_resources") +load("//shared/bazel/rules/gen:gen-version-file.bzl", "generate_version_file") + +pkg_files( + name = "licenses", + srcs = [ + "WPICalThirdPartyNotices.txt", + ], +) + +generate_resources( + name = "generate-resources", + namespace = "wpical", + prefix = "WPI", + resource_files = glob(["src/main/native/resources/*"]), +) + +generate_version_file( + name = "generate-version", + output_file = "WPILibVersion.cpp", + template = "src/main/generate/WPILibVersion.cpp.in", +) + +cc_library( + name = "headers", + hdrs = glob([ + "src/main/native/include/**/*", + ]), + strip_include_prefix = "src/main/native/include", + deps = [ + ":headers-libdogleg", + ":headers-mrcal", + ":headers-mrcal-generated", + ":headers-mrcal-java", + ], +) + +cc_library( + name = "headers-libdogleg", + hdrs = glob([ + "src/main/native/thirdparty/libdogleg/include/**/*", + ]), + strip_include_prefix = "src/main/native/thirdparty/libdogleg/include", +) + +cc_library( + name = "headers-mrcal-generated", + hdrs = glob([ + "src/main/native/thirdparty/mrcal/generated/**/*", + ]), + strip_include_prefix = "src/main/native/thirdparty/mrcal/generated/", +) + +cc_library( + name = "headers-mrcal", + hdrs = glob([ + "src/main/native/thirdparty/mrcal/include/**/*", + ]), + strip_include_prefix = "src/main/native/thirdparty/mrcal/include/", +) + +cc_library( + name = "headers-mrcal-java", + hdrs = glob([ + "src/main/native/thirdparty/mrcal_java/include/**/*", + ]), + strip_include_prefix = "src/main/native/thirdparty/mrcal_java/include/", +) + +unix_copts = [ + "-Wno-pedantic", + "-Wno-format-nonliteral", + "-Wno-unused-variable", + "-Wno-unused-function", + "-Wno-sign-compare", +] + +osx_copts = unix_copts + +copts = select({ + "@platforms//os:linux": unix_copts + [ + "-Wno-maybe-uninitialized", + ], + "@platforms//os:osx": osx_copts, + "@platforms//os:windows": [ + "/wd4047", + "/wd4098", + "/wd4267", + ], +}) + +unix_cxxopts = [ + "-Wno-missing-field-initializers", + "-Wno-pedantic", + "-fpermissive", + "-Wno-deprecated-declarations", + "-Wno-return-type", + "-Wno-missing-braces", + "-Wno-null-conversion", + "-Wno-unused-but-set-variable", +] + +osx_cxxopts = unix_cxxopts + [ + "-Wno-unused-variable", + "-Wno-unused-function", + "-Wno-sign-compare", + "-Wno-sometimes-uninitialized", +] + +cxxopts = select({ + "@platforms//os:linux": unix_cxxopts + [ + "-Wno-deprecated-enum-enum-conversion", + ], + "@platforms//os:osx": osx_cxxopts, + "@platforms//os:windows": [ + "/wd4068", + "/wd4101", + "/wd4200", + "/wd4576", + "/wd4715", + ], +}) + +mac_linkopts = [ + "-framework", + "Metal", + "-framework", + "MetalKit", + "-framework", + "Cocoa", + "-framework", + "IOKit", + "-framework", + "CoreFoundation", + "-framework", + "CoreVideo", + "-framework", + "QuartzCore", + "-framework", + "Accelerate", + "-framework", + "AVFoundation", + "-framework", + "CoreMedia", +] + +linkopts = select({ + "@platforms//os:linux": [], + "@platforms//os:osx": mac_linkopts, + "@platforms//os:windows": [ + "-DEFAULTLIB:Gdi32.lib", + "-DEFAULTLIB:Shell32.lib", + "-DEFAULTLIB:d3d11.lib", + "-DEFAULTLIB:d3dcompiler.lib", + "-DEFAULTLIB:Comdlg32.lib", + "-DEFAULTLIB:dbghelp.lib", + "-DEFAULTLIB:Advapi32.lib", + ], +}) + +wpilib_cc_library( + name = "wpical_lib", + srcs = glob( + [ + "src/main/native/cpp/**/*.cpp", + "src/main/native/thirdparty/libdogleg/src/**/*.cpp", + "src/main/native/thirdparty/mrcal/src/**/*.cpp", + "src/main/native/thirdparty/mrcal/src/**/*.c", + "src/main/native/thirdparty/mrcal_java/src/**/*.cpp", + ], + exclude = ["src/main/native/cpp/WPIcal.cpp"], + ) + [ + ":generate-resources", + ], + copts = copts, + cxxopts = cxxopts, + defines = ["OPENCV_DISABLE_EIGEN_TENSOR_SUPPORT"], + include_license_files = True, + linkopts = linkopts, + linkstatic = True, + strip_include_prefix = "include", + visibility = ["//visibility:public"], + deps = [ + ":headers", + "//apriltag", + "//thirdparty/ceres", + "//wpigui", + "//wpiutil", + "@bzlmodrio-opencv//libraries/cpp/opencv", + ], +) + +cc_binary( + name = "wpical", + srcs = [ + "src/main/native/cpp/WPIcal.cpp", + ], + copts = copts, + cxxopts = cxxopts, + linkopts = select({ + "@platforms//os:linux": [], + "@platforms//os:osx": [], + "@platforms//os:windows": [ + "-SUBSYSTEM:WINDOWS", + ], + }), + deps = [ + ":wpical_lib", + "//thirdparty/imgui_suite", + ], +) + +cc_test( + name = "wpical_test", + size = "medium", + srcs = glob(["src/test/native/**"]), + copts = copts, + cxxopts = cxxopts, + data = glob(["src/main/native/assets/**"]) + [ + "src/main/native/assets", + "src/main/native/assets/altfieldvideo", + "src/main/native/assets/fieldvideo", + ], + defines = [ + 'PROJECT_ROOT_PATH=\\"wpical/src/main/native/assets\\"', + "__BAZEL__=1", + ], + deps = [ + ":wpical_lib", + "//thirdparty/ceres", + "//thirdparty/googletest", + "@bazel_tools//tools/cpp/runfiles", + ], +) + +package_binary_cc_project( + name = "wpical", + extra_files = [":licenses"], + maven_artifact_name = "wpical", + maven_group_id = "edu.wpi.first.tools", +) diff --git a/wpical/src/test/native/cpp/bazel_path_lookup.cpp b/wpical/src/test/native/cpp/bazel_path_lookup.cpp new file mode 100644 index 0000000000..b36a3e2325 --- /dev/null +++ b/wpical/src/test/native/cpp/bazel_path_lookup.cpp @@ -0,0 +1,20 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#include +#include + +#ifdef __BAZEL__ +#include "tools/cpp/runfiles/runfiles.h" +using bazel::tools::cpp::runfiles::Runfiles; +std::string LookupPath(std::string path) { + std::string error; + std::unique_ptr runfiles(Runfiles::CreateForTest(&error)); + return runfiles->Rlocation("__main__/" + path); +} +#else +std::string LookupPath(std::string path) { + return path; +} +#endif diff --git a/wpical/src/test/native/cpp/path_lookup.h b/wpical/src/test/native/cpp/path_lookup.h new file mode 100644 index 0000000000..1c9dd5d8cf --- /dev/null +++ b/wpical/src/test/native/cpp/path_lookup.h @@ -0,0 +1,9 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +#pragma once + +#include + +std::string LookupPath(std::string path); diff --git a/wpical/src/test/native/cpp/test_calibrate.cpp b/wpical/src/test/native/cpp/test_calibrate.cpp index a7837e7e17..d82fdb57d7 100644 --- a/wpical/src/test/native/cpp/test_calibrate.cpp +++ b/wpical/src/test/native/cpp/test_calibrate.cpp @@ -10,10 +10,18 @@ #include #include +#include "path_lookup.h" + const std::string projectRootPath = PROJECT_ROOT_PATH; + +const char* const tmpdir_c_str = std::getenv("TEST_TMPDIR"); + const std::string calSavePath = - projectRootPath.substr(0, projectRootPath.find("/src/main/native/assets")) + - "/build"; + tmpdir_c_str == nullptr + ? (projectRootPath.substr( + 0, projectRootPath.find("/src/main/native/assets")) + + "/build") + : std::string(tmpdir_c_str); cameracalibration::CameraModel cameraModel = { .intrinsic_matrix = Eigen::Matrix::Identity(), .distortion_coefficients = Eigen::Matrix::Zero(), @@ -28,10 +36,11 @@ const std::string videoLocation = "/altfieldvideo"; const std::string fileSuffix = ".mp4"; const std::string videoLocation = "/fieldvideo"; #endif + TEST(Camera_CalibrationTest, OpenCV_Typical) { int ret = cameracalibration::calibrate( - projectRootPath + "/testcalibration" + fileSuffix, cameraModel, 0.709f, - 0.551f, 12, 8, false); + LookupPath(projectRootPath + "/testcalibration" + fileSuffix), + cameraModel, 0.709f, 0.551f, 12, 8, false); cameracalibration::dumpJson(cameraModel, calSavePath + "/cameracalibration.json"); EXPECT_EQ(ret, 0); @@ -39,44 +48,44 @@ TEST(Camera_CalibrationTest, OpenCV_Typical) { TEST(Camera_CalibrationTest, OpenCV_Atypical) { int ret = cameracalibration::calibrate( - projectRootPath + videoLocation + "/long" + fileSuffix, cameraModel, - 0.709f, 0.551f, 12, 8, false); + LookupPath(projectRootPath + videoLocation + "/long" + fileSuffix), + cameraModel, 0.709f, 0.551f, 12, 8, false); EXPECT_EQ(ret, 1); } TEST(Camera_CalibrationTest, MRcal_Typical) { int ret = cameracalibration::calibrate( - projectRootPath + "/testcalibration" + fileSuffix, cameraModel, .709f, 12, - 8, 1080, 1920, false); + LookupPath(projectRootPath + "/testcalibration" + fileSuffix), + cameraModel, .709f, 12, 8, 1080, 1920, false); EXPECT_EQ(ret, 0); } TEST(Camera_CalibrationTest, MRcal_Atypical) { int ret = cameracalibration::calibrate( - projectRootPath + videoLocation + "/short" + fileSuffix, cameraModel, - 0.709f, 12, 8, 1080, 1920, false); + LookupPath(projectRootPath + videoLocation + "/short" + fileSuffix), + cameraModel, 0.709f, 12, 8, 1080, 1920, false); EXPECT_EQ(ret, 1); } TEST(Field_CalibrationTest, Typical) { int ret = fieldcalibration::calibrate( - projectRootPath + videoLocation, output_json, + LookupPath(projectRootPath + videoLocation), output_json, calSavePath + "/cameracalibration.json", - projectRootPath + "/2024-crescendo.json", 3, false); + LookupPath(projectRootPath + "/2024-crescendo.json"), 3, false); EXPECT_EQ(ret, 0); } TEST(Field_CalibrationTest, Atypical_Bad_Camera_Model_Directory) { int ret = fieldcalibration::calibrate( - projectRootPath + videoLocation, output_json, - projectRootPath + videoLocation + "/long" + fileSuffix, - projectRootPath + "/2024-crescendo.json", 3, false); + LookupPath(projectRootPath + videoLocation), output_json, + LookupPath(projectRootPath + videoLocation + "/long" + fileSuffix), + LookupPath(projectRootPath + "/2024-crescendo.json"), 3, false); EXPECT_EQ(ret, 1); } TEST(Field_CalibrationTest, Atypical_Bad_Ideal_JSON) { int ret = fieldcalibration::calibrate( - projectRootPath + videoLocation, output_json, + LookupPath(projectRootPath + videoLocation), output_json, calSavePath + "/cameracalibration.json", calSavePath + "/cameracalibration.json", 3, false); EXPECT_EQ(ret, 1); @@ -84,24 +93,24 @@ TEST(Field_CalibrationTest, Atypical_Bad_Ideal_JSON) { TEST(Field_CalibrationTest, Atypical_Bad_Input_Directory) { int ret = fieldcalibration::calibrate( - projectRootPath + "", output_json, + LookupPath(projectRootPath + ""), output_json, calSavePath + "/cameracalibration.json", - projectRootPath + "/2024-crescendo.json", 3, false); + LookupPath(projectRootPath + "/2024-crescendo.json"), 3, false); EXPECT_EQ(ret, 1); } TEST(Field_CalibrationTest, Atypical_Bad_Pinned_Tag) { int ret = fieldcalibration::calibrate( - projectRootPath + videoLocation, output_json, + LookupPath(projectRootPath + videoLocation), output_json, calSavePath + "/cameracalibration.json", - projectRootPath + "/2024-crescendo.json", 42, false); + LookupPath(projectRootPath + "/2024-crescendo.json"), 42, false); EXPECT_EQ(ret, 1); } TEST(Field_CalibrationTest, Atypical_Bad_Pinned_Tag_Negative) { int ret = fieldcalibration::calibrate( - projectRootPath + videoLocation, output_json, + LookupPath(projectRootPath + videoLocation), output_json, calSavePath + "/cameracalibration.json", - projectRootPath + "/2024-crescendo.json", -1, false); + LookupPath(projectRootPath + "/2024-crescendo.json"), -1, false); EXPECT_EQ(ret, 1); } diff --git a/wpical/src/test/native/cpp/test_result_is_exact.cpp b/wpical/src/test/native/cpp/test_result_is_exact.cpp index 8ff313fe59..4945ee69a5 100644 --- a/wpical/src/test/native/cpp/test_result_is_exact.cpp +++ b/wpical/src/test/native/cpp/test_result_is_exact.cpp @@ -13,6 +13,8 @@ #include #include +#include "path_lookup.h" + using namespace cv; struct cmpByFilename { @@ -147,8 +149,9 @@ std::vector calibrate(const std::string& fname, cv::Size boardSize, const std::string projectRootPath = PROJECT_ROOT_PATH; TEST(MrcalResultExactlyMatchesTest, lifecam_1280) { - auto calculated_intrinsics{calibrate( - projectRootPath + "/lifecam_1280p_10x10.vnl", {10, 10}, {1280, 720})}; + auto calculated_intrinsics{ + calibrate(LookupPath(projectRootPath + "/lifecam_1280p_10x10.vnl"), + {10, 10}, {1280, 720})}; // ## generated with mrgingham --jobs 4 --gridn 10 // /home/mmorley/photonvision/test-resources/calibrationSquaresImg/lifecam/2024-01-02_lifecam_1280/*.png diff --git a/wpimath/BUILD.bazel b/wpimath/BUILD.bazel index 92a37f6e36..9731c7b0f1 100644 --- a/wpimath/BUILD.bazel +++ b/wpimath/BUILD.bazel @@ -102,6 +102,7 @@ filegroup( third_party_cc_lib_helper( name = "eigen", include_root = "src/main/native/thirdparty/eigen/include", + visibility = ["//visibility:public"], ) third_party_cc_lib_helper(