Skip to content
139 changes: 124 additions & 15 deletions Formula/jank-git.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Jank < Formula
class JankGit < Formula
desc "The native Clojure dialect hosted on LLVM with seamless C++ interop."
homepage "https://jank-lang.org"
url "https://github.com/jank-lang/jank.git", branch: "main"
Expand All @@ -11,34 +11,143 @@ class Jank < Formula

depends_on "boost"
depends_on "libzip"
depends_on "llvm@21"
depends_on "llvm"
depends_on "openssl"

skip_clean "bin/jank"

def install
ENV.prepend_path "PATH", Formula["llvm@21"].opt_bin
# Clear Nix-provided compiler flags that point to old SDK (11.3)
# This is critical when building on systems with Nix installed
# These variables interfere with proper SDK and libc++ header resolution
ENV.delete("NIX_CFLAGS_COMPILE")
ENV.delete("NIX_LDFLAGS")
ENV.delete("NIX_APPLE_SDK_VERSION")
ENV.delete("MACOSX_DEPLOYMENT_TARGET")
ENV.delete("SDKROOT") # Clear Nix's SDKROOT pointing to old SDK

ENV.append "LDFLAGS", "-Wl,-rpath,#{Formula["llvm@21"].opt_lib}"

ENV.append "CPPFLAGS", "-L#{Formula["llvm@21"].opt_include}"
ENV.append "CPPFLAGS", "-fno-sized-deallocation"
# Use Homebrew's LLVM (not system clang, not Nix clang)
llvm = Formula["llvm"]
ENV.prepend_path "PATH", llvm.opt_bin
ENV["CC"] = llvm.opt_bin/"clang"
ENV["CXX"] = llvm.opt_bin/"clang++"

# Use the full Xcode SDK for macOS headers/frameworks (not CommandLineTools)
# Homebrew's MacOS.sdk_path returns the CLT SDK, so query xcrun directly.
if OS.mac?
ENV["SDKROOT"] = MacOS.sdk_path
else
ENV["CC"] = Formula["llvm@21"].opt_bin/"clang"
ENV["CXX"] = Formula["llvm@21"].opt_bin/"clang++"
sdk = Utils.safe_popen_read("/usr/bin/xcrun", "--sdk", "macosx", "--show-sdk-path").strip
developer_dir = Utils.safe_popen_read("/usr/bin/xcode-select", "--print-path").strip

ENV["SDKROOT"] = sdk
ENV["HOMEBREW_SDKROOT"] = sdk
ENV["DEVELOPER_DIR"] = developer_dir

# Patch CMakeLists so the generated JIT flags don't bake CommandLineTools paths.
inreplace "compiler+runtime/CMakeLists.txt" do |s|
s.sub!(
"separate_arguments(clang_system_include_dirs)\n\nset(clang_system_include_flags \"\")",
<<~'CMAKE'.chomp
separate_arguments(clang_system_include_dirs)

if(APPLE)
set(_adjusted_dirs "")
foreach(dir ${clang_system_include_dirs})
if(dir MATCHES "/SDKs/")
# Skip SDK include paths; clang will find them via -isysroot.
else()
list(APPEND _adjusted_dirs "${dir}")
endif()
endforeach()
set(clang_system_include_dirs "${_adjusted_dirs}")
endif()

set(clang_system_include_flags "")
CMAKE
)
s.sub!(
"foreach(lib ${jank_lib_link_dirs_prop})\n list(APPEND jank_lib_linker_flags_list -L${lib})\nendforeach()",
<<~'CMAKE'.chomp
foreach(lib ${jank_lib_link_dirs_prop})
if(lib STREQUAL "/lib" OR lib STREQUAL "/usr/lib" OR lib STREQUAL "")
# Skip system defaults; clang will find them via the SDK automatically.
else()
list(APPEND jank_lib_linker_flags_list -L${lib})
endif()
endforeach()
CMAKE
)
s.sub!(
"if (NOT jank_local_clang)\n list(APPEND jank_linker_flags -L/opt/homebrew/opt/llvm/lib -L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib/unwind)\nendif ()",
<<~'CMAKE'.chomp
if (NOT jank_local_clang)
list(APPEND jank_linker_flags -L/opt/homebrew/opt/llvm/lib -L/opt/homebrew/opt/llvm/lib/c++)
endif ()

if(APPLE AND DEFINED ENV{SDKROOT})
list(APPEND jank_linker_flags "-isysroot" "$ENV{SDKROOT}")
list(APPEND jank_linker_flags "-L$ENV{SDKROOT}/usr/lib")
endif()
CMAKE
)
end

