#! /usr/bin/env crystal # # This script generates the `lib/llvm_VERSION` file from LLVM-C.dll, needed for # dynamically linking against LLVM on Windows. This is only needed when using an # LLVM installation different from the one bundled with Crystal. require "c/libloaderapi" require "llvm/lib_llvm/config" def find_dll_in_env_path ENV["PATH"]?.try &.split(Process::PATH_DELIMITER, remove_empty: true) do |path| dll_path = File.join(path, "LLVM-C.dll") return dll_path if File.exists?(File.join(path, "LLVM-C.dll")) end end unless dll_fname = ARGV.shift? || find_dll_in_env_path abort "Error: Cannot locate LLVM-C.dll, pass its absolute path as a command-line argument or ensure it is available in the PATH environment variable" end unless dll = LibC.LoadLibraryExW(dll_fname.check_no_null_byte.to_utf16, nil, 0) abort "Error: Failed to load DLL at #{dll_fname}" end begin unless llvm_get_version = LibC.GetProcAddress(dll, "LLVMGetVersion") abort "Error: Failed to resolve LLVMGetVersion" end llvm_get_version = Proc(LibC::UInt*, LibC::UInt*, LibC::UInt*, Nil).new(llvm_get_version, Pointer(Void).null) major = uninitialized LibC::UInt minor = uninitialized LibC::UInt patch = uninitialized LibC::UInt llvm_get_version.call(pointerof(major), pointerof(minor), pointerof(patch)) targets_built = LibLLVM::ALL_TARGETS.select do |target| LibC.GetProcAddress(dll, "LLVMInitialize#{target}Target") && LibC.GetProcAddress(dll, "LLVMInitialize#{target}TargetInfo") end # The list of required system libraries are hardcoded in: # https://github.com/llvm/llvm-project/blob/main/llvm/lib/Support/CMakeLists.txt # There is no way to infer them from `dumpbin /dependents` alone, because that # command lists DLLs only, whereas some of these libraries are purely static. system_libs = %w(psapi shell32 ole32 uuid advapi32) # https://github.com/llvm/llvm-project/commit/a5ffabce98a4b2e9d69009fa3e60f2b154100860 system_libs << "ws2_32" if {major, minor, patch} >= {18, 0, 0} # https://github.com/llvm/llvm-project/commit/cb7690af09b95bb944baf1b5a9ffb18f86c12130 system_libs << "ntdll" if {major, minor, patch} >= {19, 0, 0} puts "#{major}.#{minor}.#{patch}" puts targets_built.join(' ') puts system_libs.join(' ', &.+ ".lib") ensure LibC.FreeLibrary(dll) end