diff --git a/examples/small_world/.bazelrc b/examples/small_world/.bazelrc index bb5fabc7..46b0d69f 100644 --- a/examples/small_world/.bazelrc +++ b/examples/small_world/.bazelrc @@ -10,3 +10,5 @@ coverage --combined_report=lcov build:cov_mac --repo_env=GCOV=/Library/Developer/CommandLineTools/usr/bin/llvm-profdata build:cov_mac --test_env=LLVM_COV=/Library/Developer/CommandLineTools/usr/bin/llvm-cov build:cov_mac --copt=-ffile-compilation-dir=. + +build:system-gcc --platforms=@rules_swiftnav//platforms:x86_64_linux_gcc11_system diff --git a/examples/small_world/MODULE.bazel b/examples/small_world/MODULE.bazel index 17db2497..d72bc02d 100644 --- a/examples/small_world/MODULE.bazel +++ b/examples/small_world/MODULE.bazel @@ -20,19 +20,37 @@ use_repo( ) register_toolchains( + # llvm14 "@rules_swiftnav//cc/toolchains/llvm/aarch64-darwin:cc-toolchain-aarch64-darwin", + "@rules_swiftnav//cc/toolchains/llvm/x86_64-linux:cc-toolchain-x86_64-linux", + # llvm20 "@rules_swiftnav//cc/toolchains/llvm20/aarch64-darwin:cc-toolchain-aarch64-darwin", "@rules_swiftnav//cc/toolchains/llvm20/x86_64-darwin:cc-toolchain-x86_64-darwin", "@rules_swiftnav//cc/toolchains/llvm20/aarch64-linux:cc-toolchain-aarch64-linux", "@rules_swiftnav//cc/toolchains/llvm20/x86_64-linux:cc-toolchain-x86_64-linux", + # system gcc + "@rules_swiftnav//cc/toolchains/system_gcc/gcc11_x86_64-linux:system-cc-toolchain-x86_64-linux", ) bazel_dep(name = "googletest", version = "1.16.0", dev_dependency = True) bazel_dep(name = "lcov", version = "2.3.1", dev_dependency = True) +bazel_dep(name = "eigen", version = "5.0.0") + # Register the buildifier toolchain bazel_dep( name = "buildifier_prebuilt", version = "8.2.0.2", dev_dependency = True, ) + +# bazel run @hedron_compile_commands//:refresh_all +# bazel run @hedron_compile_commands//:refresh_all -- --config=system-gcc +bazel_dep(name = "hedron_compile_commands", dev_dependency = True) +git_override( + module_name = "hedron_compile_commands", + commit = "4f28899228fb3ad0126897876f147ca15026151e", + remote = "https://github.com/hedronvision/bazel-compile-commands-extractor.git", + # Replace the commit hash (above) with the latest (https://github.com/hedronvision/bazel-compile-commands-extractor/commits/main). + # Even better, set up Renovate and let it do the work for you (see "Suggestion: Updates" in the README). +) diff --git a/examples/small_world/MODULE.bazel.lock b/examples/small_world/MODULE.bazel.lock index 1a363499..0efe0d47 100644 --- a/examples/small_world/MODULE.bazel.lock +++ b/examples/small_world/MODULE.bazel.lock @@ -42,6 +42,8 @@ "https://bcr.bazel.build/modules/buildifier_prebuilt/8.2.0.2/source.json": "51eb0a4b38aaaeab7fa64361576d616c4d8bfd0f17a0a10184aeab7084d79f8e", "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/eigen/5.0.0/MODULE.bazel": "65aa1b3dfcf3b22bd45150ed4ab5bfade7cdda3ca85735fb466d45386a1722c0", + "https://bcr.bazel.build/modules/eigen/5.0.0/source.json": "954b73ff6d95db6b6f3fed1435cd75db95bab109d83b31fd43ffaacea7e6cd72", "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", @@ -779,7 +781,7 @@ "@@rules_swiftnav+//cc:extensions.bzl%swift_cc_toolchain_extension": { "general": { "bzlTransitiveDigest": "zDwq2yBSEJXdECtks4+trENu8MzrMfkm5FDsxbO1KrE=", - "usagesDigest": "zhynMdOFUVVMdnsmvkEf+0ZpkwApqRyhSbD9DRT+6Vk=", + "usagesDigest": "f0HeWlPNwuIAtqAe+Vv26z6zmEtpRchgfWRCvQ5pK3c=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/examples/small_world/src/base_math/BUILD.bazel b/examples/small_world/src/base_math/BUILD.bazel index 26997028..3a5cd263 100644 --- a/examples/small_world/src/base_math/BUILD.bazel +++ b/examples/small_world/src/base_math/BUILD.bazel @@ -1,18 +1,37 @@ load("@rules_swiftnav//cc:defs.bzl", "UNIT", "swift_cc_library", "swift_cc_test") swift_cc_library( - name = "base_math", - srcs = ["base_math.cc"], - hdrs = ["base_math.hpp"], + name = "add", + srcs = ["add.cc"], + hdrs = ["add.hpp"], + standard = 20, visibility = ["//visibility:public"], ) swift_cc_test( - name = "base_math_test", - srcs = ["base_math_test.cc"], + name = "add_test", + srcs = ["add_test.cc"], type = UNIT, deps = [ - ":base_math", + ":add", + "@googletest//:gtest_main", + ], +) + +swift_cc_library( + name = "sign", + srcs = ["sign.cc"], + hdrs = ["sign.hpp"], + standard = 20, + visibility = ["//visibility:public"], +) + +swift_cc_test( + name = "sign_test", + srcs = ["sign_test.cc"], + type = UNIT, + deps = [ + ":sign", "@googletest//:gtest_main", ], ) diff --git a/examples/small_world/src/base_math/base_math.cc b/examples/small_world/src/base_math/add.cc similarity index 63% rename from examples/small_world/src/base_math/base_math.cc rename to examples/small_world/src/base_math/add.cc index 3c1bbcd3..ee1ee0ef 100644 --- a/examples/small_world/src/base_math/base_math.cc +++ b/examples/small_world/src/base_math/add.cc @@ -1,4 +1,4 @@ -#include "base_math.hpp" +#include "add.hpp" int add(int x, int y) { return x + y; diff --git a/examples/small_world/src/base_math/add.hpp b/examples/small_world/src/base_math/add.hpp new file mode 100644 index 00000000..df16e9f8 --- /dev/null +++ b/examples/small_world/src/base_math/add.hpp @@ -0,0 +1,6 @@ +#ifndef ADD_HPP +#define ADD_HPP + +int add(int x, int y); + +#endif diff --git a/examples/small_world/src/base_math/base_math_test.cc b/examples/small_world/src/base_math/add_test.cc similarity index 52% rename from examples/small_world/src/base_math/base_math_test.cc rename to examples/small_world/src/base_math/add_test.cc index b9269a11..7546abef 100644 --- a/examples/small_world/src/base_math/base_math_test.cc +++ b/examples/small_world/src/base_math/add_test.cc @@ -1,4 +1,4 @@ -#include "base_math.hpp" +#include "add.hpp" #include "gtest/gtest.h" TEST(BaseMathTest, Add) { @@ -6,8 +6,3 @@ TEST(BaseMathTest, Add) { EXPECT_EQ(add(-1, 1), 0); EXPECT_EQ(add(-1, -1), -2); } - -TEST(BaseMathTest, SignPlus) { - EXPECT_EQ(Math::sign(10), 1); - //EXPECT_EQ(Math::sign(-10), -1); -} diff --git a/examples/small_world/src/base_math/sign.cc b/examples/small_world/src/base_math/sign.cc new file mode 100644 index 00000000..c6205808 --- /dev/null +++ b/examples/small_world/src/base_math/sign.cc @@ -0,0 +1,5 @@ +#include "sign.hpp" + +int add(int x, int y) { + return x + y; +} diff --git a/examples/small_world/src/base_math/base_math.hpp b/examples/small_world/src/base_math/sign.hpp similarity index 80% rename from examples/small_world/src/base_math/base_math.hpp rename to examples/small_world/src/base_math/sign.hpp index 0bc83dc5..1034c3f9 100644 --- a/examples/small_world/src/base_math/base_math.hpp +++ b/examples/small_world/src/base_math/sign.hpp @@ -1,5 +1,5 @@ -#ifndef BASE_MATH_HPP -#define BASE_MATH_HPP +#ifndef SIGN_HPP +#define SIGN_HPP int add(int x, int y); diff --git a/examples/small_world/src/base_math/sign_test.cc b/examples/small_world/src/base_math/sign_test.cc new file mode 100644 index 00000000..b8a4eb91 --- /dev/null +++ b/examples/small_world/src/base_math/sign_test.cc @@ -0,0 +1,7 @@ +#include "sign.hpp" +#include "gtest/gtest.h" + +TEST(BaseMathTest, SignPlus) { + EXPECT_EQ(Math::sign(10), 1); + //EXPECT_EQ(Math::sign(-10), -1); +} diff --git a/examples/small_world/src/fibonacci/BUILD.bazel b/examples/small_world/src/fibonacci/BUILD.bazel index 2fc8b617..8910dc15 100644 --- a/examples/small_world/src/fibonacci/BUILD.bazel +++ b/examples/small_world/src/fibonacci/BUILD.bazel @@ -5,7 +5,7 @@ swift_cc_library( srcs = ["fibonacci.cc"], hdrs = ["fibonacci.hpp"], visibility = ["//visibility:public"], - deps = ["//src/base_math"], + deps = ["//src/base_math:add"], ) swift_cc_test( diff --git a/examples/small_world/src/fibonacci/fibonacci.cc b/examples/small_world/src/fibonacci/fibonacci.cc index 05dd138d..df48427e 100644 --- a/examples/small_world/src/fibonacci/fibonacci.cc +++ b/examples/small_world/src/fibonacci/fibonacci.cc @@ -1,5 +1,5 @@ #include "fibonacci.hpp" -#include "src/base_math/base_math.hpp" +#include "src/base_math/add.hpp" int fibonacci(int n) { if (n <= 1) { diff --git a/examples/small_world/src/old_folder_structure/BUILD.bazel b/examples/small_world/src/old_folder_structure/BUILD.bazel index 6cf2fe1a..d985ed22 100644 --- a/examples/small_world/src/old_folder_structure/BUILD.bazel +++ b/examples/small_world/src/old_folder_structure/BUILD.bazel @@ -1,6 +1,6 @@ -load("@rules_swiftnav//cc:defs.bzl", "UNIT", "swift_cc_library", "swift_cc_test") +load("@rules_swiftnav//cc:defs.bzl", "UNIT", "swift_cc_test") -swift_cc_library( +cc_library( name = "old_folder_structure", srcs = ["src/old_folder_structure.cc"], hdrs = ["include/old_folder_structure/old_folder_structure.hpp"], diff --git a/examples/small_world/src/use_external_dep/BUILD.bazel b/examples/small_world/src/use_external_dep/BUILD.bazel new file mode 100644 index 00000000..c1a0487b --- /dev/null +++ b/examples/small_world/src/use_external_dep/BUILD.bazel @@ -0,0 +1,21 @@ +load("@rules_swiftnav//cc:defs.bzl", "UNIT", "swift_cc_library", "swift_cc_test") + +swift_cc_library( + name = "use_external_dep", + srcs = ["use_external_dep.cc"], + hdrs = ["use_external_dep.hpp"], + visibility = ["//visibility:public"], + deps = [ + "@eigen", + ], +) + +swift_cc_test( + name = "use_external_dep_test", + srcs = ["use_external_dep_test.cc"], + type = UNIT, + deps = [ + ":use_external_dep", + "@googletest//:gtest_main", + ], +) diff --git a/examples/small_world/src/use_external_dep/use_external_dep.cc b/examples/small_world/src/use_external_dep/use_external_dep.cc new file mode 100644 index 00000000..4c24cad3 --- /dev/null +++ b/examples/small_world/src/use_external_dep/use_external_dep.cc @@ -0,0 +1,9 @@ +#include "use_external_dep.hpp" + +double compute_dot_product(const Eigen::Vector3d& a, const Eigen::Vector3d& b) { + return a.dot(b); +} + +double compute_magnitude(const Eigen::Vector3d& v) { + return v.norm(); +} diff --git a/examples/small_world/src/use_external_dep/use_external_dep.hpp b/examples/small_world/src/use_external_dep/use_external_dep.hpp new file mode 100644 index 00000000..e5ea1c65 --- /dev/null +++ b/examples/small_world/src/use_external_dep/use_external_dep.hpp @@ -0,0 +1,12 @@ +#ifndef USE_EXTERNAL_DEP_HPP +#define USE_EXTERNAL_DEP_HPP + +#include + +// Compute the dot product of two 3D vectors using Eigen +double compute_dot_product(const Eigen::Vector3d& a, const Eigen::Vector3d& b); + +// Compute the magnitude of a 3D vector using Eigen +double compute_magnitude(const Eigen::Vector3d& v); + +#endif diff --git a/examples/small_world/src/use_external_dep/use_external_dep_test.cc b/examples/small_world/src/use_external_dep/use_external_dep_test.cc new file mode 100644 index 00000000..79408a72 --- /dev/null +++ b/examples/small_world/src/use_external_dep/use_external_dep_test.cc @@ -0,0 +1,32 @@ +#include "use_external_dep.hpp" +#include "gtest/gtest.h" + +TEST(UseExternalDepTest, DotProduct) { + Eigen::Vector3d a(1.0, 2.0, 3.0); + Eigen::Vector3d b(4.0, 5.0, 6.0); + + // Expected dot product: 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32 + EXPECT_DOUBLE_EQ(compute_dot_product(a, b), 32.0); +} + +TEST(UseExternalDepTest, DotProductOrthogonal) { + Eigen::Vector3d a(1.0, 0.0, 0.0); + Eigen::Vector3d b(0.0, 1.0, 0.0); + + // Orthogonal vectors have dot product of 0 + EXPECT_DOUBLE_EQ(compute_dot_product(a, b), 0.0); +} + +TEST(UseExternalDepTest, Magnitude) { + Eigen::Vector3d v(3.0, 4.0, 0.0); + + // Expected magnitude: sqrt(3^2 + 4^2) = sqrt(9 + 16) = sqrt(25) = 5 + EXPECT_DOUBLE_EQ(compute_magnitude(v), 5.0); +} + +TEST(UseExternalDepTest, MagnitudeUnitVector) { + Eigen::Vector3d v(1.0, 0.0, 0.0); + + // Unit vector has magnitude of 1 + EXPECT_DOUBLE_EQ(compute_magnitude(v), 1.0); +} diff --git a/examples/small_world/tools/test_compile_flags.py b/examples/small_world/tools/test_compile_flags.py new file mode 100755 index 00000000..98fe0bfc --- /dev/null +++ b/examples/small_world/tools/test_compile_flags.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +""" +Script to generate compile_commands.json and analyze compile flags for duplicates. +""" + +import argparse +import json +import subprocess +import sys +from collections import Counter + + +def main(): + # Parse command line arguments + parser = argparse.ArgumentParser( + description="Generate compile_commands.json and analyze compile flags" + ) + parser.add_argument( + "filename", + nargs="?", + default="src/base_math/sign.cc", + help="Source file to analyze (default: src/base_math/sign.cc)" + ) + args = parser.parse_args() + + print("Running: bazel run @hedron_compile_commands//:refresh_all") + print("-" * 60) + + # Execute the bazel command + try: + result = subprocess.run( + ["bazel", "run", "@hedron_compile_commands//:refresh_all"], + capture_output=True, + text=True, + check=True + ) + print(result.stdout) + if result.stderr: + print(result.stderr, file=sys.stderr) + except subprocess.CalledProcessError as e: + print(f"Error running bazel command: {e}", file=sys.stderr) + print(e.stderr, file=sys.stderr) + sys.exit(1) + + print("\n" + "=" * 60) + print("Reading compile_commands.json...") + print("=" * 60 + "\n") + + # Read the generated compile_commands.json + try: + with open("compile_commands.json", "r") as f: + compile_commands = json.load(f) + except FileNotFoundError: + print("Error: compile_commands.json not found", file=sys.stderr) + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error parsing compile_commands.json: {e}", file=sys.stderr) + sys.exit(1) + + if not compile_commands: + print("Error: compile_commands.json is empty", file=sys.stderr) + sys.exit(1) + + # Find the entry for the specified file + target_entry = None + for entry in compile_commands: + if entry.get("file", "").endswith(args.filename): + target_entry = entry + break + + if not target_entry: + print(f"Error: No entry found for file '{args.filename}'", file=sys.stderr) + print(f"\nAvailable files:", file=sys.stderr) + for entry in compile_commands[:5]: + print(f" - {entry.get('file', 'N/A')}", file=sys.stderr) + if len(compile_commands) > 5: + print(f" ... and {len(compile_commands) - 5} more", file=sys.stderr) + sys.exit(1) + + print(f"Target file: {target_entry.get('file', 'N/A')}") + print(f"Directory: {target_entry.get('directory', 'N/A')}") + print("\n" + "-" * 60) + print("Compile options from target entry:") + print("-" * 60 + "\n") + + # Parse the command to extract compile options + command = target_entry.get("command", "") + if not command: + # Try 'arguments' field if 'command' is not present + arguments = target_entry.get("arguments", []) + if arguments: + compile_options = [arg for arg in arguments if arg.startswith("-")] + else: + print("Error: No command or arguments found in target entry", file=sys.stderr) + sys.exit(1) + else: + # Split command string and extract options starting with '-' + import shlex + parts = shlex.split(command) + compile_options = [part for part in parts if part.startswith("-")] + + # Display all compile options + for i, option in enumerate(compile_options, 1): + print(f"{i:3d}. {option}") + + print(f"\nTotal compile options: {len(compile_options)}") + + # Check for duplicates + print("\n" + "=" * 60) + print("Checking for duplicate compile options...") + print("=" * 60 + "\n") + + option_counts = Counter(compile_options) + duplicates = {opt: count for opt, count in option_counts.items() if count > 1} + + if duplicates: + print(f"Found {len(duplicates)} duplicate compile option(s):\n") + for option, count in sorted(duplicates.items(), key=lambda x: x[1], reverse=True): + print(f" '{option}' appears {count} times") + else: + print("No duplicate compile options found.") + + # Check for contradicting flags + print("\n" + "=" * 60) + print("Checking for contradicting compile options...") + print("=" * 60 + "\n") + + contradictions_found = False + + # Check for multiple -std= flags + std_flags = [opt for opt in compile_options if opt.startswith("-std=")] + if len(std_flags) > 1: + contradictions_found = True + print(f"Found {len(std_flags)} conflicting C++ standard flags:") + for flag in std_flags: + print(f" {flag}") + print() + + # Check for multiple optimization levels + opt_flags = [opt for opt in compile_options if opt in ["-O0", "-O1", "-O2", "-O3", "-Os", "-Oz", "-Og", "-Ofast"]] + if len(opt_flags) > 1: + contradictions_found = True + print(f"Found {len(opt_flags)} conflicting optimization level flags:") + for flag in opt_flags: + print(f" {flag}") + print() + + # Check for conflicting debug flags + if "-g" in compile_options and "-g0" in compile_options: + contradictions_found = True + print("Found conflicting debug flags:") + print(" -g (enable debug info)") + print(" -g0 (disable debug info)") + print() + + # Check for conflicting warning flags + warning_contradictions = [] + for i, opt1 in enumerate(compile_options): + if opt1.startswith("-W") and not opt1.startswith("-Wl,"): + # Check if there's a negating flag + if opt1.startswith("-Wno-"): + positive_flag = "-W" + opt1[5:] # Remove "no-" to get positive version + if positive_flag in compile_options: + warning_contradictions.append((positive_flag, opt1)) + else: + negative_flag = opt1[:2] + "no-" + opt1[2:] # Add "no-" + if negative_flag in compile_options: + warning_contradictions.append((opt1, negative_flag)) + + # Remove duplicates by converting to set + warning_contradictions = list(set(warning_contradictions)) + + if warning_contradictions: + contradictions_found = True + print(f"Found {len(warning_contradictions)} conflicting warning flag pair(s):") + for pos_flag, neg_flag in warning_contradictions: + print(f" {pos_flag} <-> {neg_flag}") + print() + + if not contradictions_found: + print("No contradicting compile options found.") + + return 0 + + +if __name__ == "__main__": + sys.exit(main())