inreplace "compiler+runtime/src/cpp/jank/aot/processor.cpp" do |s|
s.sub!(
" \"-lm\",\n \"-lstdc++\",",
<<~'CPP'.chomp
"-lm",
#if !defined(__APPLE__)
"-lstdc++",
#endif
CPP
)
end
end

# Critical: Ensure Homebrew LLVM's libc++ headers come BEFORE SDK C headers
# Use -isystem for libc++ to prioritize it, -I for other LLVM includes
llvm_include = llvm.opt_include
llvm_lib = llvm.opt_lib

# Build flags with proper header search order
ENV["CPPFLAGS"] = "-isystem #{llvm_include}/c++/v1 -I#{llvm_include} -fno-sized-deallocation"
ENV["CXXFLAGS"] = "-isystem #{llvm_include}/c++/v1"
ENV["LDFLAGS"] = "-L#{llvm_lib} -Wl,-rpath,#{llvm_lib}"

cd "compiler+runtime"

system "./bin/configure",
"-GNinja",
*std_cmake_args,
"-DHOMEBREW_ALLOW_FETCHCONTENT=ON"
cmake_args = std_cmake_args
cmake_args = cmake_args.reject { |arg| arg.start_with?("-DCMAKE_OSX_SYSROOT=") } if OS.mac?

configure_args = [
"-GNinja",
*cmake_args,
"-DHOMEBREW_ALLOW_FETCHCONTENT=ON",
"-DCMAKE_CXX_COMPILER=#{llvm.opt_bin}/clang++",
"-DCMAKE_C_COMPILER=#{llvm.opt_bin}/clang"
]
configure_args << "-DCMAKE_OSX_SYSROOT=#{ENV["SDKROOT"]}" if OS.mac?

system "./bin/configure", *configure_args
system "./bin/compile"
system "./bin/install"

libexec_bin = libexec/"bin"
libexec_bin.install bin/"jank"
(bin/"jank").write <<~SH
#!/usr/bin/env bash
set -euo pipefail
unset SDKROOT
unset HOMEBREW_SDKROOT
unset MACOSX_DEPLOYMENT_TARGET
unset NIX_CFLAGS_COMPILE
unset NIX_LDFLAGS
unset NIX_APPLE_SDK_VERSION
unset NIX_APPLE_SDK_ROOT
exec "#{libexec_bin/"jank"}" "$@"
SH
(bin/"jank").chmod 0755
ln_s lib, libexec/"lib", force: true
end

test do
Expand Down
17 changes: 17 additions & 0 deletions Formula/jank.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ def install
(buildpath/"usr/local").cd do
cp_r Dir["*"], prefix
end

libexec_bin = libexec/"bin"
libexec_bin.install bin/"jank"
(bin/"jank").write <<~SH
#!/usr/bin/env bash
set -euo pipefail
unset SDKROOT
unset HOMEBREW_SDKROOT
unset MACOSX_DEPLOYMENT_TARGET
unset NIX_CFLAGS_COMPILE
unset NIX_LDFLAGS
unset NIX_APPLE_SDK_VERSION
unset NIX_APPLE_SDK_ROOT
exec "#{libexec_bin/"jank"}" "$@"
SH
(bin/"jank").chmod 0755
ln_s lib, libexec/"lib", force: true
end

test do
Expand Down
Loading