|
| 1 | +class WasiRuntimes < Formula |
| 2 | + desc "Compiler-RT and libc++ runtimes for WASI" |
| 3 | + homepage "https://wasi.dev" |
| 4 | + url "https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.2/llvm-project-19.1.2.src.tar.xz" |
| 5 | + sha256 "3666f01fc52d8a0b0da83e107d74f208f001717824be0b80007f529453aa1e19" |
| 6 | + license "Apache-2.0" => { with: "LLVM-exception" } |
| 7 | + head "https://github.com/llvm/llvm-project.git", branch: "main" |
| 8 | + |
| 9 | + livecheck do |
| 10 | + formula "llvm" |
| 11 | + end |
| 12 | + |
| 13 | + bottle do |
| 14 | + sha256 cellar: :any_skip_relocation, arm64_sequoia: "3c15d547e848cda42bffcb56e8d797f81482495ff45207c808e214274617a8e8" |
| 15 | + sha256 cellar: :any_skip_relocation, arm64_sonoma: "0effbd63bd850eef30b7d75d73b8b863b91a9dc74d532e6ca762ad11d49b9ec4" |
| 16 | + sha256 cellar: :any_skip_relocation, arm64_ventura: "b9918fe74820758f11a0a6412e957764c155886d6c999fba9a9e822f2d7b75d2" |
| 17 | + sha256 cellar: :any_skip_relocation, sonoma: "c1840dfe57ce81fdeb13e63f89aa90569e572935db233f6a34597dae63fd1e12" |
| 18 | + sha256 cellar: :any_skip_relocation, ventura: "a077d43170858dc3121b56320315028cb625447e888b2d6265c98b6c24b4d164" |
| 19 | + sha256 cellar: :any_skip_relocation, x86_64_linux: "13c5e9e2ee72e70baeee0882d2b35a5b75137e4628ca839462d8df932585184e" |
| 20 | + end |
| 21 | + |
| 22 | + depends_on "cmake" => :build |
| 23 | + depends_on "lld" => [:build, :test] |
| 24 | + depends_on "wasi-libc" => [:build, :test] |
| 25 | + depends_on "wasmtime" => :test |
| 26 | + depends_on "llvm" |
| 27 | + |
| 28 | + def targets |
| 29 | + # See targets at: |
| 30 | + # https://github.com/WebAssembly/wasi-sdk/blob/5e04cd81eb749edb5642537d150ab1ab7aedabe9/CMakeLists.txt#L14-L15 |
| 31 | + %w[ |
| 32 | + wasm32-wasi |
| 33 | + wasm32-wasip1 |
| 34 | + wasm32-wasip2 |
| 35 | + wasm32-wasip1-threads |
| 36 | + wasm32-wasi-threads |
| 37 | + ] |
| 38 | + end |
| 39 | + |
| 40 | + def install |
| 41 | + wasi_libc = Formula["wasi-libc"] |
| 42 | + llvm = Formula["llvm"] |
| 43 | + # Compiler flags taken from: |
| 44 | + # https://github.com/WebAssembly/wasi-sdk/blob/5e04cd81eb749edb5642537d150ab1ab7aedabe9/cmake/wasi-sdk-sysroot.cmake#L37-L50 |
| 45 | + common_cmake_args = %W[ |
| 46 | + -DCMAKE_SYSTEM_NAME=WASI |
| 47 | + -DCMAKE_SYSTEM_VERSION=1 |
| 48 | + -DCMAKE_SYSTEM_PROCESSOR=wasm32 |
| 49 | + -DCMAKE_BUILD_TYPE=Release |
| 50 | + -DCMAKE_AR=#{llvm.opt_bin}/llvm-ar |
| 51 | + -DCMAKE_C_COMPILER=#{llvm.opt_bin}/clang |
| 52 | + -DCMAKE_CXX_COMPILER=#{llvm.opt_bin}/clang++ |
| 53 | + -DCMAKE_C_COMPILER_WORKS=ON |
| 54 | + -DCMAKE_CXX_COMPILER_WORKS=ON |
| 55 | + -DCMAKE_SYSROOT=#{wasi_libc.opt_share}/wasi-sysroot |
| 56 | + ] |
| 57 | + # Compiler flags taken from: |
| 58 | + # https://github.com/WebAssembly/wasi-sdk/blob/5e04cd81eb749edb5642537d150ab1ab7aedabe9/cmake/wasi-sdk-sysroot.cmake#L65-L75 |
| 59 | + compiler_rt_args = %W[ |
| 60 | + -DCMAKE_INSTALL_PREFIX=#{pkgshare} |
| 61 | + -DCOMPILER_RT_BAREMETAL_BUILD=ON |
| 62 | + -DCOMPILER_RT_BUILD_XRAY=OFF |
| 63 | + -DCOMPILER_RT_INCLUDE_TESTS=OFF |
| 64 | + -DCOMPILER_RT_HAS_FPIC_FLAG=OFF |
| 65 | + -DCOMPILER_RT_ENABLE_IOS=OFF |
| 66 | + -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON |
| 67 | + -DCMAKE_C_COMPILER_TARGET=wasm32-wasi |
| 68 | + -DCOMPILER_RT_OS_DIR=wasi |
| 69 | + ] |
| 70 | + ENV.append_to_cflags "-fdebug-prefix-map=#{buildpath}=wasisdk://v#{wasi_libc.version}" |
| 71 | + # Don't use `std_cmake_args`. It sets things like `CMAKE_OSX_SYSROOT`. |
| 72 | + system "cmake", "-S", "compiler-rt", "-B", "build-compiler-rt", *compiler_rt_args, *common_cmake_args |
| 73 | + system "cmake", "--build", "build-compiler-rt" |
| 74 | + system "cmake", "--install", "build-compiler-rt" |
| 75 | + (pkgshare/"lib").install_symlink "wasi" => "wasip1" |
| 76 | + (pkgshare/"lib").install_symlink "wasi" => "wasip2" |
| 77 | + |
| 78 | + clang_resource_dir = Pathname.new(Utils.safe_popen_read(llvm.opt_bin/"clang", "-print-resource-dir").chomp) |
| 79 | + clang_resource_include_dir = clang_resource_dir/"include" |
| 80 | + clang_resource_include_dir.find do |pn| |
| 81 | + next unless pn.file? |
| 82 | + |
| 83 | + relative_path = pn.relative_path_from(clang_resource_dir) |
| 84 | + target = pkgshare/relative_path |
| 85 | + next if target.exist? |
| 86 | + |
| 87 | + target.parent.install_symlink pn |
| 88 | + end |
| 89 | + |
| 90 | + target_configuration = Hash.new { |h, k| h[k] = {} } |
| 91 | + |
| 92 | + targets.each do |target| |
| 93 | + # Configuration taken from: |
| 94 | + # https://github.com/WebAssembly/wasi-sdk/blob/5e04cd81eb749edb5642537d150ab1ab7aedabe9/cmake/wasi-sdk-sysroot.cmake#L227-L271 |
| 95 | + configuration = target_configuration[target] |
| 96 | + configuration[:threads] = configuration[:pic] = target.end_with?("-threads") ? "ON" : "OFF" |
| 97 | + configuration[:flags] = target.end_with?("-threads") ? ["-pthread"] : [] |
| 98 | + |
| 99 | + cflags = ENV.cflags&.split || [] |
| 100 | + cxxflags = ENV.cxxflags&.split || [] |
| 101 | + |
| 102 | + extra_flags = configuration.fetch(:flags) |
| 103 | + extra_flags += %W[ |
| 104 | + --target=#{target} |
| 105 | + --sysroot=#{wasi_libc.opt_share}/wasi-sysroot |
| 106 | + -resource-dir=#{pkgshare} |
| 107 | + ] |
| 108 | + cflags += extra_flags |
| 109 | + cxxflags += extra_flags |
| 110 | + |
| 111 | + # FIXME: Upstream sets the equivalent of |
| 112 | + # `-DLIBCXX_ENABLE_SHARED=#{configuration.fetch(:pic)}` |
| 113 | + # `-DLIBCXXABI_ENABLE_SHARED=#{configuration.fetch(:pic)}` |
| 114 | + # but the build fails with linking errors. |
| 115 | + # See: https://github.com/WebAssembly/wasi-sdk/blob/5e04cd81eb749edb5642537d150ab1ab7aedabe9/cmake/wasi-sdk-sysroot.cmake#L227-L271 |
| 116 | + target_cmake_args = %W[ |
| 117 | + -DCMAKE_INSTALL_INCLUDEDIR=#{share}/wasi-sysroot/include/#{target} |
| 118 | + -DCMAKE_STAGING_PREFIX=#{share}/wasi-sysroot |
| 119 | + -DCMAKE_POSITION_INDEPENDENT_CODE=#{configuration.fetch(:pic)} |
| 120 | + -DCXX_SUPPORTS_CXX11=ON |
| 121 | + -DLIBCXX_ENABLE_THREADS:BOOL=#{configuration.fetch(:threads)} |
| 122 | + -DLIBCXX_HAS_PTHREAD_API:BOOL=#{configuration.fetch(:threads)} |
| 123 | + -DLIBCXX_HAS_EXTERNAL_THREAD_API:BOOL=OFF |
| 124 | + -DLIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY:BOOL=OFF |
| 125 | + -DLIBCXX_HAS_WIN32_THREAD_API:BOOL=OFF |
| 126 | + -DLLVM_COMPILER_CHECKED=ON |
| 127 | + -DLIBCXX_ENABLE_SHARED:BOOL=OFF |
| 128 | + -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY:BOOL=OFF |
| 129 | + -DLIBCXX_ENABLE_EXCEPTIONS:BOOL=OFF |
| 130 | + -DLIBCXX_ENABLE_FILESYSTEM:BOOL=ON |
| 131 | + -DLIBCXX_ENABLE_ABI_LINKER_SCRIPT:BOOL=OFF |
| 132 | + -DLIBCXX_CXX_ABI=libcxxabi |
| 133 | + -DLIBCXX_CXX_ABI_INCLUDE_PATHS=#{testpath}/libcxxabi/include |
| 134 | + -DLIBCXX_HAS_MUSL_LIBC:BOOL=ON |
| 135 | + -DLIBCXX_ABI_VERSION=2 |
| 136 | + -DLIBCXXABI_ENABLE_EXCEPTIONS:BOOL=OFF |
| 137 | + -DLIBCXXABI_ENABLE_SHARED:BOOL=OFF |
| 138 | + -DLIBCXXABI_SILENT_TERMINATE:BOOL=ON |
| 139 | + -DLIBCXXABI_ENABLE_THREADS:BOOL=#{configuration.fetch(:threads)} |
| 140 | + -DLIBCXXABI_HAS_PTHREAD_API:BOOL=#{configuration.fetch(:threads)} |
| 141 | + -DLIBCXXABI_HAS_EXTERNAL_THREAD_API:BOOL=OFF |
| 142 | + -DLIBCXXABI_BUILD_EXTERNAL_THREAD_LIBRARY:BOOL=OFF |
| 143 | + -DLIBCXXABI_HAS_WIN32_THREAD_API:BOOL=OFF |
| 144 | + -DLIBCXXABI_ENABLE_PIC:BOOL=#{configuration.fetch(:pic)} |
| 145 | + -DLIBCXXABI_USE_LLVM_UNWINDER:BOOL=OFF |
| 146 | + -DUNIX:BOOL=ON |
| 147 | + -DCMAKE_C_FLAGS=#{cflags.join(" ")} |
| 148 | + -DCMAKE_CXX_FLAGS=#{cxxflags.join(" ")} |
| 149 | + -DLIBCXX_LIBDIR_SUFFIX=/#{target} |
| 150 | + -DLIBCXXABI_LIBDIR_SUFFIX=/#{target} |
| 151 | + -DLIBCXX_INCLUDE_TESTS=OFF |
| 152 | + -DLIBCXX_INCLUDE_BENCHMARKS=OFF |
| 153 | + -DLLVM_ENABLE_RUNTIMES:STRING=libcxx;libcxxabi |
| 154 | + ] |
| 155 | + |
| 156 | + # Don't use `std_cmake_args`. It sets things like `CMAKE_OSX_SYSROOT`. |
| 157 | + system "cmake", "-S", "runtimes", "-B", "runtimes-#{target}", *target_cmake_args, *common_cmake_args |
| 158 | + system "cmake", "--build", "runtimes-#{target}" |
| 159 | + system "cmake", "--install", "runtimes-#{target}" |
| 160 | + end |
| 161 | + (share/"wasi-sysroot/include/c++/v1").mkpath |
| 162 | + touch share/"wasi-sysroot/include/c++/v1/.keepme" |
| 163 | + end |
| 164 | + |
| 165 | + test do |
| 166 | + ENV.remove_macosxsdk if OS.mac? |
| 167 | + ENV.remove_cc_etc |
| 168 | + |
| 169 | + (testpath/"test.c").write <<~C |
| 170 | + #include <stdio.h> |
| 171 | + volatile int x = 42; |
| 172 | + int main(void) { |
| 173 | + printf("the answer is %d", x); |
| 174 | + return 0; |
| 175 | + } |
| 176 | + C |
| 177 | + (testpath/"test.cc").write <<~CPP |
| 178 | + #include <iostream> |
| 179 | +
|
| 180 | + int main() { |
| 181 | + std::cout << "hello from C++ main with cout!" << std::endl; |
| 182 | + return 0; |
| 183 | + } |
| 184 | + CPP |
| 185 | + |
| 186 | + clang = Formula["llvm"].opt_bin/"clang" |
| 187 | + wasm_args = %W[ |
| 188 | + --sysroot=#{HOMEBREW_PREFIX}/share/wasi-sysroot |
| 189 | + -resource-dir=#{HOMEBREW_PREFIX}/share/wasi-runtimes |
| 190 | + ] |
| 191 | + targets.each do |target| |
| 192 | + # FIXME: Needs a working `wasm-component-ld`. |
| 193 | + next if target.include?("wasip2") |
| 194 | + |
| 195 | + system clang, "--target=#{target}", *wasm_args, "-v", "test.c", "-o", "test-#{target}" |
| 196 | + assert_equal "the answer is 42", shell_output("wasmtime #{testpath}/test-#{target}") |
| 197 | + |
| 198 | + system "#{clang}++", "--target=#{target}", *wasm_args, "-v", "test.cc", "-o", "test-cxx-#{target}" |
| 199 | + assert_equal "hello from C++ main with cout!", shell_output("wasmtime #{testpath}/test-cxx-#{target}").chomp |
| 200 | + end |
| 201 | + end |
| 202 | +end |
0 commit comments