From e3db55dc0c9faeb7b467cd28a74e6634ff63f1f0 Mon Sep 17 00:00:00 2001
From: Sergey Fedorov <barracuda@macos-powerpc.org>
Date: Wed, 29 Jul 2026 12:07:58 +0000
Subject: [PATCH 2/2] Use OpenSSL for content hashing on macOS; make Rust and
 eden deps saner

Three build portability fixes, primarily for older/unusual macOS targets
(e.g. powerpc-darwin) where cargo does not exist:

- ContentHash: drop the CommonCrypto path on macOS and use OpenSSL's EVP
  interface on all posix systems.  The dependency stack (folly and
  friends) already links OpenSSL, and EVP avoids the SHA1_* functions
  that OpenSSL 3 deprecates.  OpenSSL is now REQUIRED on non-Windows;
  Windows keeps the built-in crypt provider API.
- Make the Rust components optional: the watchman binary is pure C++ and
  fully functional without the watchmanctl CLI.  RustStaticLibrary
  demands cargo at include time, so probe for cargo first and skip both
  the include and watchman/cli when it is absent.
- Move find_package(FBThrift) / find_package(fb303) out of the
  ENABLE_EDEN_SUPPORT block: edencommon_telemetry links against both and
  edencommon's package config does not chain its dependencies, so a
  build with -DENABLE_EDEN_SUPPORT=OFF previously failed at configure
  time with undefined imported targets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ECmTd2wkJqqrArR8VHCDm
---
 CMakeLists.txt           | 33 +++++++++++++++++++++++++++------
 watchman/ContentHash.cpp | 33 ++++++++++++++++++++++++---------
 2 files changed, 51 insertions(+), 15 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 33a71ef..b7411da 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -150,7 +150,16 @@ include(CheckFunctionExists)
 include(CheckIncludeFiles)
 include(CheckStructHasMember)
 include(CheckSymbolExists)
-include(RustStaticLibrary)
+# The Rust components (the watchmanctl CLI) are optional: the watchman
+# binary itself is pure C++ and fully functional without them.  Note that
+# RustStaticLibrary requires cargo at include time, so only pull it in
+# when cargo is available.
+find_program(CARGO_COMMAND cargo)
+if(CARGO_COMMAND)
+  include(RustStaticLibrary)
+else()
+  message(STATUS "cargo not found: skipping Rust components (watchmanctl)")
+endif()
 
 # configure_file wants us to define a separate file.  I'd rather not
 # have boilerplate for the same thing in two difference files, so we
@@ -324,7 +333,13 @@ if(THREADS_FOUND AND NOT TARGET Threads::Threads)
   endif()
 endif()
 
-find_package(OpenSSL)
+if(WIN32)
+  # Windows uses the built-in crypt provider API instead
+  find_package(OpenSSL)
+else()
+  # ContentHash requires OpenSSL on all posix systems, including macOS
+  find_package(OpenSSL REQUIRED)
+endif()
 
 # This block is for cmake 3.0 which doesn't define the OpenSSL::Crypto
 # interface section.  Test for that and define it for ourselves.
@@ -369,13 +384,17 @@ find_package(edencommon CONFIG REQUIRED)
 find_package(fmt CONFIG REQUIRED)
 find_package(folly CONFIG REQUIRED)
 
+# edencommon_telemetry links against fb303 and thrift, and edencommon's
+# package config does not chain its dependencies, so these are required
+# even when eden support is disabled.
+find_package(FBThrift CONFIG REQUIRED)
+find_package(fb303 CONFIG REQUIRED)
+include_directories(${FB303_INCLUDE_DIR})
+
 if (ENABLE_EDEN_SUPPORT)
   find_package(fizz CONFIG REQUIRED)
   find_package(wangle CONFIG REQUIRED)
-  find_package(FBThrift CONFIG REQUIRED)
-  find_package(fb303 CONFIG REQUIRED)
   find_package(cpptoml CONFIG REQUIRED)
-  include_directories(${FB303_INCLUDE_DIR})
 endif()
 if(DEFINED ENV{NODE_BIN})
   set(NODE $ENV{NODE_BIN})
@@ -763,7 +782,9 @@ endif()
 
 install(TARGETS watchman RUNTIME DESTINATION bin)
 
-add_subdirectory(watchman/cli)
+if(CARGO_COMMAND)
+  add_subdirectory(watchman/cli)
+endif()
 
 set(tests)
 # Helper function to define a unit test executable
diff --git a/watchman/ContentHash.cpp b/watchman/ContentHash.cpp
index cdecf02..bbd416d 100644
--- a/watchman/ContentHash.cpp
+++ b/watchman/ContentHash.cpp
@@ -15,13 +15,10 @@
 #include "watchman/fs/FileSystem.h"
 #include "watchman/watchman_stream.h"
 
-#ifdef __APPLE__
-#define COMMON_DIGEST_FOR_OPENSSL
-#include "CommonCrypto/CommonDigest.h" // @manual
-#elif defined(_WIN32)
+#ifdef _WIN32
 #include <Wincrypt.h> // @manual
 #else
-#include <openssl/sha.h>
+#include <openssl/evp.h>
 #endif
 
 namespace watchman {
@@ -66,8 +63,21 @@ HashValue ContentHashCache::computeHashImmediate(const char* fullPath) {
   }
 
 #ifndef _WIN32
-  SHA_CTX ctx;
-  SHA1_Init(&ctx);
+  // Use OpenSSL's EVP interface on all posix systems, including macOS:
+  // the rest of the dependency stack (folly and friends) already links
+  // OpenSSL, and the low-level SHA1_* functions are deprecated in
+  // OpenSSL 3.
+  auto* ctx = EVP_MD_CTX_new();
+  if (!ctx) {
+    throw std::runtime_error("EVP_MD_CTX_new failed");
+  }
+  SCOPE_EXIT {
+    EVP_MD_CTX_free(ctx);
+  };
+
+  if (EVP_DigestInit_ex(ctx, EVP_sha1(), nullptr) != 1) {
+    throw std::runtime_error("EVP_DigestInit_ex failed");
+  }
 
   while (true) {
     auto n = stm->read(buf, sizeof(buf));
@@ -80,10 +90,15 @@ HashValue ContentHashCache::computeHashImmediate(const char* fullPath) {
           std::generic_category(),
           fmt::format("while reading from {}", fullPath));
     }
-    SHA1_Update(&ctx, buf, n);
+    if (EVP_DigestUpdate(ctx, buf, n) != 1) {
+      throw std::runtime_error("EVP_DigestUpdate failed");
+    }
   }
 
-  SHA1_Final(result.data(), &ctx);
+  unsigned int digestLen = result.size();
+  if (EVP_DigestFinal_ex(ctx, result.data(), &digestLen) != 1) {
+    throw std::runtime_error("EVP_DigestFinal_ex failed");
+  }
 #else
   // Use the built-in crypt provider API on windows to avoid introducing a
   // dependency on openssl in the windows build.
-- 
2.43.0

